Can One Write Readable and Maintainable Perl?

Perl’s flexibility helps you avoid writing superfluous code.

The answer to this simple but somehow controversial question is an emphatic yes! Unfortunately, there is a lot of bad Perl out there owing to Perl’s history of being the language of getting things done in the 90s. It is easy for a newcomer to feel overwhelmed by such examples.

One can avoid that feeling by basically only learning from Perl that does not look like gibberish.

I decided to learn Perl a little late. Or, maybe just at the right time. I had all the tools to learn good habits right from the get go.

This was soon after 5.8 was released. It was a nice coincidence, because I avoided most of the bad habits one might have picked up by first getting things done in Perl 4 and earlier.

By that time, we had modules, lexical filehandles, an object system, and many other niceties I take for granted today.

Looking back at history, it was the right time to try out Perl. As Larry says, Perl 5 introduced everything else, including the ability to introduce everything else.

That is, CPAN was already there.

Searching the web to find out how to parse CGI parameters would invariably lead one to awful, nasty, cargo-cult code such as:

Members of comp.lang.perl.misc pointed out I should use CGI.pm. The benefits of being able to use $cgi->param('username') were obvious.

When it came to generating HTML, one could find examples such as:

or, even

but, again, the advantages of being able to write

that is, separating content from code, seemed clear.

When people claim Perl is basically -f>@+?*<.-&'_:$#/%!, they are not thinking of the Perl I learned with the guidance of people who had already solved many problems and shared them with the rest of us.

There have been vast improvements in the underlying machinery of Perl along with amazing new modules being released every day. Perl itself is up to 5.18. But, the fact remains that if you took advantage of all the ways Perl5 gave you to write maintainable code, this is just a natural progression.

The main principles of writing maintainable code in Perl are essentially the same as the principles of writing maintainable code in any other language. Start by avoiding global variables, and naming your variables, objects, functions, methods in meaningful ways. Declare and use everything in the smallest applicable scope.

Perl can be terse. I tend to think of that as the language mostly staying out of my way, stepping in only to do what I want.

For example, compare the following Java snippet:

with the Perl code:

The only real difference between them is the use of the regular expression match m{\A \p{Uppercase_Letter}+ \z}x. I could have presumed the existence of CharMatcher->upper_case->matches_all_of and written something in the same spirit, but somehow, that felt similar to writing Integer.One.addTo(counter).

I could have stored lengths in a hash instead of using Set::Bag, but if I am going to carry out set theoretic operations on sets of frequencies of all caps words from other documents, I can write more maintainable code this way than if I had replicated methods from Perl’s FAQ list.

You could also write:

which uses the much maligned topical variable $_ but arguably is still more readable than:

As the source of the Java snippets also notes, you are better off with the for loop version. My point is that sometimes explicitly writing out everything does not help with readability. To be able to read the Perl version, you only need to know that:

  1. map transforms
  2. grep selects
  3. m{…} matches.

This is one example where having more than one way to do it works to improve readability of your code.

Perl is not the best language for everything. No language is perfect. What you use depends only partially on the actual features of a language. I only want to point out that well written Perl is readable.

When one is first learning a language, extra-verbosity might be useful. Some people might more readily understand a code example if everything is spelled out. Consider this C# snippet for reading a file line-by-line:

The equivalent Perl code is:

System.IO.StreamReader might seem clearer than using '<' as the second argument to open. The IDE will help you write that code with the fewest possible keystrokes. But, when you are looking at a wall of code consisting of such class and method names, will you be able to pick the parts of the code that really matter?

Perl’s flexibility helps you avoid writing superfluous code.

How can you write readable Perl?

Spend time on examples you can read. It can be fun to decipher cryptic code, but it is easier to gain good habits by emulating what you find readable. Just as you wouldn’t want to learn good C style from IOCCC entries, JAPHs are not good examples to use in production code.

Do try Perl::Critic. Do read Perl blogs, check out the Perl area on Stackoverflow and think about how to improve others’ code. Follow PerlbuzzPerl WeeklyEffective Perl, and other sources of timely Perl related information.

When in doubt, ask. Learn from others’ experiences.

Related

