Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Writing TIMTOWDI-friendly CPAN Modules

by eibwen (Friar)
on May 15, 2005 at 07:32 UTC ( [id://457173]=perlquestion: print w/replies, xml ) Need Help??

eibwen has asked for the wisdom of the Perl Monks concerning the following question:

I've been looking into creating my own CPAN modules, reading a variety of perldoc (including perlmod, perlmodlib, and perlstyle) and nodes; however I still have several questions regarding the creation of flexible modules.

I should note that I'm approaching this from the perspective of the end user -- I'd like to implement the module to accept a variety of arguments presented in a variety of different ways; however I have several questions regarding the implementation.

Several nodes have recommended against shift @_, but I don't recall reading the reason for the recommendation. I'd presume there may be some conditions under which @_ is not locally scoped, but this is speculative.

Carp is a useful module, but at what point is carp or croak excessive? For example, if a sub expects a parameter, yet uses a default value should the code carp? From the perspective of the coder, I'd wager they knew what they were doing, but what of the end-user?

Are there instances where the organizational hierarchy should be sacrificed for brevity? Consider a module A::B::C with a member sub distorted_example_function. While I grant this example is intentionally abstract, it raises the question of the prudence of the hierarchy. While the argument could be made that the hierarchy itself should be reconsidered, this fails to address specialization and exclusivity. As a practical example, consider the module Engineering::Materials::Failure which offers a variety of failures based on the method of failure. Each of the failure methods could present a variety of functions to address a specific modus. The module structure seems ungainly at best, but is it prudent?

Prototypes are often discouraged, yet several CPAN modules feature them (albeit some with reservations). While I second this recommendation given TIMTOWDI, how does one code flexibly to provide for any number of permutations? A mathematical sub may be expected to compute a function given an input; however that input can take a variety of forms (a series of scalars, an array reference, a combination thereof, et all). While I have seen a few nodes and modules which are fairly flexible, I don't recall seeing any which support every permutation (even given the limitations of context and POD).

Tests seem to be a good idea, but how does one differentiate between the useful and the excessive? For example:

sub average { my ($min, $max) = @_; return ($min+$max)/2; }

I'm also intrigued by the notion of test-driven development, but given my limited understanding of the applicability of tests, this is not pheasible.

Suffice it to say, my foray into writing CPAN quality modules has left me with several questions regarding the perlstyle of CPAN modules. While I would appreciate responses to my questions above, I would also appreciate any other insights you may have regarding implementing TIMTOWDI-friendly modules.

Replies are listed 'Best First'.
Re: Writing TIMTOWDI-friendly CPAN Modules
by eyepopslikeamosquito (Archbishop) on May 15, 2005 at 09:42 UTC
      It is vital to focus on interface early and to get it right first time

      Well, I have found this is not always possible. Sometimes to find the best interface for a module you have to actually use it and also let others use it and give you feedback.

      I think it's better to just release the module as soon as possible clearly stating on the docs that the API could change.

        By all means, state clearly that the interface could change. Given it's the OP's first CPAN module, however, he should certainly seek advice on a proposed interface, and especially on module name, before uploading.

        As for actually using the module to determine how good the interface is, that is one of the many benefits of test-driven development: each test is a first class user of the module's interface and the act of writing the tests often causes one to change the interface. An interface that is hard to test is often hard to use. Code that can be unit tested in isolation is well de-coupled. Writing tests early improves design and interface.

        The practicality of changing an interface depends on how widely the module is adopted. For example, because File::Find is so heavily used, it has become practically impossible to change its (unfortunate) interface ... well, until Perl 6 rolls out, that is.

Re: Writing TIMTOWDI-friendly CPAN Modules
by Ctrl-z (Friar) on May 15, 2005 at 10:21 UTC

    The saying goes "Theres more than one way to do it", not "Theres more than one way you need to accomodate it". ;-)

    TIMTOWDI (as I understood it) refers to the core language, not general API design. I would reconsider your approach - you probably do not want or need the hassle of excessive error checking on parameters, a combinatorial explosion of edge cases to test for, laborious contradictory POD, maintaining obscure language features etc etc.

    If people dont like your API, well they can wrap it in "The Way They Want to Do It". And do their own damn testing.

    Make it useful and easy to grok. Keep it Simple, Stupid.




    time was, I could move my arms like a bird and...
Re: Writing TIMTOWDI-friendly CPAN Modules
by jhourcle (Prior) on May 15, 2005 at 14:35 UTC

    This may sound rude -- but write the module for yourself. Don't try to second guess how other people are going to want to use it. If you make it, and release it, and other people have suggestions, they'll tell you.

    If you make it complicated to the point where you don't even want to use the module, you've done too much work. You know what works for you. Without some sort of focus group, you're not going to know what it is that everyone else wants ... so put out something that helps you, and then see what other people comment on that would help them.

    The most important thing to writing modules is writing documentation, which I find to be one of the more difficult parts of the experience. So I would suggest writing the documentation first. (yes, I know, it sounds stupid, but it's actually like writing a use case, or writing test cases first).

    You write the documentation in a way that it makes the module easy to use in a program, then write the module to fit that documentation. If you have to, you can also write a cookbook as a series of ways that you expect the program to behave, and then use it as both documentation, and tests

      if you make it, and release it, and other people have suggestions, they'll tell you.

      Will they really? Or will they write another module? As eyepopslikeamosquito points out you're interface is kind of locked down. If you flag the modules as alpha and the interface many change it's likely people just won't use your module, and you won't get the feedback.

      In my opinion it very well can be better to use various resources to request feedback before you release it.

      If you make it complicated to the point where you don't even want to use the module, you've done too much work.

      Having a worked-out interface and a thought-through approach doesn't mean you have a bloated module. Keep it simple, but also don't paint yourself into a corner.

      ihb

      See perltoc if you don't know which perldoc to read!

        In my opinion it very well can be better to use various resources to request feedback before you release it.

        in my opinion, to get useful feedback, you need to actually release something. Specially for modules related to some specific field, say bioinformatics, its much easier to get bioinformatics to comment on your module if you give them some working code.

        If you start with a complete API doc, but without code, then you will get feedback but more of the "teorical" kind... and then you will need to discern the good advice for the bad!, with working code you can just try and decide... thought, obviusly, you should be willing to change things.

        Be realistic, you don't upload a module on CPAN and zillions of people start using it, and anyway, most people will expect a module at version 0.01 to be unstable, and will not complaint about API improvements.

        Will they really? Or will they write another module? As eyepopslikeamosquito points out you're interface is kind of locked down. If you flag the modules as alpha and the interface many change it's likely people just won't use your module, and you won't get the feedback

        I never suggested releasing alpha code. I fact, I will never knowingly release code that I'm not comfortable with. I'm required to release code due to requirements for my job (US federal government), but I have held off putting it into CPAN because I'm not happy with the quality of the documentation, or the depth of the installer tests.

        It would take a lot for me to install something that I specifically know is alpha code, and that the API isn't fixed... But I never suggested that anyone do so. I consider 'alpha' code to be anything that is known to not work as intended, known to have issues that may cause interaction problems, or that has undergone no significant testing. In my opinion, alpha should never leave the shop it was developed in. Beta, to me, is when you have passed your internal testing, but pass it out to others to test as well.

        I also have a different situation than many other people, as 'my' work is part of a team effort, so I have three other people that I regularly bounce ideas off of, and we have two other external groups who are actively making use of our API, and it's very difficult for me to keep our alpha seperate from beta. (in system terms, development vs. qa/testing)

        Yes, it is entirely possible that someone may not like your module, and decide that it's better for them to write all new code. That is not a failure on your part. Your first responsibility is to yourself, not to everyone else who might find interest in your module. This may sound rather rude, but we do not live in a purely gift society. You are never going to satisfy every possible potential user.

        This is true in any endevor -- in most situations, you can apply the 20/80 rule -- 20% of the customers require 80% of the effort. If you are writing code for yourself, and you're one of the 20%, Then doing a little bit of work to get everyone else happy isn't a big deal. However, if you go out of your way to satisfy other people, then you're exhibiting signs of co-dependency.

        My job pays me to do my work, not someone else's. Sure, I can throw in a few tweaks here and there for other people, but they don't want to pay me for solving other people's problems. I can do it on my own time, and I frequently do, but I've been trying to cut back, as I know I have every one of the signs of co-dependency, and many of the signs of being a workaholic.

        If the module is useful to you, then there's a possibility that other people may find it useful. If they drop a comment on improvements, you don't have to oblige them -- under most licenses that perl code is released under, they can always fork the project if they want to make changes that you don't want, for whatever reason.

        If you make it complicated to the point where you don't even want to use the module, you've done too much work.
        Having a worked-out interface and a thought-through approach doesn't mean you have a bloated module. Keep it simple, but also don't paint yourself into a corner.

        How did you manage to get from one quote to the other? If you make it complicated to the point where you don't even want to use the module, you've done too much work. If the module is no longer something that you want to use, there's something wrong. It's no longer something that you'll care about, and you're not the person who should be maintaining.

        There might be someone else who would be willing to improve and maintain it, or fork their own, but there is something fundamentally wrong about working on a project that you do not want to use.

        There are valid times for fork a project. Trying to make your program do everything for everyone frequently results it in becoming useless for most people. (Hell, I can't even get people to agree on how to specify time). If you can, make it so that people can inherit the module, and override parts they need to change, but you don't need to do everyone else's work for them.

Re: Writing TIMTOWDI-friendly CPAN Modules
by salva (Canon) on May 15, 2005 at 11:01 UTC
    Functions that accept multiple argument combinations are not always a good idea: they are more difficult to document, difficult to implement leading to spaghetti code and so they also are more bug prone, and sometimes corner cases become ambiguos.

    Prototypes are not so bad, you don't need them most of the time, but in some ocassions they provide the syntactic sugar required to make a function much more friendly. I specially like the & proto that allows to write functions that work as grep {...} @foo;. My advice is: use them only when there is an obvious gain.

    Carp::croak is your only way to report fatal errors in modules (well, except internal errors that should be reported with die), but Carp::carp is not so useful. If some function accepts optional arguments then it's ok for the user to not pass them and no warning is required; on the other hand, if some required arguments are missed, croak!.

    Anyway, if you use Carp::carp, remember to let the user deactivate the warnings using warnings::register and warnings::enabled() in your module.

Re: Writing TIMTOWDI-friendly CPAN Modules
by Tanktalus (Canon) on May 15, 2005 at 14:03 UTC

    Parameter checking is probably less useful than you may think - especially in perl where everything can be anything.

    Imagine that your function says it takes a file handle. Do you check that you got a GLOB reference? Or do you check for an IO::File? How about if the user finds a way that your function could be useful in a scenario where the data is coming in via IO::Socket? Or that the data is generated in memory via IO::Scalar? Or maybe there's some real dirty trick, and I find a way to create a tie'd scalar or something? All of these will work, yet your code only allows a subset for what really boils down to an arbitrary (and underinformed) reason.

    (I've recently been bitten by the unexpected behaviour of File::Copy only working if the source file is really a file.)

    Since perl is so good at doing what the user expects, take advantage of it, and let perl do the work.

Re: Writing TIMTOWDI-friendly CPAN Modules
by dragonchild (Archbishop) on May 15, 2005 at 18:09 UTC
    There's a number of good articles on http://www.perl.com, particularly in the archives. The most recent was Building Good CPAN Modules.

    • In general, if you think something isn't in Perl, try it out, because it usually is. :-)
    • "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"
Re: Writing TIMTOWDI-friendly CPAN Modules
by northwind (Hermit) on May 15, 2005 at 17:13 UTC

    This post and the resulting replies have reached a level of usefulness that makes me want to keep track of them; so I'm bookmarking this thread as reference material to keep in mind when I finally get around to releasing a module to CPAN.
    Thank-you.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2024-04-22 18:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found