Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

What is maintainable perl code?

by disciple (Pilgrim)
on Sep 20, 2002 at 00:25 UTC ( [id://199348]=perlmeditation: print w/replies, xml ) Need Help??

I have been thinking about the comments "Perl code is hard to maintain", and "Perl's design promotes hard to read code." I think most monks here will agree with this; these are naive comments. You can write Hard to read/maintain code in any language and Perl is no exception.

To the newbie, Perl can be difficult to read. Even well written code. For some people, in order to learn Perl they have to go through a paradigm shift. The Perl paradigm, TMTOWTDI, is different than any language I have used. When I first started learning perl I found it difficult to read. Then, after reading "Learning Perl", I felt more comfortable reading and writing Perl.

With a general understanding of programming, one can look at code in almost any language and understand some of it. One thing that makes a language harder to understand are it's advanced features. Well, that explains a lot for Perl because it has tons of advanced features that many languages do not have (in my experience). So how can someone from a different paradigm expect to understand Perl the first time they look at it.

Now, taking that into consideration, let's ask the question, "What is maintainable perl code?" My very simplistic viewpoint is, "Maintainable perl code can be understood or figured out by a programmer that has invested the time and effort to learn and understand the language. But it should not require 10 years of Perl under your belt (or dress)."

Disclaimer:
I am a newbie, so please go easy on me if you don't like what I write :-).

-disciple

Update:
Wow! I want to thank everyone for your informative comments. I never thought so many people would be interested in commenting on this. I am pleasantly surprised.

Replies are listed 'Best First'.
Re: What is maintainable perl code?
by BrowserUk (Patriarch) on Sep 20, 2002 at 02:21 UTC

    From my perspective as a recent convert to Perl, but with a history of several (at least 10 not counting dialecs), the main reason I found Perl harder to get to grips with is somewhat similar to the reasons I find flying a plane harder than driving a car or riding a bike.

    Basically, at any given moment there is more going on in Perl/a plane than in say C/the bike or Java/a car or C++/a darn great truck.

    In C, even with the comma operator and side effects, each single line is doing something fairly simple. A single line (by some definition of line) in Perl can be doing a great deal, and often more than one thing. As with the terrestial vehicles moving in two dimensions on a single plane with relatively few and simple controls, the plane can move in 3 dimensions and has many and complex controls.

    So it is with Perl. With all its special vars, context sensitive functionality, myriad and sometimes magical operators, DWIM features, each line can and often is doing many things at the same time. This can make it difficult for the neophyte to seperate out each individual step, and this can lead (as it did me at the beginning), to quite intense frustration when you simply cannot see how or where things are changing, usually in a way that isn't desirable.

    However, like the plane, Perl usually will reach its destination first.

    However, these problems have to be balanced with the fact that because each line is capable of doing much more than most other languages, there are usually fewer lines for any given algorithm. This, once the eye aquires it's perlish sunglasses (as the quip would have it), means that as a viewer or author of the code, you can usually see more of the program in a single screenful. This, to me at least, is a great boon. Whereas in Java and C++ I was always seeking larger and larger screens and resorting to smaller and smaller fonts in order that I could view enough code in a single view that my eyes could take in the flow of the code without needing to scroll. As a perl programmer, I have rarely found the need to introduce subroutines into an algorithm purely for the sake of breaking a long, monolithic chunk of code in smaller, visually accessable bits.

    I have resorted to creating called-once subroutines in both C++ and Java often. This is partly because of the natural verbosity of these languages, but more usually because it is required by the strictures of the languages.

    I (again personally) strongly favour writing 3 lines of comments to illuminate one line of efficent, idiomatic code in preference to breaking that line up into 3 lines with temporary variables in order to avoid the comments. I realise that is a very personal view.

    I also think that one of the biggest problems encountered with maintainance is that there are way to many programmers around who are quite happy to learn only the basics of any given language rather than explore its full potential. It reminds me somewhat of reading the tabloid press. Short, easily digestable sentances constructed with the lowest common denominator of audience in mind. Spend half an hour reading this kind of prose and then switch to something that does not aim itself at that audience and instead uses the full power and beauty of the english language and you get a feel for the problem.

    As we (used to) say over here, just my two peneth on the subject. I should also warn that I am still evolving my personal Perl style, so you may be well advised to take what I say with a pinch of salt. I may yet change my mind as I start coding larger and more complex systems in Perl.


    Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Re: What is maintainable perl code?
by grantm (Parson) on Sep 20, 2002 at 00:49 UTC

    I feel that consistency is the most important thing for writing maintainable code in any language. Being consistent with your indentation is probably the first thing to get right . The perlstyle man page has lots of recommendations for 'standard' Perl style.

    Comments used in moderation can also be very helpful. I always like to include a comment before each subroutine which describes what it takes, what it does and what it returns. Of course these comments are worse than useless if you don't change them when you change your code. On the other hand, this sort of comment probably isn't very useful:

    # print out the results print $results;

    Using sensible identifier names (eg: variables typically nouns and subroutines typically including a verb) should help make the code fairly readable without having lots of comments.

    I also recommend breaking up long sections of code into subroutines with descriptive names. That way someone can 'zero-in' quickly on the section they're looking for.

    And no, you wouldn't have to look very far at all to find examples of my code where I have failed to meet my own recommendations :-(

    Update: I also meant to point out that searching for maintainable code would probably be another good place to start.

Re: What is maintainable perl code?
by fokat (Deacon) on Sep 20, 2002 at 01:01 UTC
    First of all, I think this is a matter of (personal?) opinion, so probably we'll see a pretty interesting discussion.

    I generally agree to your idea: "Maintainable perl code can be understood or figured out by a programmer that has invested the time and effort to learn and understand the language. But it should not require 10 years of Perl under your belt (or dress).", but I think there is more to it.

    The art of writing maintainable code, in my opinion, has also a few subtle requirements (not that I am an expert myself, even as I am expected to write maintainable code). It is not only that the future programmer has to understand the code. The programmer must understand what we're doing with the code: the algorythms.

    I think that in this respect, the different ways of comments available in Perl (inline/EOF POD and regular # comments) shine above the rest.

    Let's see an example of algorythm vs code complexity at play. The problem is a very simple one, sort a list in random order. The relevant piece of code might look like:

    for (my $i = @list; -- $i;) { my $r = int rand (1 + $i); @list [$i, $r] = @list [$r, $i] unless $r == $i; }
    or
    @list = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, rand(1024) ] } @list;
    (I stole the first one from Re: Randomize an Array to get an unbiased piece of code) Now, the choice of which is easier to understand is a personal one. Both have simple algorythms behind. But a not-so-experienced programmer facing any of the two, might get confused unless a bit of help (a hint, if you will) is present, probably in the form of a helpful comment.

    I personally believe that the second form, using a Schwartzian Transform is both, daunting for beginning programmers and hard to see in other programming languages such as C, where an approach such as the first one is more likely to be seen. A programmer coming to Perl from C, might see the second alternative as quite unnatural for the problem, and therefore would have a harder time figuring it out.

    To summarize, my personal way to (try to) write maintainable code, is to suppress the desire to compress my code shaving keystrokes beyond a certain point, and instead focus on doing things in ways that are both natural an easy (easier?) to understand to the new programmer we might hire tomorrow. I also try to spend reasonable time writing the documentation. Most of the time, I write all the documentation before the first line of relevant code, which also helps me figure out how to sketch orthogonal/complete/clear semantics.

    Just my 10^-2 cents on this thought issue :)

      First of all, I think this is a matter of (personal?) opinion, so probably we'll see a pretty interesting discussion.

      I agree completely that personal opinion plays a large role in what people consider maintainable code. OTOH, I have found that much opinion is merely in style and does not affect the maintainability of the code. I do recognize that there is a fine line there. Unfortunately I am always crossing fine lines. Just ask my wife. ;-)

      I think that in this respect, the different ways of comments available in Perl (inline/EOF POD and regular # comments) shine above the rest.

      I agree. :-) I really like the commenting abilities in Perl.

      for (my $i = @list; -- $i;) { my $r = int rand (1 + $i); @list [$i, $r] = @list [$r, $i] unless $r == $i; } or @list = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, rand(1024) ] } @list;
      I personally believe that the second form, using a Schwartzian Transform is both, daunting for beginning programmers and hard to see in other programming languages such as C, where an approach such as the first one is more likely to be seen.

      I agree, the first example is easier to understand. But, if one understands what each item in the second example does, then a complete picture can be pieced together. And if I didn't understand, I would read perldoc and/or books until I did. But I just consider that a cost of learning.

      To summarize, my personal way to (try to) write maintainable code, is to suppress the desire to compress my code shaving keystrokes beyond a certain point, and instead focus on doing things in ways that are both natural an easy (easier?) to understand to the new programmer we might hire tomorrow.

      I agree except that I don't want to to avoid using an advanced technique which is quite elegant in order for a new programmer to understand it. The same thing can be done in VB. I can write something in VB that will confuse the heck out of new programmers, but it is an elegant solution for the problem. But this is where documentation helps dramatically (like you mention below).

      I also try to spend reasonable time writing the documentation.

      Thanks, I enjoyed reading your comments.

      -disciple
