Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 636 posts at DZone. You can read more from them at their website. View Full User Profile

The measures of programming

04.07.2011
| 8649 views |
  • submit to reddit

80 rows and 25 columns were the measures of one of the most popular VGA text modes in the 1980s and 90s. Today we have far more powerful graphic cards, which render several megapixels every second, on our 24" monitors.

Yet I would argue that a typical programmer does not need more than an 80x25 fixed-width characters windows for wiewing code. My measures are for PHP code, but if you change the actual numbers, fixed dimensions may work also with your Java or Ruby code.

If you are into IDEs, the screen real estate can be used for displaying other helpful informationand avoid a context switch, like a list of available methods, a tree of folders and files, or your red/green bar. I myself keep another terminal open with my running Vim one, to issue version control commands (although I may integrate that in the Vim window in the future.)

Width

So why 80x25 terminals? These measure may seem a limitation, but in fact many programming practices are based on constraints. For example, structured programming (if, for while) limits you from jumping around in your code. Private and protected scope for your class members limit from where they can be accessed. Constraints are not really that bad if they force you to simplify your mathematical model of reality (which is to say, your codebase).

The 80 character limit detects lines which are too long to be quickly understood. Some IDEs (e.g. Netbeans) may display a red line on the 80 character limit to show you if you're exceeding it (I think this number is of course configurable). My Vim displays a red background on the lines segments after. the 81 character.

Static analysis tools, such as PHP_CodeSniffer, bundle coding standards that display a warning when a line is too long and an error when it is really too long (more than 120 characters in the Zend standard):

        if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {
            require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';
            Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer());
        }

What's the condition? And what happens in line 3? I find it difficult to tell at a glance.

If you keep lines short, the readers of the code will be able to follow the flow by moving almost always in the vertical direction, without the need to explore the horizontal dimension and mismatch start of lines with the end of other lines. Again, IDEs may evidence you the selected line so that you don't lose your place, but I bet when reading code you don't continuously move the cursor on the line you're currently reading.

Height

The 25 measure detects too long methods: when you find yourself continuously going up and down your 25-line viewing window to understand what a method does, chances are that it is already too long.

In fact, the limit for ideal method length is probably set on an even lower measure, like 6-10 lines according to Uncle Bob. However, I don't have absolute measures as the length of methods depend on the brevity of the programming language you're using: Java and Python are really different and a method of 6 lines in Python may correspond to a larger, longer version in Java. In Matlab, the same method would probably be twice as long.

Within different programming languages, a limited viewing window discourages programmers from writing and maintaining long methods. If you can adjust the window's height up to 2000 pixel, you'll never touch the 100-line method which would force you to scroll completely 4 times in order to read it all.

Consider regions: some IDEs let you define special comments that act as navigation guidance. If you need regions to navigate into a class, that class is already too long for my taste. Folding of methods may be a good idea instead, but when you open a method it still needs to be shorter than the 25 lines limit.

Indentation

I am also a fan of another measure equivalence, which the 4 spaces for one tab (in general, for one level of indentation). I'm not entering into the tab vs. spaces religion war, but I think that levels of indentation are really readable when represented by 4 spaces, or by a tab character visualized with a width of 4 spaces. 4 spaces is also Python's standard (when not using tabs).

The alternative choices for indentation are 2 spaces per level and 8 spaces per level.

2 spaces are probably too few to easily detect the indentation, especially if you're pair programming and viewing the code from a skewed angle (if you pair with two screens, good for you).

8 spaces are in my opinion probably too much; if you work with object-oriented programming, like many of us, you already start writing most of your code with two levels of indentation (class and method). If you have to write a line in a cycle, you will end up with just 55-56 characters for your line.

Thus, 4 spaces will easily detect too many levels of indentations in the same method, a symptom of a method that merges many different levels of abstractions; at the same time, they will let you use two nested cycles like the ones for accessing a bidimensional array (an image for example).

class MyClass {
    public void doSomething(Image image) {
        for (int x=0; x < height; x++) {
            for (int y=0; y < width; y++) {
                doSomethingWithPixel(image.at(x, y)); //this line: 80 characters
                // why would you need a longer one?
            }
        }
    }
}

Conclusions

These are the reasons why I find myself comfortable with 80x25 windows and a 4-space indentation width. What do you use instead? Maximized Eclipse on a 30'' monitor? 2 spaces like in the Symfony 1 coding standard? Why do you find it helpful?

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Damien Lepage replied on Thu, 2011/04/07 - 9:44am

Interesting post but I've always been bothered with the default limit of 80 characters in my IDE. The following line is 87 with 8 spaces of indentation, I don't see any problem with it.

        throw new IllegalArgumentException("Try to put a meaningful message there !");

IMHO, code can remain readable up to 140 or 160 chars in any language. It just depends on what it contains. Other than that, I mostly agree with you.

