Docs: Added explanations on 'no Moose' and 'make_immutable'.
[gitmo/Moose.git] / lib / Moose / Manual / BestPractices.pod
index 96b4093..9349718 100644 (file)
@@ -1,7 +1,19 @@
+=pod
+
+=head1 NAME
+
+Moose::Manual::BestPractices - Get the most out of Moose
 
 =head1 RECOMMENDATIONS
 
-=head2 No Moose and Immutabilize
+Moose has a lot of features, and there's definitely more than one way
+to do it. However, we think that picking a subset of these features
+and using them consistently makes everyone's life easier.
+
+Of course, as with any list of "best practices", these are really just
+opinions. Feel free to ignore us.
+
+=head2 C<no Moose> and immutabilize
 
 We recommend that you end your Moose class definitions by removing the
 Moose sugar and making your class immutable.
@@ -20,24 +32,200 @@ Moose sugar and making your class immutable.
 
   1;
 
-=head2 Always call SUPER::BUILDARGS
+The C<no Moose> bit simply good code hygiene, as it removes all the
+Moose keywords that are no longer needed once your class has been
+built.  C<make_immutable> relinquishes your right to make further
+changes to your class, and allows Moose to speed up a lot of things,
+most notably object construction.
+
+=head2 Never override C<new>
+
+Overriding C<new> is a very bad practice. Instead, you should use a
+C<BUILD> or C<BUILDARGS> methods to do the same thing. When you
+override C<new>, Moose can no longer inline a constructor when your
+class is immutabilized.
+
+There are two good reasons to override C<new>. One, you are writing a
+MooseX extension that provides its own L<Moose::Object> subclass
+I<and> a subclass of L<Moose::Meta::Method::Constructor> to inline the
+constructor. Two, you are subclassing a non-Moose parent.
+
+If you know how to do that, you know when to ignore this best practice
+;)
+
+=head2 Always call C<SUPER::BUILDARGS>
+
+If you override the C<BUILDARGS> method in your class, make sure to
+play nice and call C<SUPER::BUILDARGS> to handle cases you're not
+checking for explicitly.
+
+The default C<BUILDARGS> method in L<Moose::Object> handles both a
+list and hashref of named parameters correctly, and also checks for a
+I<non-hashref> single argument.
+
+=head2 Provide defaults whenever possible, otherwise use C<required>
+
+When your class provides defaults, this makes constructing new objects
+simpler. If you cannot provide a default, consider making the
+attribute C<required>.
+
+If you don't do either, an attribute can simply be left unset,
+increasing the complexity of your object, because it has more possible
+states that you or the user of your class must account for.
+
+=head2 Use C<builder> instead of C<default> most of the time
+
+Builders can be inherited, they have explicit names, and they're just
+plain cleaner.
+
+However, I<do> use a default when the default is a non-reference,
+I<or> when the default is simply an empty reference of some sort.
+
+Also, keep your builder methods private.
+
+=head2 Use C<lazy_build>
+
+Lazy is good, and often solves initialization ordering problems. It's
+also good for deferring work that may never have to be done. If you're
+going to be lazy, use I<lazy_build> to save yourself some typing and
+standardize names.
+
+=head2 Consider keeping clearers and predicates private
+
+Does everyone I<really> need to be able to clear an attribute?
+Probably not. Don't expose this functionality outside your class
+by default.
+
+Predicates are less problematic, but there's no reason to make your
+public API bigger than it has to be.
+
+=head2 Default to read-only, and consider keeping writers private
+
+Making attributes mutable just means more complexity to account for in
+your program. The alternative to mutable state is to encourage users
+of your class to simply make new objects as needed.
+
+If you I<must> make an attribute read-write, consider making the
+writer a separate private method. Narrower APIs are easy to maintain,
+and mutable state is trouble.
+
+=head2 Think twice before changing an attribute's type in a subclass
+
+Down this path lies great confusion. If the attribute is an object
+itself, at least make sure that it has the same interface as the type
+of object in the parent class.
+
+=head2 Don't use the C<initializer> feature
+
+Don't know what we're talking about? That's fine.
+
+=head2 Use L<MooseX::AttributeHelpers> instead of C<auto_deref>
+
+The C<auto_deref> feature is a bit troublesome. Directly exposing a
+complex attribute is ugly. Instead, consider using
+L<MooseX::AttributeHelpers> to define an API that exposes those pieces
+of functionality that need exposing. Then you can expose just the
+functionality that you want.
+
+=head2 Always call C<inner> in the most specific subclass
+
+When using C<augment> and C<inner>, we recommend that you call
+C<inner> in the most specific subclass of your hierarchy. This makes
+it possible to subclass further and extend the hierarchy without
+changing the parents.
+
+=head2 Namespace your types
+
+Use some sort of namespacing convention for type names. We recommend
+something like "MyApp::Type::Foo".
+
+If you're intending to package your types up for re-use using
+L<MooseX::Types> later, avoid using characters that are invalid in
+perl identifiers such as a space or period.
+
+=head2 Do not coerce Moose built-ins directly
+
+If you define a coercion for a Moose built-in like C<ArrayRef>, this
+will affect every application in the Perl interpreter that uses this
+type.
+
+    # very naughty!
+    coerce 'ArrayRef'
+        => from Str
+        => via { [ split /,/ ] };
+
+Instead, create a subtype and coerce that:
+
+    subtype 'My::ArrayRef' => as 'ArrayRef';
+
+    coerce 'My::ArrayRef'
+        => from 'Str'
+        => via { [ split /,/ ] };
+
+=head2 Do not coerce class names directly
+
+Just as with Moose built-in types, a class type is global for the
+entire interpreter. If you add a coercion for that class name, it can
+have magical side effects elsewhere:
+
+    # also very naughty!
+    coerce 'HTTP::Headers'
+        => from 'HashRef'
+        => via { HTTP::Headers->new( %{$_} ) };
+
+Instead, we can create an "empty" subtype for the coercion:
+
+    subtype 'My::HTTP::Headers' => as class_type('HTTP::Headers');
+
+    coerce 'My::HTTP::Headers'
+        => from 'HashRef'
+        => via { HTTP::Headers->new( %{$_} ) };
+
+=head2 Use coercion instead of unions
+
+Consider using a type coercion instead of a type union. This was
+covered at length in L<Moose::Manual::Types>.
+
+=head2 Define all your types in one module
+
+Define all your types and coercions in one module. This was also
+covered in L<Moose::Manual::Types>.
+
+=head1 BENEFITS OF BEST PRACTICES
+
+Following these practices has a number of benefits.
+
+It helps ensure that your code will play nice with others, making it
+more reusable and easier to extend.
+
+Following an accepted set of idioms will make maintenance easier,
+especially when someone else has to maintain your code. It will also
+make it easier to get support from other Moose users, since your code
+will be easier to digest quickly.
 
-=head2 No complex subs for a default, use a builder
+Some of these practices are designed to help Moose do the right thing,
+especially when it comes to immutabilization. This means your code
+will be faster when immutabilized.
 
-builders can be inherited, show up more cleanly in profile
+Many of these practices also help get the most out of meta
+programming. If you used an overridden C<new> to do type coercion by
+hand, rather than defining a real coercion, there is no introspectable
+metadata. This sort of thing is particularly problematic for MooseX
+extensions which rely on introspection to do the right thing.
 
-=head2 use default for simple scalar, and empty refs
+=head1 AUTHOR
 
-=head2 use builder for everything else
+Yuval (nothingmuch) Kogman
 
-don't use initializer
+Dave Rolsky E<lt>autarch@urth.orgE<gt>
 
-=head2 use lazy_build
+=head1 COPYRIGHT AND LICENSE
 
-keep builders private
+Copyright 2009 by Infinity Interactive, Inc.
 
-consider keeping clearers & predicates private
+L<http://www.iinteractive.com>
 
-consider keeping writers private
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
 
-=head2 use MX::AH instead of auto_deref
+=cut