Merged the content from Moose::Cookbook::Style into
Dave Rolsky [Wed, 11 Feb 2009 19:19:54 +0000 (19:19 +0000)]
Moose::Manual::BestPractices, and made the former a pointer to the
latter.

lib/Moose/Cookbook/Style.pod
lib/Moose/Manual/BestPractices.pod

index 1e5059b..35429ed 100644 (file)
 
 =head1 NAME
 
-Moose::Cookbook::Style - The latest in trendy Moose cuisine
+Moose::Cookbook::Style - Expanded into Moose::Manual::BestPractices, so go read that
 
-=for authors
+=head1 DESCRIPTION
 
-Please annotate all bad examples with comments so that they won't be copied by
-accident
-
-=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 C<@_> is processed, for example for
-C<< Class->new( $single_param ) >>, use C<BUILDARGS> instead of wrapping
-C<new>. This ensures the behavior is subclassable, 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::Moose qw(Object);
-
-    use MooseX::Types (
-        -declare => [qw(Person)],
-    );
-    
-    subtype Person() => ( # note parenthesis, "Person" is a function, not a string
-        as Object, # MooseX::Types::Moose exported it
-        where { $_->can("name") },
-    );
-
-=head3 Coerce in a subtype
-
-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,
-    );
-
-when the actual coercion applies only to your specific cases.
-
-=head1 Clean up your package
-
-Use C<namespace::clean> or C<no Moose> to remove the sugar exports.
-
-This will make sure the sugar isn't accidentally called as methods on your objects.
-
-For instance:
-
-    $obj->can("has");
-
-will return true, even though C<has> is not a method.
-
-If you choose L<namespace::clean>, make sure to keep the C<meta> method if you
-want to use it for introspection:
-
-    use namespace::clean -except => "meta";
-
-=head1 Accept no substitutes
-
-By substitutes I mean hacks instead of "proper" solutions.
-
-When you have a tricky requirement, refrain from abusing Moose or MooseX:: or
-whatever it is you are using.
-
-Instead, drop by IRC and discuss it. Most of the time a crazy idea can either
-be simplified, or it will spawn a clean, reliable feature to whatever package
-you are using.
-
-This will improve your code and also share the benefit with others.
-
-=head1 AUTHOR
-
-Yuval (nothingmuch) Kogman
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2006-2009 by Infinity Interactive, Inc.
-
-L<http://www.iinteractive.com>
-
-This library is free software; you can redistribute it and/or modify it under
-the same terms as Perl itself.
+The style cookbook has been replaced by
+L<Moose::Manual::BestPractices>. This POD document still exists for
+the benefit of anyone out there who might've linked to it in the past.
 
 =cut
index cab1af9..157e499 100644 (file)
@@ -35,6 +35,21 @@ Moose sugar and making your class immutable.
 The C<no Moose> bit is simply good code hygiene, and making classes
 immutable speeds 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 immutablized.
+
+The only reason to override C<new> is if 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.
+
+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
@@ -45,9 +60,15 @@ 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 Don't use the C<initializer> feature
+=head2 Provide defaults whenever possible, otherwise use C<required>
 
-Don't know what we're talking about? That's fine.
+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
 
@@ -91,6 +112,10 @@ 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
@@ -112,7 +137,45 @@ Use some sort of namespacing convention for type names. We recommend
 something like "MyApp.Type.Foo". I<Never> use "::" as the namespace
 separator, since that overlaps with actual class names.
 
-=head2 Coercion instead of unions
+=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>.
@@ -122,8 +185,32 @@ covered at length in L<Moose::Manual::Types>.
 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.
+
+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.
+
+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 particuarly problematic MooseX
+extensions which rely on introspection to do the right thing.
+
 =head1 AUTHOR
 
+Yuval (nothingmuch) Kogman
+
 Dave Rolsky E<lt>autarch@urth.orgE<gt>
 
 =head1 COPYRIGHT AND LICENSE