Giorgio Sironi replied on Thu, 2011/04/07 - 11:54am in response to: Damien Lepage

If the longest part is just a string I agree that there is no problem (the length limit in PHP_CodeSniffer is 80, but up to 120 is only considered only a warning). But when you have three method calls on the same line, it is a real smell...

Loren Kratzke replied on Thu, 2011/04/07 - 12:05pm in response to: Damien Lepage

The 80 char "soft" limit pays off when you are doing side-by-side diff comparisons. If you try to put two 160 char lines of code side-by-side then you will be hating life.

Erwin Mueller replied on Thu, 2011/04/07 - 12:13pm

Instead of
throw new IllegalArgumentException("Try to put a meaningful message there !"); 

How about

 throw new ThisArgumentIsIllegalException(argument);

Then you can put a whole paragraph of text in your exception.

Or event better

Preconditions.checkArgument(argument); 

That's why I consider regions in C# as a really dengarous feature. You can just hide code from the developer! Just like this guy put it better words: http://artofsystems.blogspot.com/2005/09/region-directive-in-c-chocolate.html

But I disagree with him in regards that it's ok to use regions to hide boilerplate code from bad frameworks or auto generated code from Visual Studio. If you hide it, than you won't see the price for using a bad framework or the price for bad auto generated code.

Damien Lepage replied on Thu, 2011/04/07 - 3:00pm in response to: Giorgio Sironi

@Giorgio I'd be interested to see if you have a better way to write the following code with a lot of Java beans traversing. For me, it doesn't look good but this is just a limitation of Java that I have to deal with (present in any OO language I guess). The last line is 90 characters (and missing some indentation at the beginning) with 5 method calls.

if (parent.getChild() != null
    && parent.getChild().getGrandChildren() != null
    && parent.getChild().getGrandChildren().size() > 0
    && parent.getChild().getGrandChildren().get(0).getSomething() != null
    && parent.getChild().getGrandChildren().get(0).getSomething().equals(somethingElse) {
)

That said, I've been hacking with Clojure lately and I must say I enjoy the short lines that functional programming produces.

@Loren You definitely have a good point with diff.

@Erwin I personnaly don't like custom exceptions when I can avoid (that's another topic) and in your second option, the checkArgument method should contain the kind of line I wrote.

Cloves Almeida replied on Thu, 2011/04/07 - 6:41pm

If you have a lot of bean traversing, you should check JXPath, that applies XPath expressions to regular JavaBeans and collections. Or inlining Groovy.

the above code could be

