Of course, of course, TIMTOWTDI is the glory of perl, and I am no heretic. But some times, in the dark before the dawn, I confess I find myself wishing there was Only One Way To Do It.

To take a trivial example. I output a guzillion on-the-fly pages to users, requesting info or prompting to action. Each one comes with a memo-style header giving the user's name and other relevant detail, just so everyone's sure we're all singing from the same hymn sheet. Up to now I output this with
use CGI; use HTML:Template; # .. then initialise $q and get input so we know what to do sub Send_Header { my $header_tmpl = HTML::Template->new( filename => 'header.tmpl' ); $header_tmpl->param( header => shift, to => shift, date => substr(scalar gmtime time, 0, 10), subject => shift, ); print $header_tmpl->output(); } print $q->header(); print $q->start_html( -title => $title, -style => {'src' => '../styles/main.css'}, ); Send_Header($header,$user,$subject) # rest of message goes here
Which works fine. Then it occurred to me, as it might to anybody, that I could just as well put the <TITLE> and <STYLE> in the template. And that would work fine too. And doubtless by the time you've read this far you've thought of three other ways I could do the same thing, and they'd all work fine too.

This goes on all the time, and I'm not sure what to do about it. Sometimes one way really IS better than another, but even then the effort you go to in order to figure out WHICH is the best way probably means you were better off going with your first guess. Often, though, there are lots of different ways all of which are equally o.k.

And on occasions like that, I feel a bit like the donkey in the fable who starved to death between two piles of hay because he couldn't make up his mind which to eat.

<RAMBLING TYPE="PHILSOPHICAL">

I suppose this is the problem of our age in microcosm - we all have huge choices that our grandparents couldn't have dreamed of, and lots of us spend inordinate amounts of time trying to figure out which to do, rather than just doing it. As Sartre says (and I must say I think he mostly talks a load of nonsense, but this one acutely captures a psychological truth) Freedom Is Necessity. Lots of choices can be a kind of tyranny. Of course, one just has to have the gumption to turn the situation round, make the choice, and be doubly free. But in practice, it's quite hard work. And on a bad day, one longs for everything to be simple. If there were only one thing to do, one would feel completely free to do it.

</RAMBLING>

So in perl terms, for me it's as much a psychological as a technical problem. As I get better at this I'll be able to tell, and tell quickly, if there really is one way that's better than the others. But where there isn't, one's always going to need to make an existential leap and choose one rather than the other and move on. And for a perfectionist, this can be a difficult manoeuvre.

Maybe it's just me... but if not, I would be most interested to know whether and how other monks do this. When there's more than one way to do it, how do you decide how to do it?

§ George Sherston

Replies are listed 'Best First'.
Re (tilly) 1: Too Many Ways To Do It
by tilly (Archbishop) on Sep 19, 2001 at 16:26 UTC
    It is the mark of a bad programmer to not spend enough time considering their alternatives, and how they want to do things.

    A really bad programmer may hear a problem and start working on it before even having heard the full problem through.

    And it isn't Perl that is at fault. Every language will present you with choices, and the tradeoffs are not always obvious. I personally learn about the tradeoffs from sites like this, books, conversations with other people, and so on.

    BTW a random tip. I find it hard glancing at your code to see what arguments your function accepts in what order. That is why most people put function processing into its own section. Consider the following slightly modified version to see what I mean:

    sub Send_Header { my %passed_args; @passed_args{'header', 'to', 'subject'} = @_; my $header_tmpl = HTML::Template->new( filename => 'header.tmpl' ); $header_tmpl->param( %passed_args, date => substr(scalar gmtime time, 0, 10), ); print $header_tmpl->output(); }
    Isn't it easier there to glance at the function and see how it is supposed to be used? Now personally I would suggest putting everything in the template constructor if possible. Aim for having as few elements of control as possible. If you can do that then there is no need to bother naming temporaries:
    sub Send_Header { my %passed_args; @passed_args{'header', 'to', 'subject'} = @_; print HTML::Template->new( filename => 'header.tmpl', date => substr(scalar gmtime time, 0, 10), %passed_args, )->output(); }
    That method of chained method calls can be hard to read if you are not used to it, but think of it as being like a pipeline and you won't go too far wrong. Also it would be nicer if there wasn't a mix between the functionally written print, and the chain, but I don't find it too confusing.

    And I would personally prefer to see a custom written date formatting function rather than the inlined version of gmtime which someone has to run to see what it does...

    And so it goes...