Sign up for the O'Reilly Programming Newsletter to get weekly insight from industry insiders.
topic: Programming
tags: , , ,
  • Bradley

    Honestly, you’ve hit the nail on the head here. The right tool for the right job is one thing, but dismissing Perl (or any other language) because people believe you CAN’T write readable and maintainable code is just ignorance.

    I’ve seen plenty of crap in every single programming language out there!

    It’s up to the PROGRAMMER not the language to write readable and maintainable code!

    Perl FTW!

  • dfjdejulio

    The most readable, maintainable Perl code I’ve seen was written by someone who prefers C, and they wrote the Perl to look as much like C as possible (going so far as to declare a “main” function). The code was also very rich with comments.

  • Alfredo Sistema

    Unreadable perl is harder to write with the likes of use strict and warnings, but the most common complaint i get with the syntax is the use of $, @ and %. The sigils denote what behaviour the variable has, which is hidden in other languages ( most of them).
    The most important thing in my opinion is keeping a consistent style , and helping yourself with the aid of Perl::Critic and Tidy.

  • Dave

    Time for some heresy. I have been writing Perl for 18 years (and code for 38 years), and much of what you write here is pure Perl fashionista nonsense. I see this kind of recommendation frequently. Why obfuscate what you are trying to do with additional layers of code? If you really do need to rip a QUERY_STRING apart to handle parameters in an Ajax call, passing this to CGI to obfuscate what you are trying to is crazy. They are just going to use the same code in CGI, but instead you add more dead weight to the process by opening additional files and reading in a bunch of additional code that you don’t need.

    The same goes for HTML — most of us use content systems for the template code, but when it comes to writing forms and other output, nothing beats the efficiency and readability of a heredoc fro expressing that, and you can use CSS3 to style that code in any way you want.

    The Perl community has been through this multiple times in the past. Ten years ago, everyone was writing HTML template code instead of using heredocs for forms and content injection. The result? We designers that did not know Perl (and did not have a Perl programmer as a resource) gave up trying to understand HTML template code, and went to PHP in droves because it expressed HTML clearly. Obfuscation is not your friend, and that additional layer of code made Perl look “old” and “outdated” to many in the web development community.

    I am on a special email list for CEOs that use venture capital to fund their start ups. A few weeks ago, someone posted a note about a legacy app they were working with that was written in Perl and they added “don’t laugh”. WTF? We have a real perception problem in the community, and it is this continual process of obfuscation that is killing us. Why does that matter? The less people that use Perl, the fewer job opportunities for Perl programmers. And as the owner of a company that writes Perl software for a living, trying to market applications written in Perl gets harder too. We have to do better than this.

    I am all for using modules for heavy lifting when it is clear that those modules are the right thing to do, but when you only need a few lines of code, and the thing you are trying accomplish is clear, why drag in a thousand lines of cruft to do what you could have clearly written in 12 lines?

    Want to make your code readable and maintainable? Try comments — LOTS OF COMMENTS — comment the top of the program to discuss what it does, break your subroutines into logical groups, place comment blocks in front of them to discuss what they do, and when you have multiple steps in your logic process, mark them step 1, step 2, etc, with a comment on what each step does. And use line comments to document your variables. Write code as if someone with much less experience will have to come in someday and modify your code. And then review your code with other programmers to make sure everything is clear. That is real maintainability. And when you write code, say what you mean and mean what you say — take the time to understand how things work, and then if the CPAN module really does provide an advantage, use it. But obfuscation for the sake of obfuscation is never an advantage.

    • http://www.unur.com/ A. Sinan Unur

      I don’t think we disagree on many points, except for the bit about me being a Perl “fashionista.”

      First, let me note that, in my experience, when people show me Perl code accompanied with a plea of “don’t laugh”, they are not usually showing code that makes good use of modules.

      Second, I am not a big fan of “lotsa comments” because I have yet to encounter a big blob of comments that has not fallen out of sync with surrounding code. Heck, even comments alongside variable declarations are prone to that. However, I think my statement that:

      The main principles of writing maintainable code in Perl are essentially
      the same as the principles of writing maintainable code in any other
      language. Start by avoiding global variables, and naming your variables,
      objects, functions, methods in meaningful ways. Declare and use
      everything in the smallest applicable scope.

      capture the spirit of your recommendation.
      As for templates, I do recommend the spirit of HTML::Template be observed. That is, Perl code should only ever set simple values in templates. In the right set of circumstances, every feature of the language is useful. That is also the case in heredocs. They are useful in certain circumstances, so I am not categorically opposed to them, but mixing output and code willy-nilly does not really work well to help any language’s readability.

      I am not recommending pulling in CGI for your use case, but let me ask you if you repeat the same few lines of QUERY_STRING decoding code everywhere you need it, or have you abstracted it away some place? If you did the latter, that is compatible with what I said.

      A line like $template->param(vegetable_schedule => [ ... ]) says something to the reader. You think of that as obfuscation. I consider it clearly stating what I am doing with the HTML document without repeating the machinery of actually putting those values in the appropriate places in the document. This is not very controversial. Most modern PHP applications do make use of template systems just like modern JavaScript, Java, C# etc applications.

      • Dave

        Sorry, I was a little harsh in my comments. Over the years I have been programming, I have clearly seen popular trends pop up in almost all languages on what is perceived the “right way”, which constantly changes. And if you are building systems and following code fads, you can quickly find yourself with a ton of expensive code that does not meet your objectives. Hence my term “fashionista”.

        I am all for Perl modules — CPAN modules save me time and money — but many of them are heavily bloated, and when just a few lines of code will do, then writing a few lines of code is the solution. I also use application-specific modules for code I write that needs to be reused, so the concept of modules in Perl is a strong advantage.

        As for HTML::Template, I have worked with both HTML::Template and Perl heredocs, and I have had to maintain both over several years. I would much rather work with heredocs that HTML::Template any day. I do a lot of my own HTML work, and I use a lot of jQuery/JavaScript in my front-end code to make things responsive. I can’t do that easily with HTML::Template, and when I have to use workarounds to get it to work, I feel like I am paddling upstream. So I respectfully agree to disagree on this issue. The content management system we use does use templates, but they are HTML/CSS/JavaScript, not Perl code.