Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Code Maintainability

by mpeever (Friar)
on Dec 03, 2008 at 22:24 UTC ( #727817=perlmeditation: print w/ replies, xml ) Need Help??

Code Maintainability is a hot topic: I've been mulling over the issue(s) of code maintainability and code density for several years, and I thought it might be useful to lay out some of my conclusions.

I've written and maintained code (mine and others') for several years, professionally and for my own personal use. I've worked in Fortran, Python, Scheme, Perl, Java, and Ruby; to name just a few. I made the most money with Java, but I had the most fun with Scheme. Perl comes in a close second on the fun scale. Sometimes I've known the people whose code I've maintained, sometimes I haven't.

The problem of subjectivity

Code maintainability is fairly subjective. What one person considers maintainable, another considers bloated and a third considers cryptic. This suggests at the outset that "maintainability" can never be a true standard, and it's probably an elusive goal. It might be a worthy goal, but I'd suggest maintainability is really best achieved when it's not the primary aim. In other words, improving the clarity and brevity of code will result in much more maintainability than attempting to make it maintainable.

Double-blind assumptions.

The bottom-line problem from my perspective is, coders have been told to write maintainable code, and they've been reminded that they can't tell who's going to have to maintain it. Thus, they have largely opted to write code as simply as possible: code that's inefficient and bloated, "but easy to understand". What they actually produce is a brain-dead code no intelligent maintainer wants to touch... code so ugly the maintainers conclude the original developers were idiots.

It's a double-blind scenario: the coder and subsequent maintainers all assume the worst about one another, and allow that to tempt them to write code that's uglier and less maintainable than their initial instinct would have been to write. Thus, the lofty ideal of "maintainability" is used to excuse all manner of coding abominations.

Bloated code is ugly

I have seen a lot of code in the Java world that looks like this:

Something something = new Something(); something.setField1(value1); something.setField2(value2); something.setField3(value3); something.doSomething();
This is considered good style by many javanistas, but working in code bases like this will rot your soul. It's not only bloated, it's ugly. This would be much more beautiful (or at least less ugly):
Something something = new Something(value1, value2, value3); something.doSomething();
But if you suggest that to people who write this stuff, they'll make noises about how unmaintainable the second example is, because convenience constructors are hard to understand. Are they? If your maintainer has trouble understanding a convenience constructor, you need to look for a new maintainer and a new hiring manager.

See, verbose code is not only bloated: it's ugly. And ugly code is harder to maintain: it's harder to parse, harder to care about, and harder to force yourself to work on. Maintainability is subjective, so let me make a subjective point: ugly code makes me want to find another task to do. Ugly code is too great a temptation to procrastination.

Obfuscated code is ugly

Obfuscated code is impressive, but it's ugly. Seeing how closely you can make your Perl resemble line noise is interesting---and I greatly admire some of the monks solely for their ability to make random characters do cool stuff---but it has no place in code you expect others to run.

Try it: try to maintain some of the obfuscated code on this site. You'll throw in the towel in no time, partly because it's ugly. Maybe even mainly because it's ugly.

Perl people have a reputation for writing ugly code, and it's well-deserved. But our fascination with seeing how ungodly a mess the Perl interpreter can unravel has actually damaged our cause. Nobody wants to work on code that looks like a comic character cursing. You don't, I don't. Not for real, not for a living.

Good comments don't make up for bad code.

I'm becoming convinced that comments in code are close to useless. The first and greatest problem with comments is that they don't alter the code's behaviour. When your code's wrong, you can tell from its (wrong) behaviour. But when your comments are wrong, you can only tell by comparing them to the code. And if you're parsing the code to test the comments, then the comments are basically worthless: you're having to read the code as though they aren't there anyway.

This is perhaps not much of a problem unless the code has changed and the comments have not (which happens all the time), but how can you tell that's not what happened? In the real world, a maintainer has no choice but to assume the comments are wrong. Trusting comments is a very risky course of action: risky enough that I'm almost convinced of the sed -e '/^(\s+)?#/d' technique others espouse.

According to Tilton: "Every comment is a place the code could be better."

Of course comments are good for some things: as a maintainer I find it's easy to figure out what code does, and hard to figure out what it's supposed to do. I've more than once asked the original programmer what he was trying to accomplish: I find the context for a piece of code is what's more often lacking. I love to see comments that say things like:

