What You See Is What You “Get”

This is not about WYSIWYG editors, or about how I wish what I’m typing here in WordPress’s visual tab would resemble to some degree what I see on the web page without a lot of farting around with style sheets and other hideous elements.

No, this about real estate.  Not the kind that everyone says is a good investment because they’re not making any more of it (except maybe in Holland), but rather the real estate on your monitor.  When you are reading code, there is a limit on how much of a program you have within your immediate view.  That limit is set by the monitor you use, the font size your eyes prefer, the layout of your IDE, whether your window is maximized, etc.

My contention is that what you see before your eyes is what your brain is capable of digesting and analyzing.  Barring photographic memory, which few of us, myself included possess, it is only the code under your eyeballs that you can effectively ponder, debug, and otherwise grok properly.  Computer programmers realize this fairly early on in their education when they are encouraged to break up large code blocks into functions and subroutines.  Once the principles of object-oriented programming became embedded in our coding DNA, there were all kinds of neat ways to distribute code into minuscule bits and pieces in methods and properties.

So this is all nifty and keen.  Everyone knows you don’t write a function that spans pages of code.  Everyone knows that, like prisoners on a chain gang making little ones out of big ones, you try to break up big code chunks into little code chunks.  Everyone knows that.  So why do I constantly encounter code vomit that spans pages and pages?  (That’s what’s called a rhetorical question because if I were to answer it, I’d probably go off on a tear about how so many programmers just don’t give a crap…  But I’m not answering it, it was rhetorical.)

Here’s a really simple rule: if you are writing a function, it cannot scroll.  It should all fit in a single window-full of lines.  “OK, smart guy,” you say, “how do you define a window-full?  Who’s monitor do you use as a guide?”  Well, OK, if I have to choose, then I’ll say mine.  My main monitor at work is a Dell 2007FP, and it is now the Standard Definition for a Window-full of Code.  It shows about 75 lines and 150 columns, using Fixedsys 10 point font with a menu and single toolbar row in VS2008.  So there is the definition of a window-full: 75 lines and 150 columns.  Do you like that?  No?  So then why did you ask for a definition?

You could do worse than using my monitor as a standard.  It’s not wide-screen, and it’s only 20 inches diagonally, so chances are most coders have access to a monitor at least that size.  Of course YMMV, what with font sizes and various toolbars.  And one more thing:  even worse that having to scroll lines vertically is scrolling horizontally.  Nothing removes the heart of the code out from under your eyeballs faster than scrolling left to see that long-ass line from someone who forgot how to use the Enter key.  (I mean, c’mon, if we’re not going to break up our lines, couldn’t I at least stop typing all these semicolons?)

So, yea, until I get promoted from Code Curmudgeon to Code King, I cannot really come up with a fixed number of lines and columns for a window-full of code, and yea, you could go out and buy some big-ass monitor that would finally contain that function you wrote with ten nested ifs, but if you do that, you probably should stop reading this blog, ’cause you and I, we’re not on the same page–or screen for that matter.

“OK then,” you ask again, “does every function you’ve written since you’ve had this magic monitor, fit within the boundaries of your so-called Window-full of Code?”  Of course not.  There are a few cases, where I might have blown the 75 line limit by a dozen or so.  And, ssssh, yea, I occasionally let a line extend to the right farther than it should, especially if it’s a message I’m building or a comment I’ve appended.  But I would say that 95% of my functions observe the rules, and probably half of those are well under the limit.

It’s when these limits are blown by multiples that I think the alarm bells should sound.  I still find myself reviewing functions, hitting the vertical scroll bar twice, three, four times or more.  This is when I can safely say there is a problem.  A problem for which there is no excuse.

I loath ifs nested within ifs nested within even more ifs.  And it also pisses me off if someone clearly does not understand short-circuiting, e.g.:

private void HandleArray (string[] InputArray)
{
   if (InputArray != null)
   {
      if (InputArray.Length > 0)
      {
         // ...
      }
   }
}

Should always be rendered as:

if (InputArray != null && InputArray.Length > 0)
{
   // ...
}

No, the above will not throw a null-reference exception if InputArray is null, just don’t switch the order of the tests!  Nested ifs are a necessary evil in coding, as are nested loops and the various combinations of them.  But you need to give the code reader a break.  If your top level if or loop spans a screen page, then, yes, you have to refactor this mess.

There is a school of thought that says that every function should have a single exit point, and I think this is a nice design rule to shoot for.  But it is one that I will break to improve readability.  Going back to our silly HandleArray function, you would like to be able to do something like this:

if (InputArray != null && InputArray.Length > 0)
{
   // do something with the array...
}
else
{
   // Issue a message or throw or something...
}

But if do something with the array is long and involved, and you have to scroll down two screens to get to the else, then you have lost the reader’s ability to understand what the original check was about. Better to simply get the sanity checks out of the way and get to the meat of the function:

if (InputArray == null || InputArray.Length == 0)
{
   // Issue some error message or throw an exception
   return; // Unless you throw
}

// Now do your long-winded processing--no need for an 'else' here!

If there are multiple parameters to check, perhaps with different error messages or throws, then you can see that you’ll start nesting ifs to the detriment of your reader.  If all you want to do with your if checks is test the validity of the parameters, do so up top and sneak out of the function ASAP if the caller messed up.  Don’t nest the ifs.

Nested fors and foreachs are tools we would no sooner give up than a carpenter would his hammer, but judicious use of these tools demands that we don’t nest too deeply.   Think of nesting like a splitter for your TV cable.  Each split drops the signal strength by 3 dB, which, because dB is a logarithmic unit, is half of its strength.  After going through 3 splitters, the signal has dropped by 9 dB, but that means that the signal is at one-eighth of its original power.  Likewise, each nested if, for, etc., drops the comprehensibility of your code by half.

The easiest function to grasp contains one line of code.  (As long as it does not horizontally scroll, of course.  If you make me scroll horizontally to follow your logic then, I’m sorry, but you should be flogged.)  We can’t always be so lucky to be able to solve the problem we’re addressing with the function in a single line.  You need to add some checks and loops, not to mentions trys and locks, and maybe really do some work besides.  But if you start coding away and notice that the function’s starting and ending braces are disappearing from the screen as you code, then it’s time to go Back on the Chain Gang, and start making little ones out of big ones.  Because I usually can’t remember what I ate for lunch, and I’m certainly not going to remember what you wrote in the code that scrolled off the screen a minute ago.  So…

Keep It short, because, what I see is all I’m gonna get!

This entry was posted in Readability and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>