Re: What is maintainable perl code?
by Juerd (Abbot) on Sep 20, 2002 at 07:14 UTC

    Maintainable Perl code is not different from any other maintainable code. While it is true that a single character may behave like what would be ten lines in another language, that doesn't make the program less maintainable. In fact, I think a single character is a lot easier to maintain.

    It's easier to maintain 150 lines of Perl than the 500-line C equivalent. Perl does more in a single line, so don't expect to read 5 lines per second.

    As an example, let's take a piece of DBD::mysql:

    static int CountParam(char* statement) { char* ptr = statement; int numParam = 0; char c; while (c = *ptr++) { switch (c) { case '"': case '\'': /* * Skip string */ { char end_token = c; while ((c = *ptr) && c != end_token) { if (c == '\\') { ++ptr; if (*ptr) { ++ptr; } } else { ++ptr; } } if (c) { ++ptr; } break; } case '?': ++numParam; break; default: break; } } return numParam; }
    The Perl version of the same would probably be something like (untested):
    # Count question marks that are not in (escapable) quotes sub CountParam { my ($statement) = @_; return scalar grep $1 eq '?', $statement =~ /( \? # Question mark | "(?:\\.|[^\\"]+)*" # String in \-escapable "" | '(?:\\.|[^\\']+)*' # String in \-escapable '' | [^?"']+ # Anything else )/sgx; }
    The more statements you have, the more statements can be malfunctioning. On the other hand, removing one character from this regex may break it.

    Is Perl code maintainable? IMHO, it is. Is it readable? If you know Perl, it is -- I admit: the C version is easier for Perl coders than the Perl version is for C coders.

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

