X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FBestPractices.pod;h=1e084691f35ad4f28ce3e29e84f21be41a41e35e;hb=970a92fa56f1ea409c8d7c5428392479292fd8d4;hp=157e4995ffb533c04396e15250a22152143f34e5;hpb=1ad2aa8ed94a903175c59a26a6981877b7fd817c;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/BestPractices.pod b/lib/Moose/Manual/BestPractices.pod index 157e499..1e08469 100644 --- a/lib/Moose/Manual/BestPractices.pod +++ b/lib/Moose/Manual/BestPractices.pod @@ -13,48 +13,52 @@ 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 and immutabilize +=head2 C and immutabilize -We recommend that you end your Moose class definitions by removing the -Moose sugar and making your class immutable. +We recommend that you remove the Moose sugar and end your Moose class +definitions by making your class immutable. package Person; use Moose; + use namespace::autoclean; # extends, roles, attributes, etc. # methods - no Moose; - __PACKAGE__->meta->make_immutable; 1; -The C bit is simply good code hygiene, and making classes -immutable speeds up a lot of things, most notably object construction. +The C bit is simply good code hygiene, as it removes +imported symbols from you class's namespace at the end of your package's +compile cycle, including Moose keywords. Once the class has been +built, these keywords are not needed. + +The C call allows Moose to speed up a lot of things, most +notably object construction. The trade-off is that you can no longer change +the class definition. =head2 Never override C Overriding C is a very bad practice. Instead, you should use a C or C methods to do the same thing. When you override C, Moose can no longer inline a constructor when your -class is immutablized. +class is immutabilized. -The only reason to override C is if you are writing a MooseX -extension that provides its own L subclass I a -subclass of L to inline the -constructor. +There are two good reasons to override C. One, you are writing a +MooseX extension that provides its own L subclass +I a subclass of L 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 +=head2 Always call the original/parent C -If you override the C method in your class, make sure to -play nice and call C to handle cases you're not -checking for explicitly. +If you C the C method in your class, make sure to play +nice and call C to handle cases you're not checking for explicitly. The default C method in L handles both a list and hashref of named parameters correctly, and also checks for a @@ -80,12 +84,11 @@ I when the default is simply an empty reference of some sort. Also, keep your builder methods private. -=head2 Use C +=head2 Be C -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 to save yourself some typing and -standardize names. +Lazy is good, and often solves initialization ordering problems. It's also +good for deferring work that may never have to be done. Make your attributes +C unless they're C or have trivial defaults. =head2 Consider keeping clearers and predicates private @@ -106,6 +109,15 @@ If you I make an attribute read-write, consider making the writer a separate private method. Narrower APIs are easy to maintain, and mutable state is trouble. +In order to declare such attributes, provide a private C +parameter: + + has pizza => ( + is => 'ro', + isa => 'Pizza', + writer => '_pizza', + ); + =head2 Think twice before changing an attribute's type in a subclass Down this path lies great confusion. If the attribute is an object @@ -116,13 +128,12 @@ of object in the parent class. Don't know what we're talking about? That's fine. -=head2 Use L instead of C +=head2 Use L traits instead of C -The C feature is a bit troublesome. Directly exposing a -complex attribute is ugly. Instead, consider using -L to define an API that exposes those pieces -of functionality that need exposing. Then you can expose just the -functionality that you want. +The C feature is a bit troublesome. Directly exposing a complex +attribute is ugly. Instead, consider using L +traits to define an API that only exposes the necessary pieces of +functionality. =head2 Always call C in the most specific subclass @@ -133,9 +144,8 @@ changing the parents. =head2 Namespace your types -Use some sort of namespacing convention for type names. We recommend -something like "MyApp.Type.Foo". I use "::" as the namespace -separator, since that overlaps with actual class names. +Use some sort of namespacing convention for type names. We recommend something +like "MyApp::Type::Foo". We also recommend considering L. =head2 Do not coerce Moose built-ins directly @@ -146,15 +156,15 @@ type. # very naughty! coerce 'ArrayRef' => from Str - => via { [ split /,/ ] }; + => via { [ split /,/ ] }; Instead, create a subtype and coerce that: - subtype 'My.ArrayRef' => as 'ArrayRef'; + subtype 'My::ArrayRef' => as 'ArrayRef'; - coerce 'My.ArrayRef' + coerce 'My::ArrayRef' => from 'Str' - => via { [ split /,/ ] }; + => via { [ split /,/ ] }; =head2 Do not coerce class names directly @@ -165,20 +175,20 @@ have magical side effects elsewhere: # also very naughty! coerce 'HTTP::Headers' => from 'HashRef' - => via { HTTP::Headers->new( %{$_} ) }; + => via { HTTP::Headers->new( %{$_} ) }; Instead, we can create an "empty" subtype for the coercion: - subtype 'My.HTTP.Headers' => as class_type('HTTP::Headers'); + subtype 'My::HTTP::Headers' => as class_type('HTTP::Headers'); - coerce 'My.HTTP.Headers' + coerce 'My::HTTP::Headers' => from 'HashRef' - => via { HTTP::Headers->new( %{$_} ) }; + => 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. +covered in L. =head2 Define all your types in one module @@ -204,7 +214,7 @@ will be faster when immutabilized. Many of these practices also help get the most out of meta programming. If you used an overridden C to do type coercion by hand, rather than defining a real coercion, there is no introspectable -metadata. This sort of thing is particuarly problematic MooseX +metadata. This sort of thing is particularly problematic for MooseX extensions which rely on introspection to do the right thing. =head1 AUTHOR