start a style guide
Yuval Kogman [Mon, 30 Jun 2008 09:54:59 +0000 (09:54 +0000)]
lib/Moose/Cookbook/Style.pod [new file with mode: 0644]

diff --git a/lib/Moose/Cookbook/Style.pod b/lib/Moose/Cookbook/Style.pod
new file mode 100644 (file)
index 0000000..4a28aaa
--- /dev/null
@@ -0,0 +1,160 @@
+=pod
+
+=head1 NAME
+
+Moose::Cookbook::Style - How to cook Moose with style
+
+=for authors
+
+Please annotate all bad examples with comments so that they won't be copied by accodent
+
+=cut
+
+=head1 Benefits of Good Style
+
+Good Moose style, as defined by this document, helps ensure your code has the
+following desirable properties:
+
+=over 4
+
+=item Play well with others
+
+Your code will be more reusable and easier to extend.
+
+=item Ease maintenance
+
+The code will be easier to understand because it follows an accepted set of
+conventions and idioms.
+
+This will help others maintaining your code, and also help you to get support
+on IRC for instance.
+
+=item Help Moose generate better code
+
+By using the most appropriate features, the generated code will be safer and
+more efficient.
+
+=item Benefit from meta programming
+
+Code that operates on the metaclass will benefit from clean meta definitions.
+
+If you are manually converting argument types with C<around 'new'> there is no
+meta data explaining your intention. If on the other hand you use coercions,
+there is introspectable meta data that makes this clear.
+
+This means that e.g. MooseX extensions that work by introspecting your class
+will be able to do the right thing more often, because they don't need to
+guess.
+
+=back
+
+=head1 Don't change C<new>
+
+It is generally considered bad style to override L<Moose::Object/new> for a
+number of reasons.
+
+The first reason is consistency. Subclasses of your class and code
+instantiating your class would be simpler if your constructor works closer to
+the default.
+
+The second reason is performance. By calling C<make_immutable> on your metaclass:
+
+    __PACKAGE__->meta->make_immutable;
+
+And opting out of any class definition changes from that point on, you allow
+Moose to create more efficient versions of certain generic methods. Moose will
+generate a tight, optimal C<new> for you, based on the minimal set of features
+you use.
+
+Moose provides many features that allow you to do common object construction
+tasks at the right level of abstraction.
+
+When attributes have the ability to provide the necessary functionality, use
+that. If that isn't sufficient, L<Moose::Object> has numerous features you can
+use at construction time.
+
+=head2 Use C<BUILD> instead of custom initialization or overriding C<new>
+
+Instead of changing C<new>, do initialization in C<BUILD>.
+
+The construction parameters are passed in, so you don't need to replicate
+C<BUILDARGS>, and since C<BUILD> is called for each superclass that defines it,
+you will never forget to invoke your initializers if you extend them.
+
+=head2 Use C<default>, C<builder> or C<lazy_build>
+
+To initialize attributes there is a plethora of methods preferable to assigning
+the value at initialization time.
+
+If you want to translate parameter data, use coercions.
+
+If you want to ensure a parameter can't be overridden by the constructor, set
+the C<init_arg> to C<undef> instead of overwriting it in C<BUILD>.
+
+=head2 Use C<BUILDARGS> to alter C<@_> processing
+
+If you need to change the way L<@_> is processed, use C<BUILDARGS>, instead of
+wrapping C<new>. This ensures the behavior is subclassible, it keeps this logic
+independent of the other aspects of construction, and can be made efficient
+using C<make_immutable>.
+
+=head1 Don't pollute the global type registry
+
+=head2 Use fully qualified type names for your own data
+
+L<MooseX::Types> provides a convenient method to do this.
+
+If you define
+
+    # Bad style:
+
+    subtype Person => (
+        as 'Object',
+        where { $_->can("name") },
+    );
+
+Then the global name C<Person> is registered, and this could conflict with
+other bad usage of the sort.
+
+Instead, prefix type name with your project namespace, or class name:   
+
+    subtype 'My::Foo::Person' => (
+        as 'Object',
+        where { $_->can("name") },
+    );
+
+Or with L<MooseX::Types>:
+
+    use MooseX::Types (
+        -declare => [qw(Person)],
+    );
+    
+    subtype Person() => ( # note parenthesis, "Person" is a function, not a string
+        as 'Object',
+        where { $_->can("name") },
+    );
+
+Likewise use fully qualified subtypes of other types for defining coercions, so
+that they won't affect unrelated code, causing action at a distance.
+
+This is important because the type registry is global, kind of like the symbol
+table.
+
+This means that code like:
+
+    # Bad style:
+
+    coerce ArrayRef => (
+        from Str => via { [ split /,/ ] },
+    );
+
+Will add a coercion to B<all> attributes like:
+
+    has foo => (
+        isa => "ArrayRef",
+        coerce => 1,
+    );
+
+in a specific way.
+
+