Re: What is maintainable perl code?
by atcroft (Abbot) on Sep 20, 2002 at 05:13 UTC

    In reading so far, I see lots of great comments on this thread, and look forward to more of them. A most excellent post, and I think you hit quite a few of good points in it, with more good points being touched on in the follow-ups to the thread. I look forward to reading the postings of others, for they may expand my own approach to this question.

    My own opinion is that "maintainable" takes on multiple meanings. Two of the more important ones that come to mind are:

    • That it doesn't take an unreasonable amount of experience for someone to be able to look at the code, figure out what it is doing, and perform maintenance on the code. Using modules, good/standard coding practices (strict and warnings, not depending on side-effects, etc.), and documentation, all help in this respect.
    • That the code is not so fragile that the (inevitable) modifications that will be requested or needed do not break it so badly that it must be completely rewritten from scratch again. When I think of this one, I'm not considering the single-use script you do for a one-time data massage and import, but instead the application that is used every day that causes screams and such when/if it were to break. Using modules (especially using CPAN modules when you don't have to roll your own), OO (when appropriate), and good design, all help when this is considered.
Re: What is maintainable perl code?
by derby (Abbot) on Sep 20, 2002 at 08:57 UTC
    A lot of people above have posted some good stuff about maintainable perl "style" and a few have posted about reusing a good library (that is CPAN); however I think maintainable code is maintainable code is maintainable code (apologies to Gertrude Stein).

    It really doesn't matter what the language is (Perl, C, C++, Java, Python, etc) or the method (structural or object oriented). The key to maintainble code is decomposition (structural -> functions or subroutines, object oriented -> classes and methods) and ensuring your decomposed code follows the "High Cohesion/Low Coupling" mantra. Ensuring your methods/functions/subroutines/whatever do one thing well and "live" fairly independent (all necessary info is either "passed" in or lives within the object) is the nirvana of maintainable code.

    -derby

      That's a good point. The solid base of maintenance is the overall design imposed on the code - the way how bits and pieces work together. Perl doesn't imply nor exclude any specific methodologies - so this core aspect of maintainability is decoupled from the language itself.

      Readability is certainly an aspect of maintainability too, but it's also a matter of taste. Few (no?) other languages offer the large variety of phrasings that Perl does. That can make it hard for non-Perl folks to understand immediately, but it allows you to code close to natural languages on the one hand, or to compress complex algorithms to small chunks of code and explain in comments on the other hand.

      That's why I would say that Perl is designed to meet exactly that level of maintainability that you want.

      ~Django
      "Why don't we ever challenge the spherical earth theory?"

        Readability is certainly an aspect of maintainability too, but it's also a matter of taste. Few (no?) other languages offer the large variety of phrasings that Perl does. That can make it hard for non-Perl folks to understand immediately, but it allows you to code close to natural languages on the one hand, or to compress complex algorithms to small chunks of code and explain in comments on the other hand.

        I wish I could have said it that well.

        -disciple
      Ensuring your methods/functions/subroutines/whatever do one thing well and "live" fairly independent (all necessary info is either "passed" in or lives within the object) is the nirvana of maintainable code.

      Amen brother.

      derby++

      -- vek --
