X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FBestPractices.pod;h=0c74d7578a3ae0c280f34e2f2bcacd4b47c3d115;hb=19320607dd1e6217be5f0f7f68db79465d0fb6d9;hp=ef2236c6fe780e3ba3d803fb865b9a7b40c27766;hpb=541027c54293913e099d83b92521726ee76e71c0;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/BestPractices.pod b/lib/Moose/Manual/BestPractices.pod index ef2236c..0c74d75 100644 --- a/lib/Moose/Manual/BestPractices.pod +++ b/lib/Moose/Manual/BestPractices.pod @@ -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 and immutabilize We recommend that you end your Moose class definitions by removing the Moose sugar and making your class immutable. @@ -20,34 +32,194 @@ Moose sugar and making your class immutable. 1; -=head2 Always call SUPER::BUILDARGS +The C bit is simply good code hygiene, and making classes +immutable speeds up a lot of things, most notably object construction. + +=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 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. + +If you know how to do that, you know when to ignore this best practice +;) + +=head2 Always call 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. + +The default C method in L handles both a +list and hashref of named parameters correctly, and also checks for a +I single argument. + +=head2 Provide defaults whenever possible, otherwise use C + +When your class provides defaults, this makes constructing new objects +simpler. If you cannot provide a default, consider making the +attribute C. + +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 instead of C most of the time + +Builders can be inherited, they have explicit names, and they're just +plain cleaner. + +However, I use a default when the default is a non-reference, +I when the default is simply an empty reference of some sort. + +Also, keep your builder methods private. + +=head2 Use 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. + +=head2 Consider keeping clearers and predicates private + +Does everyone I 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 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 feature + +Don't know what we're talking about? That's fine. + +=head2 Use L 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. + +=head2 Always call C in the most specific subclass + +When using C and C, we recommend that you call +C 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". I use "::" as the namespace +separator, since that overlaps with actual class names. + +=head2 Do not coerce Moose built-ins directly + +If you define a coercion for a Moose built-in like C, 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. + +=head2 Define all your types in one module -=head2 No complex subs for a default, use a builder +Define all your types and coercions in one module. This was also +covered in L. -builders can be inherited, show up more cleanly in profile +=head1 BENEFITS OF BEST PRACTICES -=head2 use default for simple scalar, and empty refs +Following these practices has a number of benefits. -=head2 use builder for everything else +It helps ensure that your code will play nice with others, making it +more reusable and easier to extend. -don't use initializer +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 use lazy_build +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. -keep builders private +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 +extensions which rely on introspection to do the right thing. -consider keeping clearers & predicates private +=head1 AUTHOR -consider keeping writers private +Yuval (nothingmuch) Kogman -=head2 Think Twice Before Changing an Attribute's Type in a Subclass +Dave Rolsky Eautarch@urth.orgE -=head2 use MX::AH instead of auto_deref +=head1 COPYRIGHT AND LICENSE -=head2 Namespace Your Types +Copyright 2009 by Infinity Interactive, Inc. -and don't use "::" +L -=head2 Coercion Instead of Unions +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. -=head2 Define All Your Types in One Module +=cut