Re: Too Many Ways To Do It
by stefan k (Curate) on Sep 19, 2001 at 16:20 UTC
    unless(i_got_much_time()) { take_the_first_guess(); } else { unless(i_am_performance_sensitive()) { if(rand < 50 || i_am_in_a_strange_mood()) { @solutions = think_about_other_solutions(max => 3); pick_one_from @solutions; } else { take_first_guess(); } } else { # pathological case: much time and performance needed really_start_thinking_and_try_to_find_best(); } }
    ;-)

    Obviously this is a very pragmatic approach, but that's how I usually do it in perl.

    Regards... Stefan
    you begin bashing the string with a +42 regexp of confusion

"Get the Job Done" (GeJDo)
by dragonchild (Archbishop) on Sep 19, 2001 at 16:38 UTC
    The issue of "best" is very deceptive. Best how? I've said this in a number of nodes, but I'm going to say it here all laid out.

    The best language when it comes to CPU and RAM usage is machine language. You cannot do better than machine language. At all. No way. The best compiler will only match the machine language implementation, and usually not even come close.

    However, development time in machine language is extremely slow. Like, slower than that. And, maintenance is even harder. This is why we use higher-generation languages.

    Now, every 3+G language has tradeoffs. Each language's syntax lends itself to certain applications. FORTRAN is excellent for engineering/math. COBOL is excellent for business apps. Haskell for functional, etc. In addition, different compilers do different things well. You can compile the same C program with two compilers and one will have better RAM, but worse CPU. The other will be reversed.

    Perl, that 4G language we all know and love, has been optimized for development time. Now, what does that mean?

    It means that no matter how I think about it, I can get a functional program that does what I want it to do in a reasonable amount of time.

    • Does it mean that I use RAM most efficiently? Nope.
    • Does it mean that I use CPU most efficiently? Nope.
    • Does it mean that I built it so that I could maintain it easily? Nope.
    It means that I can write one-offs quickly and efficiently and "Get The Job Done". (GeJDo? Maybe GAJD for Get A Job Done? I dunno.) Remember that human time is the most expensive part of a development effort.

    Does this mean that Perl cannot do all the things other languages do? Yes, it can ... and "Well Enough". Perl is, as we all know, a RAM hog. It can also be a CPU hog. This is part of the tradeoff for having lightning-fast development time.

    Now, what does this all mean?

    It means that "Good Enough" should be your mantra. You can always optimize. You can always rewrite your thing in machine code, if you really wanted to. However, you have to determine when the gains made in runtime performance are not worth the value of the (re)development time needed to achieve those gains. At that point, you have hit diminishing returns, and should probably stop.

    If your program works, it doesn't matter if the template is perfect or if your for-loops are optimized or whatever. Are you going to reuse the template? If not, then leave it alone. If you are and the rewrite would help you when you use it again, then go ahead and rewrite it. Otherwise, leave it alone.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      The best language when it comes to CPU and RAM usage is machine language. You cannot do better than machine language. At all. No way. The best compiler will only match the machine language implementation, and usually not even come close.

      there's actually a lot of debate about this point. unless you're a really, really good assembly programmer, a mature compiler working with well written high-level code will most likely produce faster, more efficient assembly than you can. a good compiler benefits from the years of knowledge and experience of its authors. this means that it knows every trick that they know. it knows the chip inside and out and can make much more sophisticated counter-intuitive optimizations around obscure side-effects of infrequently used instructions. compilers have less of an advantage on RISC architectures than they do on more advanced chips with hundreds of instructions; many more than most humans can hope to fully understand.

      of course, if you write bad high-level code, the compiler will happily produce bad assembly code.

      and assembly still can't be beat for code size. that and its direct access to the hardware are the reasons people still do use it.

      its fun though and will teach you a great deal about computers that you just won't learn from coding high-level languages. you haven't lived till you've spent over 24 hours straight debugging Z-80 assembly.

      anyway, i agree with your message though. TIMTOWTDI applies outside perl too. sometimes one of the ways to do it is a different language.

      anders pearson

        The last time I used assembly language was a one-line inline asm opcode to call the RDTSC instruction on X86.

        The last significant amount of asm I wrote was a function to convert UTF-16 to UTF-8. I was inspired by a comment in the reference implementation saying "I wish there was a better way to do this" where there is a bunch of if/else chains to test how many leading 1 bits are in a byte. Well, the CPU has an instruction for that. Then, it proved easier just to write it all in asm than to interface a helper function. After all, its work is to push bits around, something asm is good at.

        So, instructions that are not modeled in your high-level language is a good reason to dig to asm.

        —John

Re: Too Many Ways To Do It
by Masem (Monsignor) on Sep 19, 2001 at 16:42 UTC
    I'll give you one hint that, while TIMTOWTDI, this way below is the right way :-). Namely, you create the HTML::Template every single time that you call Send_Header. Now, if you're not using mod_perl (wha..?!), this isn't really a problem, but if you are, you should create the HTML::Template for the header once for each server thread that you start. Namely that this:
    sub Send_Header { my $header_tmpl = HTML::Template->new( filename => 'header.tmpl' ); $header_tmpl->param(...); ...
    is not as good as:
    my $PACKAGE::header_tmpl = HTML::Template->new( filename => 'header.tmpl'); ... sub Send_Header { $PACKAGE::header_tmpl->param(...); ... }
    since in the latter version, you only create the tmpl variable once. I'm not sure how cache'ing works in HTML::Template, for but Template Toolkit 2, for example, this can be very important; if it only has to cache once, that's a significant CPU savings.

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    It's not what you know, but knowing how to find it if you don't know that's important

Re: Too Many Ways To Do It
by perrin (Chancellor) on Sep 19, 2001 at 19:29 UTC
    I agree that TMTOWTDI can be problematic for newbies, but the issue you're talking about here is language-independent. You would have these kinds of questions if you were programming in C++ or Python or Java as well. In general, I think it's this "am I doing it right?" feeling that causes developers to use commercial tools like ASP so often: they tell you how to do it, and you just fill in the blanks! But the direction you're going is better, because ultimately your experience will lead to knowledge about what works and confidence in your methods to a degree that people using black box software like ASP can't hope for.
      My experience of programming with other languages could be written on the back of a postage stamp and still leave room for a shopping list... so I guess this IS a general problem. It's a GOOD problem, of course. I mean, if you have a passport you have the PROBLEM of deciding what other countries to visit. I'd be very interested to know how monks solve this problem. My method is to burrow deeper and deeper into all the different ways of doing it and then jump up from my desk, run down to the kitchen and put on a jug of espresso, come back to my desk and go ahead with whatever was the last solution I came up with. I feel this might be open to optimsation...

      FWIW I'd think perl might even be a bit tricksier than other languages in this way, because not only do you have all the different core Ways To Do It, but you've also got CPAN. I mean, how 'nhell do you ever make a rational choice of templating module?

      § George Sherston
        1. Find a problem you want to solve
        2. Implement solution A
        3. Walk away, as the problem is solved
        4. 6 months later, run into problem again, but in a different context
        5. Implement solution B, cause you're 6 months better at Perl and wince whenever you remember solution A
        6. Repeat 4 or 5 times, wincing less and less cause solution E is only marginally better than solution D
        7. Log onto PM and realize that others have solution M.
        8. Cry for a while because it's so elegant and simple
        9. Rewrite 3 years of code to use solution M
        10. Realize you didn't understand solution M at all
        11. Cry for a longer while cause you just introduced 10 new bugs and hadn't backed up your code
        12. Rewrite again, using solution F, which takes what little you understand of solution M and grafts it onto solution E
        13. Read PM again in 6 months and realize you not only do understand solution M, but found a better way!
        14. Dance around your cube for an even longer while (gotta make up for all that crying!)
        15. Post solution N and get 100 XP for being cool
        16. Delete 3.5 years of code cause it's all worthless crap that a module you just wrote with solution N does it all, and more
        17. Go on with your life.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        I mean, how 'nhell do you ever make a rational choice of templating module?

        Well, you could start by reading my guide.

Re: Too Many Ways To Do It
by MZSanford (Curate) on Sep 20, 2001 at 12:46 UTC
    And interesting idea, that perl is a metaphor for the decline of western society ... i rather like it :-)
    But, since this is philsophical, there is no right/left/wrong, only opinion. In my opinion, as un-humble as it may be, the choices are what makes Perl great. As i have many time looked at my old code and thought "what in the hell was i thinkning ?", i do prefer that to spending years on a language and learning only that i can change the syntax the smallest bit with no noticable optimization. In short, the choices make for some horrible code, but they give me a sence of style with the way i do things .... without it, the decline of western society could be blamed on all writing the same code. None of us will ever know, and sometime, thats just fine.
    my own worst enemy
    -- MZSanford