Previous Page
Next Page

1.1. Three Goals

A good coding style is one that reduces the costs of your software project. There are three main ways in which a coding style can do that: by producing applications that are more robust, by supporting implementations that are more efficient, and by creating source code that is easier to maintain.

1.1.1. Robustness

When deciding how you will write code, choose a style that is likely to reduce the number of bugs in your programs. There are several ways that your coding style can do that:

  • A coding style can minimize the chance of introducing errors in the first place. For example, appending _ref to the name of every variable that stores a reference (see Chapter 3) makes it harder to accidentally write $array_ref[$n] instead of $array_ref->[$n], because anything except an arrow after _ref will soon come to look wrong.

  • A coding style can make it easy to detect incorrect edge cases, where bugs often hide. For example, constructing a regular expression from a table (see Chapter 12) can prevent that regex from ever matching a value that the table doesn't cover, or from failing to match a value that it does.

  • A coding style can help you avoid constructs that don't scale well. For example, avoiding a cascaded if-elsif-elsif-elsif-... in favour of table look-ups (see Chapter 6) can ensure that the cost of any selection statement stays nearly constant, rather than growing linearly with the number of alternatives.

  • A coding style can improve how code handles failure. For example, mandating a standard interface for I/O prompting (see Chapter 10) can encourage developers to habitually verify terminal input, rather than simply assuming it will always be correct.

  • A coding style can improve how code reports failure. For example, a rule that every failure must throw an exception, rather than returning an undef (see Chapter 13), will ensure that errors cannot be quietly ignored or accidentally propagated into unrelated code.

  • A coding style can improve the structure of code. For example, a prohibition against reusing code via cutting-and-pasting (see Chapter 17) can force developers to abstract program components into subroutines and then aggregate those subroutines into modules.

1.1.2. Efficiency

Of course, it doesn't matter how bug-free or error-tolerant your code is if it takes a week to predict tomorrow's weather, an hour to execute someone's stock trade, or even just one full second to deploy the airbags. Correctness is vital, but so is efficiency.

Efficient code doesn't have to be fragile, complex, or hard to maintain. Coding for efficiency is often simply a matter of working with Perl's strengths and avoiding its weaknesses. For example, reading an entire file of text (possibly gigabytes of it) into a variable just to change each occurrence of 'C#' to 'D-flat' is vastly slower than reading and changing the data line-by-line (see Chapter 10). On the other hand, when you do need to read an entire file into your program, then doing so line-by-line becomes woefully inefficient.

Efficiency can be a particularly thorny goal, though. Changes in Perl's implementation from version to version, and platform-specific differences within the same version, can change the relative efficiency of particular constructs. So whenever you're choosing between two possible solutions on the basis of efficiency, it's critical to benchmark each candidate on the actual platform on which you'll be deploying code, using real data (see Chapter 19).

1.1.3. Maintainability

You will typically spend at least four times longer maintaining code than you spent writing it[*]. So it makes sense to optimize your programming style for readability, not writability. Better yet, try to optimize for comprehensibility: easy-to-read and easy-to-understand aren't necessarily the same thing.

[*] The observation that maintenance costs tend to outweigh initial development costs about 4-to-1 is often referred to as Boehm's Law. The predominance of maintenance over development has been repeatedly observed in real-world studies over the past three decades, though the actual cost ratio varies from about 2-to-1 to well over 10-to-1.

When you're developing a particular code suite over a long period of time, you eventually find yourself "in the zone". In that state, you seem to have the design and the control flow and the data structures and the naming conventions and the modular decomposition and every other aspect of the program constantly at your mental fingertips. You understand the code in a profound way. It's easy to "see" problems directly and locate bugs quickly, sometimes without even quite knowing how you knew. You truly grok the source.

Six months later, the code might just as well have been written by someone else[]. You've moved on from it, forgotten the clever intricacies of the design, lost the implicit understanding of the control and data flows. And you have no idea why that critical variable was named $nxt_eTofF_trig, what it stores, what that value is used for, or how it might be implicated in this newly discovered bug.

[] That's Eagleson's Law. Other experts bitterly assert that the critical interval is closer to three weeks.

By far the easiest way to fix that bug is to get yourself back into the zone: to recover the detailed mental model you had when you first wrote it. That means that to build software that's easy to maintain, you need to build software that's easy to re-grok. And to do that, you need to preserve as much of your mental model of the code as you can, in some medium more permanent and reliable than mere neurons. You need to encode your understanding in your documentation and, if possible, in the source itself.

Having a consistent and coherent approach to coding can help. Consistent coding habits allow you to carry part of your mental model through every project, and to stay at least partially in the same mindset every time you write code. Having an entire team with consistent coding habits extends those benefits much further, making it easier for someone else to reconstruct your intentions and your understanding, because your code looks and works the same as theirs.

    Previous Page
    Next Page