Commit | Line | Data |
9632a49e |
1 | =pod |
2 | |
3 | =head1 NAME |
4 | |
2b8a8ab7 |
5 | Moose::Cookbook::Style - The latest in trendy Moose cuisine |
9632a49e |
6 | |
7 | =for authors |
8 | |
facc5d76 |
9 | Please annotate all bad examples with comments so that they won't be copied by |
10 | accident |
9632a49e |
11 | |
12 | =cut |
13 | |
14 | =head1 Benefits of Good Style |
15 | |
16 | Good Moose style, as defined by this document, helps ensure your code has the |
17 | following desirable properties: |
18 | |
19 | =over 4 |
20 | |
21 | =item Play well with others |
22 | |
23 | Your code will be more reusable and easier to extend. |
24 | |
25 | =item Ease maintenance |
26 | |
27 | The code will be easier to understand because it follows an accepted set of |
28 | conventions and idioms. |
29 | |
30 | This will help others maintaining your code, and also help you to get support |
31 | on IRC for instance. |
32 | |
33 | =item Help Moose generate better code |
34 | |
35 | By using the most appropriate features, the generated code will be safer and |
36 | more efficient. |
37 | |
38 | =item Benefit from meta programming |
39 | |
40 | Code that operates on the metaclass will benefit from clean meta definitions. |
41 | |
42 | If you are manually converting argument types with C<around 'new'> there is no |
43 | meta data explaining your intention. If on the other hand you use coercions, |
44 | there is introspectable meta data that makes this clear. |
45 | |
46 | This means that e.g. MooseX extensions that work by introspecting your class |
47 | will be able to do the right thing more often, because they don't need to |
48 | guess. |
49 | |
50 | =back |
51 | |
52 | =head1 Don't change C<new> |
53 | |
54 | It is generally considered bad style to override L<Moose::Object/new> for a |
55 | number of reasons. |
56 | |
57 | The first reason is consistency. Subclasses of your class and code |
58 | instantiating your class would be simpler if your constructor works closer to |
59 | the default. |
60 | |
61 | The second reason is performance. By calling C<make_immutable> on your metaclass: |
62 | |
63 | __PACKAGE__->meta->make_immutable; |
64 | |
65 | And opting out of any class definition changes from that point on, you allow |
66 | Moose to create more efficient versions of certain generic methods. Moose will |
67 | generate a tight, optimal C<new> for you, based on the minimal set of features |
68 | you use. |
69 | |
70 | Moose provides many features that allow you to do common object construction |
71 | tasks at the right level of abstraction. |
72 | |
73 | When attributes have the ability to provide the necessary functionality, use |
74 | that. If that isn't sufficient, L<Moose::Object> has numerous features you can |
75 | use at construction time. |
76 | |
77 | =head2 Use C<BUILD> instead of custom initialization or overriding C<new> |
78 | |
79 | Instead of changing C<new>, do initialization in C<BUILD>. |
80 | |
81 | The construction parameters are passed in, so you don't need to replicate |
82 | C<BUILDARGS>, and since C<BUILD> is called for each superclass that defines it, |
83 | you will never forget to invoke your initializers if you extend them. |
84 | |
85 | =head2 Use C<default>, C<builder> or C<lazy_build> |
86 | |
87 | To initialize attributes there is a plethora of methods preferable to assigning |
88 | the value at initialization time. |
89 | |
90 | If you want to translate parameter data, use coercions. |
91 | |
92 | If you want to ensure a parameter can't be overridden by the constructor, set |
93 | the C<init_arg> to C<undef> instead of overwriting it in C<BUILD>. |
94 | |
95 | =head2 Use C<BUILDARGS> to alter C<@_> processing |
96 | |
facc5d76 |
97 | If you need to change the way C<@_> is processed, for example for |
98 | C<< Class->new( $single_param ) >>, use C<BUILDARGS> instead of wrapping |
99 | C<new>. This ensures the behavior is subclassible, it keeps this logic |
9632a49e |
100 | independent of the other aspects of construction, and can be made efficient |
101 | using C<make_immutable>. |
102 | |
103 | =head1 Don't pollute the global type registry |
104 | |
105 | =head2 Use fully qualified type names for your own data |
106 | |
107 | L<MooseX::Types> provides a convenient method to do this. |
108 | |
109 | If you define |
110 | |
111 | # Bad style: |
112 | |
113 | subtype Person => ( |
114 | as 'Object', |
115 | where { $_->can("name") }, |
116 | ); |
117 | |
118 | Then the global name C<Person> is registered, and this could conflict with |
119 | other bad usage of the sort. |
120 | |
121 | Instead, prefix type name with your project namespace, or class name: |
122 | |
123 | subtype 'My::Foo::Person' => ( |
124 | as 'Object', |
125 | where { $_->can("name") }, |
126 | ); |
127 | |
128 | Or with L<MooseX::Types>: |
129 | |
7c43d079 |
130 | use MooseX::Types::Moose qw(Object); |
131 | |
9632a49e |
132 | use MooseX::Types ( |
133 | -declare => [qw(Person)], |
134 | ); |
135 | |
136 | subtype Person() => ( # note parenthesis, "Person" is a function, not a string |
7c43d079 |
137 | as Object, # MooseX::Types::Moose exported it |
9632a49e |
138 | where { $_->can("name") }, |
139 | ); |
140 | |
23306f77 |
141 | =head3 Coerce in a subtype |
142 | |
9632a49e |
143 | Likewise use fully qualified subtypes of other types for defining coercions, so |
144 | that they won't affect unrelated code, causing action at a distance. |
145 | |
146 | This is important because the type registry is global, kind of like the symbol |
147 | table. |
148 | |
149 | This means that code like: |
150 | |
151 | # Bad style: |
152 | |
153 | coerce ArrayRef => ( |
154 | from Str => via { [ split /,/ ] }, |
155 | ); |
156 | |
157 | Will add a coercion to B<all> attributes like: |
158 | |
159 | has foo => ( |
160 | isa => "ArrayRef", |
161 | coerce => 1, |
162 | ); |
163 | |
facc5d76 |
164 | when the actual coercion applies only to your specific cases. |
9632a49e |
165 | |
d9fa4da9 |
166 | =head1 Clean up your package |
167 | |
168 | Use C<namespace::clean> or C<no Moose> to remove the sugar exports. |
169 | |
170 | This will make sure the sugar isn't accidentally called as methods on your objects. |
171 | |
172 | For instance: |
173 | |
174 | $obj->can("has"); |
175 | |
176 | will return true, even though C<has> is not a method. |
177 | |
5bfcfd33 |
178 | If you choose L<namespace::clean>, make sure to keep the C<meta> method if you |
179 | want to use it for introspection: |
180 | |
181 | use namespace::clean -except => "meta"; |
182 | |
58954bc3 |
183 | =head1 Accept no substitutes |
184 | |
185 | By substitutes I mean hacks instead of "proper" solutions. |
a76e2bac |
186 | |
187 | When you have a tricky requirement, refrain from abusing Moose or MooseX:: or |
188 | whatever it is you are using. |
189 | |
190 | Instead, drop by IRC and discuss it. Most of the time a crazy idea can either |
191 | be simplified, or it will spawn a clean, reliable feature to whatever package |
192 | you are using. |
193 | |
194 | This will improve your code and also share the benefit with others. |
9632a49e |
195 | |
47b19570 |
196 | =head1 AUTHOR |
197 | |
198 | Yuval (nothingmuch) Kogman |
199 | |
200 | =head1 COPYRIGHT AND LICENSE |
201 | |
202 | Copyright 2006-2008 by Infinity Interactive, Inc. |
203 | |
204 | L<http://www.iinteractive.com> |
205 | |
facc5d76 |
206 | This library is free software; you can redistribute it and/or modify it under |
207 | the same terms as Perl itself. |
47b19570 |
208 | |
209 | =cut |