Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Can I please have *simple* modules?

by Ovid (Cardinal)
on Nov 23, 2005 at 06:38 UTC ( [id://511014]=perlmeditation: print w/replies, xml ) Need Help??

Class::MethodMaker is symptomatic of a problem that is causing me more and more frustration. Bricolage, as many know, is rather difficult to install. A huge part of the problem isn't Bricolage itself (once the dependencies are in place Bricolage is a piece of cake to install), it's the twisty little maze of annoying dependencies which are the bulk of the problem. Some dependencies don't list all of their dependencies. Some fail their tests but run just fine. Some fail their tests but those failures are portions of the software we don't use. What's a programmer to do?

Personally, I've sent plenty of bug reports to authors. Sometimes they fix them. Sometimes they ignore them. I've sent plenty of patches to authors. Sometimes they use them. Sometimes they ignore them. Sometimes I've just sent a damned tarball with everything working only to receive no response. In fact, there's one piece of software I use regularly which I've patched locally because I've been waiting over a year for the author to keep his promise to incorporate my patch (I'm not naming the code but I'm pretty annoyed by this).

What do these various modules have in common? They're usually large "wunderkind" modules which do everything you could ever want and your dishes too. Unfortunately, they have a nasty habit of breaking those dishes. Class::MethodMaker is a great module and I've used it quite a bit in the past, but it's been seriously failing its installs for over a year and these don't appear to be the typical failures related to the CPANPLUS bugs we've all been plagued with lately. This is a problem I keep encountering and it's frustrating when I run into huge modules which keep failing and I only need a small fraction of its functionality.

So I suppose I can look at Class::MethodMaker's XS code and regular code and try to see what's going on but frankly, it's very confusing code (just take a look at Build.PL and Makefile.PL). With Class::Trait, I sent enough patches and suggestions for complicated code because I needed it (that was before stvn gave it to me). With so many other modules, I face the agonizing task of maybe having a bug fixed, maybe having a patch accepted, maybe having some response from the author when, for the most part, I don't need that code.

There's nothing wrong with wanting small, lightweight modules that do exactly what I need and do it well. There's absolutely nothing wrong with trying to build big modules that do everything an end user might need (I've written some of them), but there's also nothing wrong with deliberately trying to get small, easy to install modules that just friggin' work. The problem is, when we release large software packages with many dependencies, relying on other large software packages with many dependencies means that more things are likely to break and my software is less likely to be useful.

So when perrin reasonably suggests that I reuse existing code, I feel trapped between Scylla and Charibdis. If I follow his suggestion, I'm going to spend more time on something which may or may not work only to incorporate code which makes our products harder for others to install and use. Or, if I create a small, powerful alternative which is much less likely to break, I can silently incorporate it in our code and not get a chance to share it or I can put it on the CPAN and have people get upset with me reinventing the wheel.

This is why Joel Spolky's defence of "Not Invented Here" syndrome is more and more appealing to me. I really don't know what else to do. Should I not "pollute" the CPAN with easy to use modules which might duplicate functionality? There are definitely pros and cons to this approach, but I'm beginning to think that if I "reinvent" any wheels, maybe just not releasing them is the way to go. That sounds selfish, but I'm also concerned about CPAN pollution. It's often difficult to find what we need and if everyone releases every module they've ever written, it's going to make a current bad problem even worse. I really don't know the best solution here.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Can I please have *simple* modules?
by BrowserUk (Patriarch) on Nov 23, 2005 at 08:33 UTC

    This issue is so symptomatic of all library systems, but especially OO library systems; and even more so when the components that make up the overall system are developed by disparate groups, of which CPAN is the most extreme example I know.

    When you sit down to develop a module, as opposed to solve a problem, you have a single core problem you are addressing. You put the code in place to solve that, but then you have a single function, or a class that has a single constructor and a single result producing method. At this point you are tempted to try and envisage all the ways that your module might be used, with the usual result that you add a few extra subs/methods that make it's use 'easier' or 'more intuitive' for half a dozen "common use scenarios".

    Then the next guy does the same with his module. And the next with his.

    And then someone comes along and picks up these modules to reuse them within their module. And then they add a few extras to support various use cases their users might have. And, they also have to write various bits of glue code to match the data-structural requirements of their module to those of the various modules they reuse. And, potentially, mappings between the data requirements of those reused modules.

    The result is that you end up with a considerable amount of extra code at each level that isn't used by any given caller. This accumulates with each new layer that gets added. This has a detrimental affect on performance, code-base size, load-time footprint. The problem grows exponentially relative to the number of layers.

    And most importantly, the communication paths, and therefore the hysteresis involved, in maintenance of the top levels, grows exponentially also. Every time a change is required as a result of bugs or feature additions, the need to communicate with others, convince them of the requirements for change, and the potential that the change you require is going to break their module for some or all of their other users, can lead to molasses-like problem resolution.

    The alternative, as exemplified by the Java libraries, is to break each piece of functionality out into separate classes. In the case of the Java libraries, with their single inheritance model and interfaces fudge to class partitioning, this leads to cut&paste code reuse, (of concrete implementations of the interface methods in different classes), as the only option for dealing with common functionality across the breadth of the class structure. And horribly deep vertical superclass trees. ANd Java has the advantage of a single controlling body making the decisions--unlike CPAN.

    Using the MI approach can avoid the cut&paste code reuse, by subdividing functionality into a fine-grained mesh. The problem with that is that it has a tendency to produce base classes that get thinly wrapped, by almost every caller, in order to bend the interface to the needs of their application. It also has the effect of producing very wide class structures with cross-links, and therefore cross-dependency chains, at many levels. This is where traits/mix-ins would be most beneficial, especially in Perl.

    Why especially in Perl?

    Compared to Java, C++, Haskell et al., Perl has a very small set of basic data types. This means that if the instance data of classes is maintained within Perl's native data types; scalars and arrays (not sure about hashes yet); then it becomes easy to write traits/mix-ins that operate directly upon the instance data of their symbiotic partners. Just as map, grep, etc. can operate directly upon any array, regardless of the type or meaning of their contents, so a well written trait or mix-in should be able to operate directly on the instance data of it's host with a minimum of, or no data conversion required.

    The big idea behind Java's interfaces is that if two classes fulfill the same Interface specification, the it becomes possible to write a concrete class that implements that Interface and it will be usable from both classes. The problem that arises is that the methods of the Interface often make little or no sense in respect to the classes that import them. At the simplest level, a method name that makes sense in terms of the Interface, may make no sense at all in terms of the class importing it, even though the operation performed does.

    Eg. An interface that calculates the minimum of a set of numbers might use the word 'minimum' in the method name. Of two modules using that Interface, one might better name the method ShortestRoute(), and the other BestPrice(). That's a weak example, but illustrative.

    Example 2: One hosting author might prefer getters and setters and the other mutators.

    In both cases, the authors of the hosting classes are forced to write trivial wrappers around the Interface methods to achieve their requirements. And that assumes that the data storage used is compatible.

    A harder problem, that harks back to the need for 'interface glue code' I mentioned earlier, is the need to restructure the data used within the hosting class to a form that the Interface can manipulate. And back again if the method is mutative.

    Perl 5's preponderant use of hash-based objects, and the tendency to wrap every piece of data, even aggregates, into separate instances, means that every method that operates upon that aggregate has to be written to understand the interface to those objects. It has to know what methods to call to get and set the values inside as a very minimum.

    If aggregate data is stored within Perl's base data-types, particularly arrays, it becomes possible to write methods that can manipulate a variety of data using common code with no need for type introspection cascades. The ultimate expression of this is sorting. A module like Sort::Key can export a small set of entrypoints, that deal with the various value interpretations of Perl's scalars, and then be re-used for many situations with the only proviso that the data be in list form.

    The ultimate expression of this maximising re-usablility through the expedient of a minimal type system, is Lisp--where damn nearly everything is a list, including code.

    This is where I get antsy about the varying specifications of traits, mix-ins et al. Some propose that they should have no instance data of their own; others would permit it. Some would utilise introspection of their hosts to achieve their function; others require the hosting class to provide concrete implementations of one or more methods. Which combination of permissions and restrictions is going to make for the best combination of usability and re-usability whilst imposing the least amount of glue, is still very unclear in my mind.

    And I think that the balance will be markedly different for Perlish, dynamic languages than it is for statically compiled languages; with the fulcrum of the balance shifting according to how much compile-time effort can be appropriately expended upon rationalisation, optimisation and automated interface code generation.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      You have pointed out the|my situation -- when using different classes (in Perl or Java) -- very well about the requirement|necessity to convert data structures. If one is not using a list-based processing langauage, sooner or later data structure *has* to be converted (in the above context).

      "One hosting author might prefer getters and setters and the other mutators"- A setter is a mutator?as it mutates the value?

      Anyway I think the solution is sometimes to write code that works both ways.That is make some subs handle being called on objects with and without any attributes. So you then have the option of passing object or parameters.

      Interfaces are used to connect otherwise unrelated classes and don't contain any real code. Thus you separate the actual implementation from the externaly used interface.

      The same wrapping/implementation hiding can be done in Perl, except you cannot ensure the classes always implement the required methods for the interface and it is less easy to restrict class access to private attributes.

      CPAN modules having multiple interface classes to allow easy implementation/version changes is an interesting idea.

Re: Can I please have *simple* modules?
by brian_d_foy (Abbot) on Nov 23, 2005 at 07:19 UTC

    I think you should write the general module that solves the task with a simple interface. Some of the modules you have mentioned (in this thread and others) make assumptions about the class implementation or other design details.

    Your pain takes up two of chromatic's "Seven Sins of OO Programming" which appears in the next The Perl Review (and maybe in his talk slides if they are around.

    As a PAUSE admin I don't mind Class::* pollution. In training and consulting I tell people to ignore that namespace since so much of it trivial code with much better ways to do things, and the ones that aren't are overly complicated that force you into a corner.

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review

      I've seen that talk. It was a good one. I look forward to the article.

      And while you as a PAUSE admin might not mind the Class:: namespace pollution, it was hell for me as a consumer to have to wade through all of them just to find out that what I needed wasn't there :)

      Cheers,
      Ovid

      New address of my CGI Course.

        As a consumer, it's already hell. You'd be adding a grain of sand to a beach. :)

        The only way to get rid of the bad interfaces and unmaintained modules is to upload good interfaces that somebody will maintain. That the space is cluttered with crap shouldn't keep out the good stuff. Once you upload, I can say "Don't worry about remembering the name, just use the one Ovid wrote." :)

        --
        brian d foy <brian@stonehenge.com>
        Subscribe to The Perl Review
Re: Can I please have *simple* modules?
by perrin (Chancellor) on Nov 23, 2005 at 15:57 UTC
    Beware the devilish lure of writing a ::Simple or ::Lite module. I often hear people say they are writing something "like Template Toolkit, but faster and more lightweight." They eventvually discover that there was a good reason for those features that seemed pointless to them at first, and soon the lightweight module grows into a beast.

    That's not really the issue here though. In this case, the issue is that the module which does what you want (Class::Accessor) requires you to inherit from it, and you don't want to.

    I have a lot of sympathy for not wanting your namespace polluted. I hate it when people put things in UNIVERSAL:: and I try to be very careful about namespace stuff. However, if I avoided every module I didn't like the interface of, I would be rewriting a ton of code.

    Just to name a few, Regexp::Common, CGI, Getopt::Long, Apache::Session and Data::FormValidator all have pretty annoying APIs. (I don't like the much-replicated HTML::Template interface either. Sorry Sam.)

    I hold my nose and use these modules because they work, get my job done, and save me tons of time. In your case, writing something to make accessors is so trivial that I suppose you aren't saving that much time, so it could go either way. I don't personally see the interface problems as very serious though.

    Regarding your troubles with Bricolage installation, I still think the smartest way to distribute an application that relies on CPAN modules is to bundle them with it, along with a build script that installs them into a local directory. This has worked really well for Krang, and the company I work for has adopted this approach for all of our software. It avoids module versioning issues and allows you to patch a broken module locally if you have to.

    There is no need to run the test scripts for every single module when you build them -- just run the tests for Bricolage. If they are not good enough to tell whether you have a working Bricolage system by themselves, improve them.

      One of our clients distributes a minicpan with his application. The user starts with a "run_me" file on the distro CD. That script configures CPAN.pm in memory (so it doesn't change or overwrite local settings), then installs everything from its own repository. Using CPAN::Mini::Inject and some other magic, we can add or replace any file.

      It's certainly a pain when the external module authors don't acccept patches or can't be reached, but for most people they don't need to upgrade. That we might have to modify somebody else's code to deal with updates isn't all that worrisome: imagine writing all that code from scratch! We're in a pretty good place when that's our major annoyance. We've been living a pretty good life. :)

      --
      brian d foy <brian@stonehenge.com>
      Subscribe to The Perl Review
        I just noticed that Module::Install seems able to do all this too: find dependencies, package them up, and install them with your project.

      FYI: Class::Accessor also assumes I'm using blessed hashes. I just discovered that. So we have yet another module which doesn't do what I need (I wonder how many folks want accessor generation only to find out they must use a blessed hash with canned modules?)

      Cheers,
      Ovid

      New address of my CGI Course.

        Class::Accessor does let you override get/set. You may well ask what the point of it would be if you have to override that part, but it can be done.
Re: Can I please have *simple* modules?
by fluffy (Scribe) on Nov 23, 2005 at 14:34 UTC
    Ovid,

    thanks for your commentary. I've checked my email, I don't see any messages from you to say that you've got problems installing C::MM. Did I miss one? Is there an email misdirect somewhere? Did you mail me as a different name? Have I simply mis-filed? If you let me know how to reproduce them, I'll see if I can help. I have MacOS X and linux available.

    If you want a simple module, write a simple module. C::MM tries to do some complex stuff, so it's a complex module. If you want a simple interface to the more common tasks, I'm open to contributions.

      Hi fluffy,

      I ran into this problem last night. I didn't send the email because I've seen those test failures for CMM for a long time and since there are also a variety of open issues in the CMM RT queue, I just moved on. I don't mean this as any offense to you, but there are days when I just get tired of documenting and tracking every bug I find in large external modules. There's also the problem that CMM apparently assumes I'm using a hash internally. This breaks some of my code. So not only did I have difficult installing it, it really doesn't do what I need.

      I did check and see I still have the info in my buffer. If you're curious:

        Ovid,

        Thanks for the details. FWIW, I don't see the same thing in similar circumstances (I'm also on Mac OS, and Linux), but there were a couple of bugs in Build.PL I picked up from the RT queue, so I've fixed those and uploaded 2.08. I'd not used CPANPLUS before, being a roll-your-own kinda guy, but I tried it and it worked out of the box for me (with C::MM 2.07), so that's kinda weird. Do you have any non-default settings with yours?

        I've resolved all the issues on the RT queue, I hope.

        As to the generic thrust, I'll make the following points:

        -) As far as forcing one to use hashes "I wonder how many folks want accessor generation only to find out they must use a blessed hash with canned modules?", I will observe that I did consider trying to be object-impl. agnostic, but chose against, for that would make the module even more complex, and the slanging on PerlMonks would have come all the faster. As it is, hash-based objects are the majority by an order-of-magnitude, and non-hash-based are used most commonly in specialist situations (e.g., performance-intensive ops) where you'll be avoiding generic solutions anyway.

        -) The rest of the thread seems to me the general case of "I want the moon, and I'd like it on a stick". I'm referring to thread as a whole here, not specifically your posts. Of course we'd like modules to be simple to use, and (although it's often less said), we'd like 'em to solve complex issues. If they were simple issues, it wouldn't be worth the time surfing CPAN for them. So we end up with a trade-off: simplicity of use vs. complexity of problem solved. And wherever there's a trade-off, there's a team of people ready to criticize it. It is worthy of note that there's always a thread like this one, including the position (e.g., demerphq), of "accessor generators are wrong", and I regularly get requests for more feature additions. There's no pleasing everyone.

        -) I see no problem of you writing you own module if C::MM and others don't suit your needs, either because they are too complex, or you want to use arrays/scalars/filehandles/whatever to implement your objs. Code reuse is about not re-writing code that does do what you need, not code that doesn't. If you were to write a module that assumes hash-based classes, with argument type-checking & optional tied storage, then I would wonder if re-using C::MM wouldn't make more sense, but it's your time & code.

        -) C::MM does have many flaws, it is more complex than I would like, the documentation isn't as good as I would like, and I don't get to spend much time on it now that I have a daughter to look after. I'm happy to talk about those (subject to time). On the other hand, it's used in many places, I get positive feedback from many users, so I'm happy to have contributed what I can.

        In summary, if you go to the farm and find a horse, by all means help me to make it run faster, but please don't complain to me that it doesn't give milk. You want a cow for that.

        I appreciate that you weren't aiming to offend me, and I'm not offended; my comments are aimed at the thread as a whole. I do get a little tired of the complaints (at all free software) that it "doesn't do what I want". If as the complainants generated half as much code as commentary, there'd be a great deal less complaining to do. And that's definately not aimed at you Ovid - you clearly do produce the goods, so you've earned your right to a whinge.

