"When I am working on a problem I never think about beauty. I only think about how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong. " - Buckminster Fuller (1895-1983)
That quote is so true for my programming style, and it's what distinguishes the "used for 10 minute hacks" from the "publish it in a column code".

I can't tell you the number of times I've whipped out some snippet for public consumption, then sat back and stared at it for somewhere between 10 minutes and 10 hours, simply because it wasn't elegant. (So if you think the code you see is weird, you should have seen the rejects! {grin})

It makes me mad when I have to use the same expression in two places, for example. There's just something wrong about that. Or when it looks like it'll be fragile to changes, or not very reusable, or has too many global variables. It just looks wrong.

Of course, I have deadlines which I'm always up against, so I publish what I've got occasionally, but you'll find me using phrases like "sorry this looks so ugly". Often, after I see the code in print a few months later, I'll go "doh! I could have done XYZ", because I still work on it in my head. It's why I've revisited that link checking problem over and over again. I am still not satisfied at how ugly the logic is in the middle of those, or how hard it is to do things in parallel. But each time I hack out a new version, I'm more and more proud of the result.

That's probably one of my objections to objects for small programs. It seems inelegant, making me write too much code to be done in what I can do tighter. So my rule is "if you don't write 1000 lines of code in your program, and you're not subclassing an existing class, don't use objects!". And that upsets some of the "OO for everything" crowd, but Perl is already a hybrid (part-OO) language, so get over it. {grin}

And back to elegance: each part of a program should do one thing well. Very well, in fact. I chunk the subroutines adding whitespace for paragraph breaks. I try to introduce lexicals as I need them, and then don't let their scope go more than 10 or 15 lines. In a recent experiment, I wrote the entire top-level code as Perl pseudo-code, invoking clearly-named subroutines for each of the steps of the algorithm, and then implemented that, but then stared at the code for a full day, agonizing over the fact that the same thing appeared in a couple of the steps. Here... take a look:

{ ## main loop if (cache_is_good()) { show_cache_and_exit("current"); } if (cache_is_stale()) { if (i_am_the_writer()) { if (i_can_fork()) { if (i_am_the_parent()) { show_cache_and_exit("stale"); } ## child does: be_a_child(); update_cache(); exit 0; } ## cannot fork, so it's up to me update_cache(); show_cache_and_exit("current"); } ## I'm not the writer, so show old cache show_cache_and_exit("stale"); } ## cache is dead if (i_am_the_writer()) { update_cache(); show_cache_and_exit("current"); } ## we cannot do anything about a bad cache, so retry close_cache(); sleep 5; redo; }
See, you can probably see the whole algorithm, self described, right here. But I agonized over the fact that some of those steps are duplicated in a way, but we get to them because of different conditions. (This is my next Linux Magazine column, but it won't be online for a few months, as usual.) I tried rewriting it, changing the order of testing for some of the conditions, but it got only messier.

So after a day, this is the main code for my program, followed by 100 lines of code to implement the subroutines. And even after I had coded them, I rearranged them so that the subroutines that shared the same global data lived in their own block so the globals could disappear. This even helped me explain the program easier, and I know it'll be easier to maintain.

And when I complain about code posted here in the Monestary, it's these ideals that I'm holding the code against. I'm sorry if I sound annoying about them sometimes. It's just that I view programming as an art, not just a hack.

Whew. Long post. Comments?

-- Randal L. Schwartz, Perl hacker


In reply to On elegant coding... by merlyn
in thread Just thinking ... by toadi

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.