|Just another Perl shrine|
Re: How Large Does Your Project Have To Be to Justify Using Moose? (modular)by tye (Sage)
|on Oct 06, 2011 at 19:14 UTC||Need Help??|
Sure, Moose requires way too much "buck" for the "bang" it gives (in many people's opinions). But I actually choose to not use Moose because I believe it fundamentally shifts design focus in the wrong direction and pushes designs in directions that are counter-productive in the long run.
In order for Moose to be a complete OO system and for it to avoid requiring the writing of "ugly code", Moose pretty much requires (due to quirks of Perl 5) that everything be defined around methods. So Moose doesn't really allow you to talk about object attributes unless you write (or, much more likely, generate) accessor methods.
So OO design using Moose will almost always revolve around, primarily focus on, what attributes you want your object to have and the accessor methods for them. And that leads to class design that is mostly glorified hashes (or Pascal 'record's, aka. C 'struct's). And I've seen that suck in the long run so many times.
The point of good design is modularity. Modular design means defining a narrow, meaningful interface. Your focus should be on the methods you expose to the users of your class. Later you figure out what attributes are secretly used internally in order to implement that interface. (Never is when you worry about how inheritance plays into the design because inheritance is one of the worst tools you can use in design.)
So I get more bang from trivial things I can roll myself quite easily than the bang I would get from the parts of Moose that I don't consider unwise to use.
Implement attributes as constants so you get compile-time catching of typos on their names. Make internal accessing of attributes actually look different and a bit ugly, so you know the difference and you keep internal implementation details internal.
Delegate rather than inherit when combining classes. Actually pay attention to the interfaces between your classes. Iterate the designs of those interfaces so that they stay relatively narrow, clean, logical. Achieve polymorphism via "duck typing". Allow future classes to easily slip in where your current classes are. Allow for dependency injection.
Eschew the fall back to a C, C++, or Java style of "type system" that seems so essential to preventing simple mistakes when you are in a C, C++, or Java style of language where interfaces are only defined by positional parameter passing (and making methods more versatile via positional analysis of argument "types").
You are using Perl where you can easily use named arguments when the arguments are even moderately non-trivial or non-obvious. Name matching beats the heck out of type matching in my long experience in both programming worlds.
Types are very constrained objects. They are like objects with a single attribute, and that attribute is completely public. If you start slipping back into type-based validation (as you are almost pushed into doing as you use more Moose), you will find yourself more and more doing C++/Java-style design.
You'll end up with classes as bags of attributes with accessors and then you'll try to put protections around those accessor by adding "types" and adding 'before' and 'after' wrappers. Your logic for a single class will be split apart into tons of tiny pieces where the order and interactions will become almost impossible to see, predict, adjust, and debug.
But your code will look pretty. Just don't try to understand it on any sort of deep level (such as when you need to fix something).
Yes, doing modular development this way is a little less convenient in the short term. Moose and inheritance allows you to bang out something simple-looking very quickly. It is hella convenient when you start. But it really reminds me of "goto": simple, powerful, convenient, and leads to spaghetti in the long run. It reminds me of "ORM is Vietnam". Moose is very appealing when you start out and even provides productivity wins at first.
So, for me, the question would be more like "How small and short-lived does a project need to be for me to consider using Moose?".
(Yes, I'm actually working on several simple tools to make good OO design more convenient in Perl 5. For example, delegation of a whole list of methods should be something trivial to write, almost as trivial to write as 'use base "Thingy";' or 'does CoolStuff;'. But even while it isn't trivial in Perl 5, it also isn't particularly hard. Just a bit inconvenient.)