-=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
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
+=head2 C<namespace::autoclean> 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<no Moose> bit is simply good code hygiene, and making classes
-immutable speeds up a lot of things, most notably object construction.
+The C<use namespace::autoclean> 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<no Moose> at the end
+of your package).
+
+The C<make_immutable> 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<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.
+class is immutabilized.
-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.
+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>
+=head2 Always call the original/parent C<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.
+If you C<override> the C<BUILDARGS> method in your class, make sure to play
+nice and call C<super()> 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
Also, keep your builder methods private.
-=head2 Use C<lazy_build>
+=head2 Be C<lazy>
-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.
+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<lazy> unless they're C<required> or have trivial defaults.
=head2 Consider keeping clearers and predicates private
Predicates are less problematic, but there's no reason to make your
public API bigger than it has to be.
+=head2 Avoid C<lazy_build>
+
+As described above, you rarely actually need a clearer or a predicate.
+C<lazy_build> 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<lazy> and C<builder> options instead.
+
=head2 Default to read-only, and consider keeping writers private
Making attributes mutable just means more complexity to account for in
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<writer>
+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
Don't know what we're talking about? That's fine.
-=head2 Use L<MooseX::AttributeHelpers> instead of C<auto_deref>
+=head2 Use L<Moose::Meta::Attribute::Native> traits 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.
+The C<auto_deref> feature is a bit troublesome. Directly exposing a complex
+attribute is ugly. Instead, consider using L<Moose::Meta::Attribute::Native>
+traits to define an API that only exposes the necessary pieces of
+functionality.
=head2 Always call C<inner> in the most specific subclass
=head2 Namespace your types
-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.
+Use some sort of namespacing convention for type names. We recommend something
+like "MyApp::Type::Foo". We also recommend considering L<MooseX::Types>.
=head2 Do not coerce Moose built-ins directly
# 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
# 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<Moose::Manual::Types>.
+covered in L<Moose::Manual::Types>.
=head2 Define all your types in one module
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
+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 E<lt>autarch@urth.orgE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 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.
-
=cut