X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FBestPractices.pod;h=68950426aede5a9f4bcb7c1c0fcda1cce6b95fb3;hb=1e62ec3bf60b5f85bc0a567958dda1be8df93e84;hp=c73f4d3b2b1cd1a1c844c272f63c4f773db0c59c;hpb=410daadb31a736e7f124f9d4c3e47ca4a42cfd7c;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/BestPractices.pod b/lib/Moose/Manual/BestPractices.pod index c73f4d3..6895042 100644 --- a/lib/Moose/Manual/BestPractices.pod +++ b/lib/Moose/Manual/BestPractices.pod @@ -1,8 +1,10 @@ -=pod +package Moose::Manual::BestPractices; + +# ABSTRACT: Get the most out of Moose -=head1 NAME +__END__ -Moose::Manual::BestPractices - Get the most out of Moose +=pod =head1 RECOMMENDATIONS @@ -13,27 +15,33 @@ 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 your 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. (This is preferred to placing C at the end +of your package). + +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 @@ -50,11 +58,10 @@ 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 +87,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 @@ -96,6 +102,13 @@ by default. Predicates are less problematic, but there's no reason to make your public API bigger than it has to be. +=head2 Avoid C + +As described above, you rarely actually need a clearer or a predicate. +C adds both to your public API, which exposes you to use cases that +you must now test for. It's much better to avoid adding them until you really +need them - use explicit C and C options instead. + =head2 Default to read-only, and consider keeping writers private Making attributes mutable just means more complexity to account for in @@ -106,6 +119,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 +138,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,10 +154,8 @@ 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 MooseX::Types later, avoid using -characters that are invalid in perl identifiers such as ' ' and '.'. +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 @@ -147,15 +166,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 @@ -166,20 +185,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 @@ -205,22 +224,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 particularly problematic MooseX +metadata. This sort of thing is particularly problematic for MooseX extensions which rely on introspection to do the right thing. -=head1 AUTHOR - -Yuval (nothingmuch) Kogman - -Dave Rolsky Eautarch@urth.orgE - -=head1 COPYRIGHT AND LICENSE - -Copyright 2009 by Infinity Interactive, Inc. - -L - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - =cut