Re: Can I please have *simple* modules?
by dragonchild (Archbishop) on Nov 23, 2005 at 16:52 UTC
    This is the very reason I wrote Tree and am taking over maintainership of all of the main Tree::* modules so I can deprecate them. My theory behind it is that the main module should do the simplest thing possible to implement what needs implementing. Then, when you want to customize it, it should be customized very easily. For example, stvn pointed me to DBIx::Roles (which is really DBI decorators, not roles). That provides a really good framework within which an author can release DBIx functionality in a way that plays nicely with other DBIx functionality. Tree does this by providing five functions1 that, with options, does everything you want to do to a tree data structure. It also provides an events/callbacks framework that Tree::Persist uses to implement transparent persistence. It also provides a place to put arbitrary data that Tree::Compat uses to implement compatibility layers for the various modules I'm taking over.

    DBI v2, from what I understand, will be moving in this direction. So is CGI::Application with the plugins architecture. The Class::* namespace is a mess, in large part because Perl5's OO framework is too minimal. That's why I didn't use one when writing Tree - I didn't want the dependency on something that fundamental when it was easy enough for me to avoid it. It may not be so easy for others, especially a well-developed distribution.

    You're right - this is a hard problem which doesn't admit of an easy answer. Things will be easier in Perl6 (as they currently are in Ruby) where you will be able to require a name, version, and author (plus arbitrary metadata). Then, you can fork your distribution, release it to CP6AN, and then depend on it based on author. When your fork is folded back into the main branch, you can release an update that now points at the main branch with the appopriate version and author.

    Once that comes into play, if I don't own the module, I will probably require the exact version I built with for modules I don't own. Because installing versions side-by-side won't be a problem, that will probably be safest.

    1. Those are new, add_child, remove_child, traverse, and set_value. There's a large number of state-inquiry functions, like is_root, is_leaf, parent, children, root, depth, height, width, size, etc, but those don't do things. Everything else can be implemented in terms of those functions, and I provide an example of this (implementing a visitor) in the documentation. So, for example, I didn't write add_child_before() or add_child_with_value() or any crap like that.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Can I please have *simple* modules?