Re: What is maintainable perl code?
by grantm (Parson) on Sep 20, 2002 at 10:19 UTC

    Let's attack this from the opposite angle: What makes unmaintainable Perl code?

    Passing stuff around using global variables - it makes it much harder to find why a value changed than if you pass/return values explicitly or use OO/accessor methods

    Using Perl's builtin globals ($_, $/ etc) without using local()

    Using the flip flop operator ('..') especially in close proximity to the range operator ('..')

    Rolling your own solutions instead of using well tested CPAN modules with widely understood APIs

    Not catching and handling errors, but leaving them to fall through to someone else's error handler

    Using stupid symbolic reference tricks when you really ought to use a hash (see MJD's 3 part anecdote if only for entertainment value)

    ASP spaghetti - chunks of code and conditionals and loops tucked away in gigabytes of <font> tags

    Coding while drunk :-)

    And here's a contentious one ... excessive use of inheritance. One advantage of 'uses a' (container style) over 'is a' (inheritance) relationships is that can be much easier to work out which class file to look in to find the implementation of a method.

Re: What is maintainable perl code?
by sauoq (Abbot) on Sep 20, 2002 at 10:08 UTC

    Wow. You've gotten a lot of great answers already.

    Most of the focus so far has been on what you can do to make your code easier for a maintainer to read, understand, and change. Although these are crucial considerations and I don't want to minimize their importance, talking about them tends to obscure the real point.

    The most maintainable code isn't the code that's easiest to read, it's the code that requires the least maintenance.

    To use a car analogy, is it more important that the fuel pump be easy to change or that you don't have to do it every weekend?

    Your program could be the most cleanly written piece of software in history; it could have perfectly consistent indentation, exactly the right variable names, and just the right amount of well-written accurate comments but if it breaks whenever the environment changes a little it'll probably be more trouble than it is worth.

    One reason that this is true is that, the more maintenance that is done to your program, the less maintainable it will tend to become. Fixes are often carried out with an emphasis on speedy completion. It often makes sense to, for instance, toss a temporary variable in the mix rather than determine how to change the algorithm and avoid its use. The result is that the more times a program is fixed, the more cruft it collects. The more cruft, the more difficult it is to make another change next week.

    The most maintainable programs are robust and configurable. They validate their input. They error out with informative messages whenever possible. They are coded defensively and thoroughly tested.

    There is a lot of worthwhile practical advice that could be given such as to hardcode as few parameters as possible, to check the returns of all of your system calls, or to pay special attention to testing boundary condtions. There are lots of books available that contain lots of this advice and you can learn from them or, more effectively, from experience.

    In the end, writing maintainable software is an art. It requires attention to detail as well as the ability to see a bit into the future and guess how users are going to use and abuse your program.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: What is maintainable perl code?