# We need to ensure that the widget press is fully # stopped before we disconnect the syrup tanks, because # the nozzles can leak syrup for at least 30 seconds # after the hoses are disconnected.
I know what the code does, my concern is figuring out why it does it. That's precisely where comments should be used.

Comments that simply narrate the code are close to useless. Comments that explain the rationale of some code can be very helpful. In my experience, there is much more of the former going on than the latter.

Beautiful code is more maintainable

Beautiful code is generally easy to maintain. I find the best Perl reads a whole lot like English: the closer to English prose you can get your Perl, the easier it is for the next person to maintain it. When you accomplish prose-like Perl, you essentially write comments that are your code. If your comments are your code, and your code is your comments; maintenance is a snap.

Perl has several features that make prose-like code easier. One of my favourites is unless. if not is ugly in any language: unless makes that flow so much better.

I also prefer to test predicates at the end of a line: it makes it read more like a conversation. For example:

if ($DEBUG) { print STDERR "Debug: some value"; }
is pretty clear, but if we re-write that one line, it becomes more of a conversation with the maintainer:
print STDERR "Debug: some value" if $DEBUG;
Notice how well it flows in English: do this if that is very much what we say to one another all day in the real world. If this that is very much how one expects a computer to talk, not a real person.

But being prose-like is not the only test of beauty. Accomplishing a lot with very few well-chosen commands is elegant: that's an important part of beauty. Using well-named variables is very beautiful. Initialising variables when they are declared is much more aesthetic than declaring something and using it later. Using constants to represent constants and variables to represent varaiables: that's graceful. Carefully building scopes to subtly influence the meaning of code: that's just flat-out gorgeous.

An aesthetic sense of code accomplishes more than self-flagellation over maintainability. Code you're proud of, code that is genuinely appealing, is code your maintainer will enjoy working on. That's really the defining characterstic of maintainability.

Brevity and tact are the soul of beauty

All other things being equal, shorter code is better. I was discussing a piece of legacy Perl with a co-worker the other day, who was defending it's length and incredible verbosity on the grounds that "it should only do one thing per line". That's a cute theory, but it's a real pain to try and maintain long pieces of code. If you take 15 lines to say what can be said in 10, then you've squandered 5 lines' worth of screen real estate. More lines of code take more screen real estate, require more time to read, and are harder to scroll through. Obviously there is such thing as code that's too dense, but fluffy, airy, light-as-a-feather density code is agony for a competent maintainer. Don't write something like this:

foreach my $line (@lines) { print STDERR "$line\n;" }
when you can use something like:
print STDERR join("\n", @lines), "\n";
Of course, this is even better, if it's appropriate for your purposes:
print STDERR Dumper \@lines;

Always look for a shorter way to express the same behaviour. Every line you add gratuitously is a line your maintainer has to read, parse, understand, and potentially alter. If you're adding them for some obscure, esoteric ethic; then you're making your code less maintainable.

Is there such a thing as too short? Yes, there is... but my experience has been that my skill level generally grows to catch up with dense code: my frustration level rarely diminishes with bloat.

A certain competence level must be assumed for the maintainer.

I find it insulting as a frequent code maintainer, that people equate "maintainable" with "obvious and basic, even for a total idiot." Don't assume the maintainer is not as smart as you are: write code you want to maintain, and leave it at that. If the maintainer can't read decent code, then let Natural Selection take its course: eventually someone competent will touch your code, and they'll thank you for not making them rewrite it all.

It's ironic that the quest for "maintainability" has prompted a lot of people to write code that's so idiot-proof it's hard to read. There is a point of diminishing returns in code clarity efforts: and there's a point where the coder's effort to write "maintainable" code will actually make it much worse for the poor schmuck who has to actually maintain it.

I've learned a lot of Perl from maintaining other people's code. Code that makes the maintainer reach for the Camel now and then is not a bad thing. A decent maintainer will thank you for it.

WWHD?

I think part of the solution can be summed up in one phrase: What Would Howard Roark Do? Roark would rather starve than design an "ugly" building. If you apply that idea to your code, you'll find it's much more maintainable than if you'd set out to make it so. Write code you can be proud of, code you want to email to your friends to boast about. That's code that will prove to be maintainable in the long run. If your friends look at it and say "wow," then it's not hard to read, and your maintainer won't have trouble either.