by creamygoodness (Curate) on Nov 23, 2005 at 15:40 UTC

    The pressure exerted by a user base towards Feeping Creaturism can be intense. For an example, see the CPAN reviews for List Util.

    Users have supplied some very sophisticated patches for a contribution of mine to the "simple modules" group, Sort::External. I wrote the Sort::External::Cookbook rather than integrate one of them. It can be challenging to balance showing appreciation for people's contributions with the need to keep a module's interface streamlined and its documentation brief.

    For Ovid and me and everyone else to "have simple modules", first they have to be written, and then they have to stay simple after they're written. I'd like to raise a pint to Graham Barr for keeping List::Util uncluttered.

    --
    Marvin Humphrey
    Rectangular Research ― http://www.rectangular.com
      I don't think that "simple" equals "only doing a few things". I don't think List::Util is much simpler than POSIX. They are both modules with a collection of subroutines. And while the POSIX module has the potential of doing a lot more than Class::MakeMaker - it's much simpler.

      Adding functions to POSIX or List::Util doesn't make the modules more complicated - it doesn't become harder to use the new functions, neither does it make the existing functions harder to use. You just use the module, and list the subs you want to use. Class::MakeMaker suffers from the problem that there are so many ways of doing related things, that's why there's a lot of 'configuration' necessary, and that's what makes it complicated.

      Perl --((8:>*
        I don't think that "simple" equals "only doing a few things".

        Maybe not, but it helps. Compare what happens when you perldoc POSIX with what happens when you perldoc List::Util.

        A cacaphony starts with a single "feep". You have to draw the line.

        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com
Re: Can I please have *simple* modules?
by rinceWind (Monsignor) on Nov 23, 2005 at 16:53 UTC

    Ovid++ brilliant insight.

    I think that you have highlighted the main drawback of Perl, and why it is losing favour for "enterprise applications". CPAN is both Perl's great strength and its great weakness. Having an application that requires a gazillion dependencies, all of which could break the install, is a nightmare that is beyond the ken of most people outside the Perl community.

    I recently attended an evening presentation on web frameworks in London. Presented were Catalyst, Django (Python) and Ruby on Rails. Catalyst did not come across well to the audience, except for the Perl geeks who know and love Template Toolkit, Class::DBI, etc. The Perl "solution" came across as a Lego (or perhaps Meccano) kit to build websites with - lots of choices, flexibility, and it really can make you a cup of tea (if you install Catalyst::Plugin::TeaMaker :) ).

    Both Django and Rails came across as slick presentations with end user application demos that certainly impressed me, and I think a large chunk of the audience including the Perl geeks. This event has been discussed subsequently on the london.pm mailing list.

    Solving the packaging problem is something I am very interested in, and is the subject of a talk I have given, and intend to repeat on Saturday at the London Perl Workshop.

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)

      The next Catalyst release (5.58) will have quite good PAR support.