by Preceptor (Deacon) on Sep 20, 2002 at 09:02 UTC
    Maintainable code (not just perl) is code that some other moderately skilled programmer can pick up and modify _safely_.
    To make your code reach this state, you need global definitions of constants, _good_ comments when you do any 'magic'. The example would be that
    #display the result; print $result;
    is a waste of disk space.
    But commenting round a Schwartzian transform, to a) say what it does, and b) link to example/discussion somewhere on the net, is extremely useful if I'm coming to it, and trying to understand your code.
    If I to get out a pad of paper to figure out what you're trying to do, then it doesn't have enough comments.
    Consistent style is also important. I don't want to be getting confused by what some code is doing because in some situations you start the 'code block' on the same line, and in others, you start it on the next line.
    (It can be dealt with by using something like PerlTidy, but...)

    --
    It's not pessimism if there is a worse option, it's not paranoia when they are and it's not cynicism when you're right.
Re: What is maintainable perl code? (table-driven design)
by grinder (Bishop) on Sep 20, 2002 at 15:19 UTC
    One aspect that doesn't appear to have been covered is what I would term table-driven design.

    This involves any kind of coding whereby you can remove pure code, and replace it by a generic loop that runs down an array of values. To extend the functionality of the program, you just have to add another entry to a table, and you're done.

    The benefits are that the tables (the user-serviceable parts, if you will), are usually defined at the top of the file, or better yet, in a seperate data file, which means you don't have to grovel through the code to find what you want.

    This leads to a second effect, in that if you don't have to grovel through source, possibly adding one too many or too few braces, and getting syntax errors that can be a pain to track down. Or, worse, introducing new semantic errors.

    For instance, cascading ifs can nearly always be replaced by a hash lookup.

    In a completely different dimension, maintainable code does one thing, and one thing only. For instance, a function that manipulates data and prints it out is doing two things, and that's unmaintable. One day someone is going to need to just manipulate data, and not print it out. At this point they will have to factor out the manipulation code into a new routine, and re-run the the regression tests to make sure they haven't broken anything. (Why are you all rolling around on the floor laughing uncontrollably?)


    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
Re: What is maintainable perl code?
by perrin (Chancellor) on Sep 20, 2002 at 03:45 UTC
    Less talk, more code. This is maintainable Perl code. So is this.
Re: What is maintainable perl code?
by adrianh (Chancellor) on Sep 21, 2002 at 13:43 UTC

    I have one word you should remember if you want to write maintainable perl code.

    Tests

    Lots of them. Ones that can be automatically run. Ones that take advantage of Test::More and integrate with the normal module build/distribute mechanisms.

    Once you have a good test suite you immediately get lots of help with maintainability:

    • Have I broken anything? Run the test suite.
    • How is this piece of code supposed to be used? Look at the test suite.
    • Does everything still work after I upgrade module Foo? Run the test suite.
    • Does it still work on that box running perl 5.0? Run the test suite.
    • ...etc...

    Tests are good. Write more tests and future developers will sing your praises.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-04-25 19:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found