Write code that's short, elegant, and beautiful. Write code that uses more of Perl's vast vocabulary than a few loop constructs and some declarations. Try to assemble collections when you declare them (using map and grep), rather than declaring a variable without initiaizing it. Uninitialized variables are... well, ugly.

Look at return values, and don't call an operator solely for its side-effects when it's designed to return a value. Think in terms of immutable variables: they're implicitly thread-safe and easier to debug.

Learn the language. Don't be satisfied with knowing enough Perl to get by. Everyone has to start there, but that's not a good excuse for not developing further. Perl is a vast language with a zillion keywords and unimaginable number of permutations of solutions. Don't stop learning: use every Perl problem as an opportunity to learn just a little more Perl. It took me years to get around to learning map, and now I can't imagine writing Perl without it. Who knows what cool Perl features are waiting for me to discover them? A wider vocabulary means more beautiful code: that's more maintainable code.

Comment on Code Maintainability
Select or Download Code
Re: Code Maintainability
by kyle (Abbot) on Dec 03, 2008 at 23:01 UTC

    Thanks for your meditation. You've given me some food for thought.

    I like statement modifiers for short statements.

    upchuck() if ! $healthy;

    For a much longer statement, I find the modifier gets lost, and it gets harder to understand what's going on.

    Exception::Of::Doom->throw( error => 'Detailed error messages are impo +rtant, especially when this error happens' ) if $oops;

    I think there are plenty of times—perhaps even most times—that I'd rather read "if not" rather than "unless". I've seen programmers use "unless" almost universally for error conditions, and that seems like a pretty good convention, but even then I think it depends somewhat on what's in the condition.

    upchuck() unless $healthy; # doesn't sound right error() unless happiness_ensues(); # better?

    The other thing about statement modifiers is they make it harder to add stuff to the condition.

    if ( ! $healthy ) { upchuck(); die; }

    If it were written as three lines to begin with, I wouldn't have to go through so much trouble to add the one extra action.

    Sometimes "maintainability" is about "editability" rather than "readability". Yes, statement modifiers allow you to get more on the screen, and it may flow more naturally before your eyes. Now insert some debugging statements. When it barfs on line 123, is that the stuff in the condition, or in the condition's result?

    I don't always write "one thing per line", but I see its advantages.

    As an aside, this looks clumsy to me:

    print STDERR join("\n", @lines), "\n";

    I've sometimes written that as:

    print STDERR map { "$_\n" } @lines;

      I like statement modifiers at the end for simple things like an early return, or throwing an exception. To handle longer lines I use indention:

      die 'Detailed error messages are important, especially when this error + happens' if $oops;

      But with the long exception you showed I might do:

      Exception::Of::Doom->throw( error => 'Detailed error messages are important, especially when t +his error happens', ) if $oops;

      I often hear that switching the order is difficult and that it is a good reason not to use the trailing conditional. In practice, I haven't found that switching the conditional around to be that onerous. A good text editor makes it easy. If switching was so hard you would see more of this:

      do { turn_green(); throw_up(); die "Ach, food poisoning"; ) if $ptomaine;


      TGI says moo

      The other thing about statement modifiers is they make it harder to add stuff to the condition. (...)

      If it were written as three lines to begin with, I wouldn't have to go through so much trouble to add the one extra action.

      Sometimes "maintainability" is about "editability" rather than "readability".

      Editability is about using a decent editor. For example, in Emacs you can convert between block "if" and statement-modifier "if" with a single command. If your editor can't do that, then I would argue it's your editor's problem...

      As an aside, this looks clumsy to me:

      print STDERR join("\n", @lines), "\n";

      I've sometimes written that as:

      print STDERR map { "$_\n" } @lines;

      I wouldn't use either form; they both get too far away from mpeever's ideal, which I share, of code that reads like English.

      If you want to print a bunch of lines to STDERR, I personally believe it's best to say "I want to print a bunch of lines", not "I want to build a string by joining a bunch of lines with newline characters, and then print that" or "I want to map a bunch of lines to a new array where they're terminated with newline characters, and then print that". In other words, I'd write:

      print STDERR "$_\n" for @lines;

      or, better still,

      say STDERR $_ for @lines;

      if you're lucky enough to have an up-to-date Perl, which of course many of us don't, in the workplace.

        In other words, I'd write:
        print STDERR "$_\n" for @lines;
        I think you're right: that's the clear winner. It's much less cryptic, and doesn't seem to offer any real downsides.