Re: Can I please have *simple* modules?
by sauoq (Abbot) on Nov 24, 2005 at 02:48 UTC

    As great as CPAN is, you've brought up its Achilles's Heel.

    The ugly truth we all avoid when we tout the greatness of CPAN is the fact that its many jewels are hidden among heaps of mediocre, amateurish tripe. (Sorry, but it's true.) I don't mean to impugn CPAN's greatness by any means but I do think that we should be honest with ourselves. Part of the problem is that we applaud the sheer quantity of modules it contains as some grand realization of TIMTOWTDI without acknowledging that some many of those ways suck.

    Maybe the ratings on CPAN were supposed to help. If so, I don't think they have. They certainly don't help someone find the best module to use. That can take hours of reading documentation (and then more hours of discovering what's wrong with that documentation) and hours more of experimentation.

    Dependency hell has grown out of control, IMNSHO. I have a pet peeve when it comes to the Test::* modules. I'm sick to death of finding I have to go install Test::Yet::Some::More to run the tests for Some::Module.

    I think CPAN needs a "best of breed" designation or something. There should be some way of searching a subset of modules that have already gotten substantial use and review by experienced Perl programmers. It should also be a requirement that no BoB module depends on any non-BoB module.

    -sauoq
    "My two cents aren't worth a dime.";
    
      There were a few initiatives to improve CPAN: CPAN::Forum, AnnoCPAN. Yet after some initial play with them I don't use them. There is something missing, CPAN is enormous, I don't want to read posts about all of its modules, there should be some way to subscribe to the modules I like and receive only messages about them. Another improvement would be to somehow integrate it with search - but I have no idea how to do this. Eventually I think that we need something where the information structure can be build incrementally - a wiki (there was a wiki for modules maintained by Iain Truskett, but it's down now after his death).
        I believe CPAN::Forum allows you to subscribe to specific distributions (not modules) and sends you an automated email whenever someone posts about them. I was planning to add a similar feature to AnnoCPAN, but no one had complained about it yet. ;-) (People did ask about being able to subscribe by author, so I added that.)
Re: Can I please have *simple* modules?
by demerphq (Chancellor) on Nov 24, 2005 at 08:50 UTC

    I don't use modules like C:MM or kin. I think they are a waste of time. Its far far easier to handcode such factories to your individual taste and requirement than it is to try to fit your requirements into the way modules like that expect you to do things. You asked in another threads why people dont use Traits. Well, for all I know I do use traits. Its just I dont use Class::Traits or any module like that to manufacture them.

    You mention Spolsky defense of NIH, which brings to mind something that I read in Code Complete: never use wizards you didnt write. I consider method factories and class factories to be wizards I didnt write so I dont use them. Hand coding stuff like this is acceptably fast (c'mon folks, writing method factories is trivial stuff) and it then fits your requirements to a T. Using other peoples code just introduces dependencies and points of failure that are difficult to manage.

    Now, dont go an take what im saying here and assume it means I dont agree with code reuse, thats not at all what I'm saying. I use CPAN stuff all the time. But I dont use any of the "helper class" stuff. So far every time I have its proved to be both an exercise in frustration and a big waste of time.

    ---
    $world=~s/war/peace/g

      It all depends on the complexity of the methods you're making. Let's say I have 4 or 5 "inherited sets" in a particular class. I'm saving a bit more than just a handful of lines of code by using a method maker in that situation. But the best part is that if there's a bug in my inherited set implememntation, I can fix it in one place (the "no code duplication" thing strikes again) and all my classes that use inherited sets benefit from the fix.

        Looks to me like you wrote that code. Which means it doesn't violate the "don't use wizards you didn't write" rule. And yes, I too have written such code. For some of my work code I have a shared framework where I have method manufacturers. But I wrote them, they fit _exactly_ to my needs. I'd never upload them to CPAN because quite simply no other set of applications would ever want to use them.

        In other modules I also have method manufacturing code. But again I wrote it. It does exactly what I need, and if I need to I will totally rewrite it for the next release. In my case I also fix one place and it fixes all my code using it, but all the code using it is all the code that will ever use it. And frankly I think that makes a lot more sense than reusing some of the stuff on CPAN. I have full control, understanding and insight of the methods, and they match my requirements and my thinking patterns exactly.

        I guess this is like shoes or other custom clothing. Sure you can by mass-produced shoes and like them, but if you go to shoemaker and get a custom pair youll never complain about the fit, and you certainly wont be lending them to anybody else. To me method factories are like shoes. They should always be custom because they fit better that way, and they should never be loaned to somebody else, because they are designed for my feet not theirs.

        ---
        $world=~s/war/peace/g

      I agree 100%. I'll never understand why people are willing to add another dependency on a third-party module to use a "helper function" that saves a few lines of code (sometimes even just one, yes, one line of code!). My policy is to only use helper modules/functions that come with the perl core (and then not all of them).

      I also agree entirely with this. I've no interest in incorporating code that restricts how I must code my own modules. And I don't want someone else's code to have that deep of an impact on mine. Using a module that provides a specific set of functionality through a well defined API is something else entirely.

      -sauoq
      "My two cents aren't worth a dime.";
      
Re: Can I please have *simple* modules?
by Perl Mouse (Chaplain) on Nov 23, 2005 at 20:45 UTC
    While I can understand the wish for simple modules in general, I fail to see why anyone would want to use a module to generate their accessors.

    Accessors are simple. They're one liners. I find code that just spells out the accessors much simpler than code that uses a module to create the accessors for them - no matter how simple the module is.

    # Look ma, no module! sub get_attribute {$attribute {refaddr $_[0]}} sub set_attribute {$attribute {refaddr $_[0]} = $_[1]}
    Perl --((8:>*

      Why on earth would you want to retype that over and over again for every accessor/mutator?

      Cheers,
      Ovid

      New address of my CGI Course.

        Huh? Retype? What primitive editor do you have?
        Perl --((8:>*

      So thats the accessor code you use. Cool. But wheres the DESTROY? And how do you manage it? Id expect some infrastructure to manage the attributes. Something like:

      package Foo; use Scalar::Util qw(refaddr); use strict; use warnings; BEGIN { my @destroy; sub DESTROY { my $addr= refaddr $_[0]; foreach my $hash (@destroy) { delete $hash->{$addr}; } } sub reg_attr { push @destroy,\my %hash; \%hash } } BEGIN { my $attribute=reg_attr(); sub get_attribute{ $attribute->{refaddr $_[0]} } sub set_attribute{ $attribute->{refaddr $_[0]} = $_[1] } }
      ---
      $world=~s/war/peace/g

      #11911 You wrote the same thing twice here. The cardinal rule of programming is that you never ever write the same thing twice.

      Makeshifts last the longest.

        What? You only have at most one for() statement, or one while (<$handle>) statement per program? Or do you factor that out as well?

        Never writing the same thing twice doesn't work on a low level. Accessors are low level.

        Perl --((8:>*
      I'll often just use a loop and a closure to make mine.


      -Lee

      perl digital dash (in progress)
      What about AUTOLOAD? Infinitely extendable, allows the user to add attributes without sub-classing :-D

      --
      In Bob We Trust, All Others Bring Data.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://511014]
Approved by BrowserUk
Front-paged by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (7)
As of 2024-03-19 03:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found