if (groovy(parent, "it.child?.grandChildren[0]?.something ?: 'NOT_FOUND' " ).equals(somethingElse){

}

Of course, you lose static type checking, but you lose with Clojure also...

Damien Lepage replied on Thu, 2011/04/07 - 9:05pm in response to: Cloves Almeida

@Cloves You're right. I already use JXPath when appropriate. But I still maintain that Java is just too verbose for 80 characters. I'm sure I could find countless of examples and using a library every time is just not an option.

Maybe it's just a matter of personal preference. For example the following lines come straight from the javadoc of ResourceBundle:

ResourceBundle myResources = 
ResourceBundle.getBundle("MyResources", currentLocale);

I personnally prefer the one-liner, even if it's 84 characters without indentation:

ResourceBundle myResources = ResourceBundle.getBundle("MyResources", currentLocale);

 

Erwin Mueller replied on Fri, 2011/04/08 - 2:22am

@Damien

What's wrong with custom exceptions? I thought that's the whole point of exception inheritance. You can have as many custom exception as you like, as long as your exceptions are inheriting the base exception, the client doesn't care at all.

checkArgument() have a use which a generic message, because it signalts to the reader of your code that you want to check the argument. In Guava it's checkArgument(boolean expression), so you can write checkArgument(size > 0). This way it's more clearer to the reader of your code.

But if you really need a message, strings should always be as constants. So you can still write checkArgument(size > 0, MESSAGE_SIZE).

 

 if (parent.getChild() != null
&& parent.getChild().getGrandChildren() != null
&& parent.getChild().getGrandChildren().size() > 0
&& parent.getChild().getGrandChildren().get(0).getSomething() != null
&& parent.getChild().getGrandChildren().get(0).getSomething().equals(somethingElse) {
)
Rewrite it as:
int level = 2; // 0: Child, 1: Grand Child, 2: Grand Grand Child
if (parent.haveChildren(level)) {
int index = 0;
if (parent.childSomethingEqualsTo(level, index, something)) {
// code
}

That should be basic OOP: Ask for what you really need. Aka http://en.wikipedia.org/wiki/Law_of_Demeter

If you can't or don't like to, than variables and a method are viable alternatives:

boolean grandGrandChildEquals(parent, something) {
child = parent.getChild();
if (child != null) {
grandChildren = child.getGrandChildren();
if (grandChildren != null && grandChildren.size() > 0) {
childSomething = grandChildren.get(0);
return childSomething != null && childSomething.equals(something);
}
}
}
// much easier to read then your if-statement
if (grandGrandChildEquals(parent, something) {
// your code
}
 

Erwin Mueller replied on Fri, 2011/04/08 - 2:27am

You do have static import. And strings should always be constants.

ResourceBundle myResources = getBundle(RESOURCE_NAME, currentLocale); 

So even if the name is 100 characters long, the code is still inside the 80 characters bounds. But I agree that Java is too verbose, we should have the option to omnit the type of the variable if the type is clear. It's get wors with generics:

Map<Integer, Map<String, String>> items = new HashMap<Integer, Map<String, String>>();
That's why I like commons-lang. So it becomes more easier to read:
Map<Integer, Map<String, String>> items = Maps.newHashMap(); 

Ben Fox-Moore replied on Fri, 2011/04/08 - 5:27am in response to: Erwin Mueller

@Erwin, there's a solution to the generics verbosity issue coming in JDK7: http://marxsoftware.blogspot.com/2011/03/jdk-7-diamond-operator.html

Giorgio Sironi replied on Fri, 2011/04/08 - 5:41am in response to: Loren Kratzke

Nice, I haven't thought of that as I usually diff in unified format.

Giorgio Sironi replied on Fri, 2011/04/08 - 5:52am in response to: Damien Lepage

@Damien

I agree with Erwin that a train wreck of dots (x().y().z()) is a symptom of a violation of the Law of Demeter, and a limit on line length will help you catch that. When you're accessing all these objects in a single line, you are coupled to the structure of the object graph and any change in one of those methods will impact all the places where you have those "long lines" (although counting the dots can be more helpful than counting characters for this specific case.)

It seems that these calls are defined by an Api you can't change, but you can wrap part of them, since there is a lot of duplication in this condition. I would instantly wrap

parent.getChild().getGrandChildren()

in an helper method if I cannot change parent's class, and give it a meaningful name:

extractDescription(parent)

Then you can also wrap the other conditions. The longest one may become:

matchBetween(extractDescription(parent), somethingElse)

But it's just a start, you can do a lot better once you start extracting methods (see Extract Method in Fowler's Refactoring).

Damien Lepage replied on Fri, 2011/04/08 - 9:01am

@Giorgio
@Erwin

Interesting suggestions, thanks guys. I will watch the length of my Java lines a little closer now.

But I'm a little stubborn, I don't think I'll be happy with 80 chars when some class or method names already use 20. Also, I think not all strings need to be extracted as constants, as long as it is in a single place.

Gilbert Herschberger replied on Sun, 2011/04/10 - 11:59pm

Really, kids, please be aware that the history of 80 characters by 25 rows did not begin and end with Video Graphics Array (VGA).

  1. 80 characters comes from the physical limitation of paper stock used in punch cards. While 120 or 150 column punch cards would hold more data, 80 column cards could be read by a machine more reliably, possibly hundreds of times. Longer punch cards had an irritating tendency to fold and jam the machine. In 1889, a patent was granted to Hermin Hollerith and used for the 1890 census. Census data was encoded on punch cards. Who remembers punch cards? Anyone?
  2. When moving from data to programming, 80 column punch cards was an obvious choice. The COBOL programming language is an example of embracing a physical limitation.
  3. When moving from punch cards to cathode ray tube (CRT) terminals, such as the IBM 3270 series, the tradition of 80 characters per line was well established.
  4. A CRT terminal has a curved screen, low refresh rate, and distortion on the edges. 25 rows is as much as legible on the screen and became a standard.
  5. It is no coincidence that 80 columns and 25 rows became a VGA standard for the IBM PC because so many customers wanted to replace their "dumb" terminal with a general purpose computer, and preserve backward compatibility. Who still remembers the IRMA board? Anyone?
  6. A terminal window on Fedora Linux is 80 columns and 25 rows by default. Coincidence? I don't think so.

So if you're happy with exactly 80 characters by 25 lines at a time, it is either an astonishing coincidence or you have adapted yourself to your tools. Personally, I work with many programming languages, or polyglot programming, and each one seems to have a sweet spot for its most writable and most readable size. But I just can't agree with reading code 25 lines at a time. That would be like reading a website in text mode. That would be like reading an ebook on a mp3 player. As for Java programming, choose a consistent style, and stick to it.

Caution: Please be aware that 80 characters by 25 lines makes less sense for non-Roman languages, such as Arabic, Chinese and Japanese.

My Me replied on Mon, 2011/04/11 - 6:39am

@Giorgio:
> But when you have three method calls on the same line, it is a real smell...

$userRepository->save($userRepository->find(1)->rename('f00b4r'));

what you think about this line?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.