Re: Code Maintainability
by lima1 (Curate) on Dec 04, 2008 at 03:17 UTC
    This is kind of trivial, but I like it when the main file is basically a flowchart of the program. So many people write this huge main functions. Or often the pattern happy smart ass fraction - even worse in most cases - this tiny ones. Which means I also like it when I can read the program like English, but I think more about reading function names. How people actually implement the functions, where they place the if-statement for example, is a matter of style and that can often be controlled with Perl::Critic. Structure is more important for maintainability, more precisely structure you can easily see and follow.
Re: Code Maintainability
by graff (Chancellor) on Dec 04, 2008 at 03:45 UTC
    Lot's of valuable considerations -- from the OP and the first reply as well. IMO, these are the key points:
    mpeever: improving the clarity and brevity of code will result in much more maintainability than attempting to make it maintainable.

    kyle: Sometimes "maintainability" is about "editability" rather than "readability".

    By far the worst PITA for any code maintainer (whether working on one's own code or someone else's) is finding that a particular bug fix or enhancement entails making a particular change multiple times in multiple places. Resisting the false economy of copy/paste programming is a discipline that is forsaken all too often by coders in all languages.

    When you take the time to actually analyze the task at hand (many of us hold the "official" job title of "programmer/analyst, and there's a reason for that), there is virtually no need for more than one instance of a given literal string, "if" condition or computation/assignment statement. People who repeatedly copy a sequence of lines and make minor changes in each copy -- instead of creating a subroutine with parameters to handle the variations -- should be employed as "data-entry technicians" rather than programmers.

    As for the proper role of comments, I agree with this point completely:

    Of course comments are good for some things: as a maintainer I find it's easy to figure out what code does, and hard to figure out what it's supposed to do.

    My personal mantra is: no source code file that will require maintenance should ever be written before a spec is written to explain its purpose. My personal habit for obeying this law is to start each perl file with a standard POD template (NAME, SYNOPSIS, DESCRIPTION), and this gets fleshed out with a good-enough (clear and reasonably detailed) explanation of what it's for and how it's used, before writing any code beyond "use strict;" (which happens to be part of the template). In some cases, I end up with more lines of POD (and take more time to write that) than lines of code.

    This is usually so that I'll understand the file six months later, but it also helps whenever someone else asks something like "what was the spec for that procedure we did six months ago?" The POD is the spec.

Re: Code Maintainability
by GrandFather (Cardinal) on Dec 04, 2008 at 04:21 UTC

    Very nice, especially as you seem to have copied it straight out of my (mental) guide book (how did you manage that!).

    Two related area you've not covered are the question of line length and nesting. One might think that long lines are a good idea now that we have wide screen monitors which can easily display several hundred characters on a line - more code per line, yay! Well, think again. Part of the art of structuring code so that it is maintainable is breaking it up into comprehensible units. Like long sentences, long lines are hard to comprehend. Deeply nested code is hard to comprehend.

    Historically 80 character lines were a hard limit. In practice 80 character lines is a very satisfactory length. It's long enough to express as much complexity as is generally required and short enough to limit the complexity of reasonable code to a chunk that can be teased apart and understood without resort to taking off shoes and socks to count brackets. 80 character lines also means that with most editors it's easy to have two edit windows side by side, and that is often very useful.

    Nesting is related to line length in as much as the deeper you nest control structures (if statements and loops) the less room you have on the line to put interesting stuff. It's also related in the sense of being able to comprehend the code. With deeply nested code, especially with nested conditional code, it can be very difficult to figure out when a particular line or block is executed.

    A technique that can help avoid nesting is to take advantage of early exits from sub and loops. Very often the changing the sense of a test allows a short block containing a little code that handles a special case and ends with a return, next or last. The if is then followed by the general case code without needing extra nesting. That gives a double benefit - you avoid nesting and it's much easier to identify the different case code and how you get there.


    Perl's payment curve coincides with its learning curve.
Re: Code Maintainability
by moritz (Cardinal) on Dec 04, 2008 at 08:38 UTC
    I found your example of the constructor quite intriguing. Let me re-write that as a concrete example of generating a geometric shape:
    my $circle = Circle->new(4.5, 2.3, 2.2, 1)

    Do you know which parameter does what? No, of course not, you'd have to memorize the order of parameters, which nobody can or want for larger libraries.

    Consider this in contrast:

    my $circle = Circle->new(); $circle->set_radius(4.5); $circle->set_origin(2.3, 2.2); $circle->set_visibility(1);

    Although the second version is bloated, it's much more readable. So in terms of maintainability, it wins. IMHO. I don't like it, but it's easier to understand, and at least in terms of readability it also scales to more arguments.

    But wait - can't we do better? The repeated part $circle->set_ is ugly, and repetition is the enemy of good programming. Consider this instead:

    my $circle = Circle->new( radius => 4.5, origin => [2.3, 2.2], visibility => 1, );

    That's not shorter than the second example, but much less bloated, because of less repetition. But it's still as readable, and it scales well (ie even if you have eight or ten arguments to new() you can see what it does).

    (If you are a Perl 6 fan boy like me, you'll be pleased to learn that Perl 6 provides such constructors with named parameters by default. Of course they can be overwritten).

      Consider this instead:
      my $circle = Circle->new( radius => 4.5, origin => [2.3, 2.2], visibility => 1, );
      I agree that named parameters are a huge win. That's a bit of Lisp and PL/SQSL I miss frequently in other languages.

      And frankly, without named parameters, it seems to me the convenience constructor debate really becomes a choice between the lesser of two evils. On the one hand we can be verbose, on the other we can be cryptic. I personally prefer cryptic to verbose: I expect a maintainer to look up parameters as he or she needs.

      But I return to my thesis: maintainability is a red herring. If we choose which idioms to use based on aesthetic value, we eliminate the problem. We both agree that a constructor taking a series of numbers is ugly. But I would argue that :

      my $capital = Capital -> new ("Canada", "Ottawa");
      Is obvious and very maintainable, even though it's conceptually the same pattern.

      My conclusion is that a sense of code aesthetics allows us to choose the best (or least evil) option on a case-by-case basis.

        Actually, I think it's more than just cryptic vs verbose. One of those examples has a serious logical flaw, and the other doesn't.

        my $circle = Circle->new(); # What is $circle now?! $circle->set_radius(4.5); # or now? $circle->set_origin(2.3, 2.2); $circle->set_visibility(1);

        See those comment I added? When you first create a circle object without any parameters, what is it, logically speaking? It has no radius and no origin, so it's more like a theoretical circle, but not representative of any real-world circle.

        After we set a radius, it starts to make sense, though maybe in our particular app circles always need an origin too.

        This dovetails with one of my newer mantras, which is that mutable state is evil. In the "pass everything to the constructor" version, we might be able to avoid (or at least limit) our mutators. If we're lucky, there's no need to change the radius of a circle, we can just make new ones with different radii. Avoiding mutable state greatly simplifies code. It makes APIs smaller, and makes reasoning about an application much simpler.

        Java, with it's regular pattern of "construct, set, and call", makes mutable state a given, and that's a terrible thing to do.

      I believe your second example (which is always the way i call methods and subs now) is something that is almost exclusive* to Perl because of the concept of lists. PHP can't even do this "out of the box" like Perl can, observe:

      my $circle = Circle->new( array( radius => 4.5, origin => array( 2.3, 2.2 ), visibility => 1 ) );
      That's right ... PHP methods do not accept a list of arguments -- you have to make your array and pass it to your method. Now, you can use named args in PHP but they are still positional, meaning that you can't pass the args in an arbitrary order. In Java you would need to first instantiate a new Hash object, fill in its values and then pass that to your object's constructor. Yuck!

      All of this just reinforces my belief that 9 out of 10 Perl haters only hate Perl because they just don't get it. I myself am no fan of Perl 6, but it is good to hear that named parameters are now default.

      *I haven't bothered to read up on it, but i'll wager $50 that Ruby and Python can handle this.

      UPDATE: Duh! Lisp! Thanks for setting me straight Porculus. :)

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      

        It's far from exclusive to Perl. You're right that Python can handle it; I don't know about Ruby, but there are plenty of other languages that do, the granddaddy of them all being Lisp.

        It doesn't require that things be based on lists of arguments, of course, though it helps (that's the way Lisp does it!), and it doesn't even require a dynamic language. For example, the completely static language O'Caml provides named arguments as a syntactic feature, with compile-time checking etc.

      I agree. You will probably spend twice as much time debugging, and later maintaining, your code then you will writing it (stolen from Perl Best Practices, or some book like that). So, it makes much more sense to optimize your code for later readability and ease of understanding (two or three months later when you don't have the whole thing in memory) then it does to optimize it for the initial ease of writing.

      Of course, one line is always quicker to read then five, so if you're sure you'll be able to quickly understand that one line instantly, at a glance, months later, then that one line will be the way to go.

      And that's the tradeoff, which will always evaluate differently for beginning, mid-level, and advanced Perl programmers.

      Jim

Re: Code Maintainability
by Anonymous Monk on Dec 04, 2008 at 12:02 UTC

    Even though I currently only write markup languages (starting to learn Perl lawlz), most of this makes good sense to me. I'm not a big fan of stuffing everything on one line just to do it, but if I can use shorthands for values I do. It's true, if someone can't read shorthands (esp if they are in the specs) then they shouldn't be reading it at all.

    The "wider vocaulary" part works too. It's part of "use the right tool for the job" as usually this means less hammering around to get the ill-fitting piece to do the job someone else should've been doing, and if you don't know what's possible, you'll find yourself using a screwdriver to hammer in nails more often.

    You know code is too bloated when you can clean it up, make it half the size it was and get exactly the same result with just as much readability as anything you would've written yourself.

    elegant!=obscure

Re: Code Maintainability
by webfiend (Vicar) on Dec 04, 2008 at 14:29 UTC

    I definitely agree that you should take advantage of Perl's rich syntax, even though I lean towards a verbose code style myself. The main issue I had with your meditation was about constructor arguments, and that was already addressed by Moritz.

    I'd still like to comment on the bit about debugging. I tend to shuffle any logic for debugging into a sub, and invoke that sub whenever I need something dumped:

    # Skipping boilerplate pragmas ... use constant DEBUG => 1; sub debug { if (DEBUG) { say STDERR (ref $_[0]) ? Dumper $_[0] : $_[0]; } } debug("Something is on fire"); debug([ qw(fire famine flood) ]);

    This way I can easily change what I mean when I say debug - print to STDERR, log to a file, dump to a database, summon the remote controlled sky writing airplane, whatever. It's really just another opportunity to avoid copy and paste coding.

Re: Code Maintainability
by jeffa (Chancellor) on Dec 04, 2008 at 16:23 UTC

    Wonderful stuff. :) I only have one gripe and that's with the following:

    if ($DEBUG) { print STDERR "Debug: some value"; } [download] is pretty clear, but if we re-write that one line, it becomes more of +a conversation with the maintainer: print STDERR "Debug: some value" if $DEBUG;

    I do agree that the second line reads like English ... but it doesn't scale well. Consider this:

    if ($DEBUG) { print STDERR "Debug: some value"; # some tempory line to debug our debuger ... # some other temp line ... }

    The difference is to never use one line for such if statements because sooner or later you are going to want to put another line in the block. Even if it's just temporary, you are going to have to rewrite the second line so you might as well accept that all if blocks will always take up at least 3 lines. I have adopted this practice for about a year now and it has served me very very well. YMMV naturally. Great mediation man! :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      if ($DEBUG) { print STDERR "Debug: some value"; # some tempory line to debug our debuger ... # some other temp line ... }
      I think that Perlers have a (probably appropriate) inclination against do blocks; but of course one can (as jkva points out below) have the multi-line cake and eat it too (or something):
      do { print STDERR "Debug: some value"; # some temporary line # some other temporary line } if $DEBUG;
      Of course, a trailing modifier after 17 lines of code isn't going to do anything for readability; but I think that do this; that if DEBUG is still reasonably English-like. As an added bonus, it's easy to transform a do-with-trailing-if to a leading if when the block gets too big and readability suffers.
Re: Code Maintainability
by johndageek (Hermit) on Dec 04, 2008 at 17:04 UTC
    Nice Meditation!

    My additional comments:

    Please be consistent. At least in a given program or series of programs. We all improve over time, please use those gains, but if you use variables like $companyName, or $company_name, or $co_nm please feel free to stick with approximately the same naming standard. This also applies to formatting and general ways of accomplishing given tasks like printing, calling subroutines and so on

    If you modify/maintain a program that uses a standard you HATE please make the choice re-write the whole thing based upon your standards (the boss will love your time sheet) or much more reasonably, use the existing ugly standard.

    I very much agree that many people believe that all programs should be written so an untrained person can step in and become a programmer this is wrong Wrong WRONG. Use the language effectively, as you say, use all of the power of the language skip using arcane little side effects as a method to accomplish anything in your program.

    Yes I have broken all of these rules, sometimes on purpose for fun like Obfu code. Other times I have broken the rules without thinking, and generally lived to regret it, or more than likely lived to regret the same problem in someone else's code.

    Always remember the basic rule : there is nothing so permanent as a temporary fix

    Enjoy!
    Dageek

Re: Code Maintainability
by doom (Deacon) on Dec 04, 2008 at 20:59 UTC

    I'm becoming convinced that comments in code are close to useless. The first and greatest problem with comments is that they don't alter the code's behaviour. When your code's wrong, you can tell from its (wrong) behaviour. But when your comments are wrong, you can only tell by comparing them to the code. And if you're parsing the code to test the comments, then the comments are basically worthless: you're having to read the code as though they aren't there anyway.

    Even a stale comment tells you something about the code -- you know immediately that someone made a change from the original version there, and they did it very quickly, without thinking it through (or else the comment would've been fixed, also).

    If you want to talk about code maintenance, revising comments (and documentation) is part of the job.

    And I'm sorry if this sounds rude, but it's based on experience: You really don't want to work with people who think their fabulous code is so beautiful it doesn't need comments anywhere.

      True, one wouldn't wish to work with people who think that. But I'd sure like to work with people who's code is so beautiful it doesn't need comments (at least not implementation comments - context comments are to be encouraged).


      Perl's payment curve coincides with its learning curve.
      No you don't know that about comments. Approximately one line in 10 that we initially write is wrong. This is true for both comments and code. The difference is that the mistakes in the code tend to get caught and fixed, while mistakes in comments do not. So a wrong comment does not indicate that there was a change, because it could have always been wrong.

      As for who I do and don't want to work with, I have had the displeasure of working with people who never comment, and of working with people who comment everything heavily. Of the two styles I far prefer no comments at all. The style that I personally like is very sparsely commented code that is written in such a way that the code itself stands as a comment.

      For more details I strongly recommend reading the old thread starting at Re (tilly) 2 (disagree): Another commenting question,. In that thread I discuss in detail a piece of code that I just wrote, the commenting decisions that I made, and the reasons for my deciding what to comment, where and when. I no longer hold to quite that style, these days I'm inclined to write longer variable names than I was back then, but I haven't changed views by that much.

        I've never had to work with one of the legendary "comment every line" types -- it could be they don't get hired at the kind of places I've worked.

        From skimming tilly's example here: [Text::xSV] I would summarize that he likes sparse, higher-level comments, but with very verbose error messages that actually function fairly well as substitutes for comments. At a glance it does seem that both variable names and sub names are a bit short, but then, they don't strike me as confusing. He also likes pod-at-the-bottom style which also comes recommended by Conway in his "Best Practices" (I'm a fan of interspersed-pod style, myself, but not so much that I'd insist it's the One True Way).

        By the way: if the main objection to comments is that they tend to diverge from the code, what does one do about those rather infrequently run error messages? Don't they, too, tend to diverge from the code? And what about the the "=item" lists buried down in the pod?

        Anyway, as it happens, I've written up a brief comment example: Re^5: Programming *is* much more than "just writing code". In summary: explaining a paragraph of code in english can speed skimming through the code, and hinting at how a line of code works can sometimes be a good idea.

Re: Code Maintainability
by tilly (Archbishop) on Dec 04, 2008 at 22:10 UTC
    A few random thoughts for you. The first is that maintainability is the result of an interaction between the programmer and the code.

    The second is that while you're right on the pitfalls of comments, you didn't say enough about how well-chosen variable and function names can serve some of the same purposes that people use comments for, in a much more maintainable way. For instance flags should be yes/no questions that the value is the answer to. And hash lookups linguistically should be read "of", name your hashes so that they will read nicely when you do.

Re: Code Maintainability
by ady (Deacon) on Dec 05, 2008 at 06:44 UTC
    Interesting discussion, but apart from (and above, really) the syntax (incl. comments) impact on semantics, I find that code design is of superior importance for maintainability; Consider design principles such as Separation of Concerns, Orthogonality, Extensibility, Testability (quote On-Writing-Maintainable-Code) :


    Best regards,
    Allan Dystrup
Re: Code Maintainability
by jkva (Chaplain) on Dec 05, 2008 at 07:35 UTC

    Very nice meditation!

    Since I noticed some discuss their debug flag techniques, I tend to do either

    my $DEBUG = 1; $DEBUG && print 'debugging mode';

    or

    my $DEBUG = 1; $DEBUG && do { print 'isn\'t'; print 'that something' }

    in case of blocks.

    Having $DEBUG in the start of the line immediately tells you there's debug related code coming through.
Re: Code Maintainability
by n3toy (Friar) on Dec 06, 2008 at 04:58 UTC
    Very good meditation indeed!

    Lots of good advice in the original post and the comments. I am currently reading Perl Best Practices so this meditation is very timely. Plus I like the Howard Roark reference. Trying to maintain any code from Peter Keating would definitely suck! Unless it was code Howard Roark wrote for him...
Re: Code Maintainability
by dws (Chancellor) on Dec 07, 2008 at 06:32 UTC

    Want to write maintainable code? Then learn the unit testing frameworks and use them.

    The act of writing tests against your code can flush out a lot of nonsense. The act of writing tests first, before you write production code, can flush a lot of nonsense out of your design.

    Having good tests improves the chances that whoever picks up the code next won't break something and not realized it. That's maintainability.

    Beautiful code but no tests? You're only halfway there.

Re: Code Maintainability
by sundialsvc4 (Abbot) on Dec 09, 2008 at 21:34 UTC

    Well, I do find that comments are extremely useful. They help me understand "what that damned fool was (not...) thinking when he wrote this awful code!" ... even though, of course, that "fool" was likely-as-not me!

    What a good comment tells me, that (Perl or otherwise) source-code cannot, is: the designer's intent. It serves as an introduction to the code, a way to point-out particulars about understanding it, a "running narrative" between the original writer and the (same or different) person who follows him/her.

    I never need a comment to tell me, "this is what this-or-that code block does." I can see that. What I need to know is: "what was running through your head when you wrote this?" "What's the not-so-obvious or easily forgotten aspect of this code that you'd really like to point out to me? What's the special breadcrumb that you'd like me to remember?"

    "Priceless."

      I can't help but agree with this. Going through some code that I wrote 2 years ago, I can easily see *what* it does, but I'm damn happy I used comments to explain *why* I chose to do certain things a certain way.


      Remember rule one...
Re: Code Maintainability
by wol (Hermit) on Dec 12, 2008 at 14:54 UTC
    OT...

    "What would Howard Roark do? Roark would rather starve than design an "ugly" building."

    Beauty is in the eye of the beholder. If he were hungry enough, then he might even lower himself to think of a building that looks like this.

    In case you're wondering, I'm on the second floor, and it's even worse from some other angles.

    --
    use JAPH;
    print JAPH::asString();

Re: Code Maintainability
by mikeraz (Friar) on Jan 06, 2011 at 17:01 UTC

    I also prefer to test predicates at the end of a line: it makes it read more like a conversation. For example:
    if ($DEBUG) { print STDERR "Debug: some value"; }
    is pretty clear, but if we re-write that one line, it becomes more of a conversation with the maintainer:
    print STDERR "Debug: some value" if $DEBUG;
    Notice how well it flows in English: do this if that is very much what we say to one another all day in the real world. If this that is very much how one expects a computer to talk, not a real person.

    Really? I frequently encounter

    if( $Going_by_the_grocery_store ) { pickup_milk(); } or if( $in_my_town ) { meet_for_beer(); }
    Perhaps a regional difference in speaking patterns.


    Be Appropriate && Follow Your Curiosity

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (13)
As of 2014-10-20 13:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (76 votes), past polls