Everyone has their own itches to scratch. It would be nice if their scratcher worked on your itches, but it doesn't appear so. And I suspect that most people don't have the time to scratch your itches -- they have too many of their own.
So the decision then becomes to adapt theirs or create yours. Working with people you've never met can be hard, especially when you're asking them to do more work, so you might as well create your own, right?
But while your new module might start out focused and with an elegant idea of separating everything into nice neat little compartments, real life and complex problems often force messiness on us. What's insidious is that the messiness is a little bit here, a little bit there. And (being generous) I'd hazard a guess that this accumulation of messiness is one reason why publicly released modules get the way they do.
IMO, the real flexible, elegant solutions for nontrivial problems have either been out for a while in some form or other (like the Template Toolkit) or have been designed by lots of smart people doing nothing else. There are exceptions of course (look at SOAP::Lite), but they prove my (just made up) rule.
So what's my conclusion? I suppose if I wrote and supported one of these modules and you came to me with a request to separate some logical piece out, I'd take it with a grain of salt inversely proportional to the amount of work you're willing to put into it. Even if it's a good idea. There are an awful lot of good ideas floating around but no time for most of them.
Such work doesn't even have to be implementation code -- why not write up some dummy code as to how you want something to work? Frequently it's easier to work backwards from the result than try and create it from thin air. And of course everyone loves people who write documentation...
Related link: A defense of the NIH syndrome.
(I've now used up my quota for the words 'itch' and 'scratch' for the rest of the year.)
Chris
M-x auto-bs-mode
| [reply] |
You are talking about a problem that is as old as programming. In fact I expect that it
started just as soon as the second person learned how to cut code. In a nutshell, it comes
down to “How do you interface your code with someone else's code?”
There are days when I suspect that all code is just one kind of interface or another—
the rest of the time I'm sure of it! The examples you site demonstrate what I mean. You
look in vain for their tab A to slip into your slot B, only to find out that all they have
are round wooden pegs!
Most times when you hear cubie discussions about interfaces, it
is typically about what the user sees when he or she sits down to the application just
developed. But that is hardly the only interface we deal with, and the design of every
one of them bears directly on the problem you've noticed. We spend vast resources building
GUIs but virtually nothing on designing code to be used by other programmers.
Given the way most libraries, modules or what have you develops, it shouldn't come
as a surprise that the only code reuser who gets a custom fit, is the one who wrote the
code in the first place— pretty much what you would expect. In fact, one of the
great ironies in programmer land is that this problem is usually made worse, the better
the programmer who wrote it. The best programmers have a style of coding and if that
style doesn't match yours, problems ensue. Whatever, most of the time, someone
solves a problem (usually a difficult one, but not always) and the next thing you know
its available to all comers. Could be free, could cost money, but by whatever means, you
see it and shout hooray, 'cause you just know that it will solve the very problem that
has been racking your brains for low these many thirty hour days, etc., etc., etc.
And of course that is when you run into this little snag! You need low level functions,
they only supply high level. You don't have time to build it, but they have only given
you a zillion tiny pieces… Yadda, yadda, yadda, bitch, bitch, moan, moan. So—
how do you solve this problem? Well you don't really, you just sort of live with it. At
best, you can minimize things, at worst, do what you have to do. There are some things
that help:
- Treasure any code that you can use as is. In fact seek it out. Like the truth, it's
out there, you just have to wade through the 90% that won't do you much good in order to
find it.
- Second, you can increase your chances of successful merger by seeking code that
handles an entire problem domain, typically the more you can black box it, the easier
the interface.
- Learn the art of software triage. In this case, the pragmatic analysis of what will
cost more, writing new, or rewriting to fit.
- Moderate your expectations. There is not now, nor will there ever be, any such
thing as a free lunch.
- Don't let them grind you down! If the wheel doesn't fit, don't use it. If no
one has something that will work, make your own. It is not re-inventing the wheel, it
is just getting the job done.
Here is one last piece of anecdote, I probably own at least a dozen books on building
interfaces, but I've only found one1 on building software tools and libraries! hsm
1“Building Custom Software Tools and Libraries” by Martin Stitt, John Wiley & Sons,
New York, New York. 1993.Update: ISBN: 0471579149 see http://isbn.nu/0471579149/price
| [reply] |
Instead of looking for that ONE module - consider looking
for many modules and write some glue code to get the desired
result. Sounds easy, right? However, in my
frustration to find that ONE module, i wound up
rolling my own and submitting it to CPAN - go figure. . .
Now i am faced with a delima - creature feep. Example,
i received an email from a person who modified my module in
a rather cool way. Should i add the patch, or dismiss it
due to 'loose cohesion'?
i realize that i am now talking to myself - but i think you
just inspired me to decompose my module into smaller ones,
that way, i might just be able to incorporate this 'cool
idea' presented to me as a specialized subclass.
Thanks :)
jeffa | [reply] |
I've been reading a fair bit on this lately, so while
I'm certainly no expert, I do have a bunch of ideas
fresh in my head.
Seems to me that one good way to make code more reusable
is to make its different elements orthogonal to each other:
that is, as uncoupled as possible. So, to take your
CGI::FormBuilder example, you'd have one function
(or set of functions) for form generation, another for
validation, and another for session tracking, but they
wouldn't depend on each other: as long as you conformed to
the interface, you'd be able to validate input from a form
you wrote with a different package; session tracking
wouldn't depend on any magic in the form generation code;
and so on.
The problem is, this is hard to achieve! You have
to spend a lot of time thinking about the interfaces to your
code. Writing orthogonal code often means that communicaton
between two parts of the same module is more difficult than
it would be if you could only share this one little bit of
data... but that way lies madness, tight coupling, and
endless hours of frustration for anyone who doesn't want to
solve the exact problem you had in mind. I find it's useful
to design interfaces from the perspective of a user who only
wants to use the function you're writing: "I already have a
form generator, I just want to do session tracking".
(The problem with that approach is that the resulting
code can get disjointed and generally inconsistent. Oh
well. If I had all the answers, I'd be making tons of money
as a software design consultant.)
An excellent example of solid, orthogonal library design
is the ccMath library. (It's ANSI C, not Perl,
but the same principles hold.) I haven't worked with every
part of it, but what I have worked with has been
beautiful. No setup code, no gnarly data types, just call
the function you need. And two books you might want to look
at (in addition to the others already mentioned) are The
Pragmatic Programmer (Hunt & Thomas, Addison Wesley) and
The Practice of Programming (Kernighan & Pike,
Addison Wesley).
--
:wq
| [reply] |
| [reply] |