How to write robust code

Jan 13 2007

As soft­ware is one of the most impor­tant issues in our era, writ­ing good robust pro­grams is essen­tial. This arti­cle is an in-depth essay focused on Object Ori­ented soft­ware and large projects. Every­thing said here, though, scales well to good direc­tives for small projects as well.

Our time is dom­i­nated by soft­ware. There is basi­cally soft­ware every­where around us; most of the object you can see right now around you, have some­thing to do with soft­ware, prob­a­bly because they were cre­ated using some sort of machine. Given the impor­tance of soft­ware nowa­days, I just have to find bugs unac­cept­able. Of course you might argue that a small and rare bug is a minor soft­ware won’t harm any­one, and is not nearly as impor­tant as a bug that could affect the soft­ware of an air­plane, and I’m going to agree with that. But as time goes by, every­thing has to be going towards per­fec­tion, and cur­rent trends about soft­ware seem to be going nowhere: there were bugs in soft­ware 30 years ago, and there are today. There was a time, in the begin­ning, where sci­en­tists thought that it would be rel­a­tively easy to write bug free pro­grams right away, but then they real­ized pretty soon that it wasn’t quite so. After all, soft­ware is writ­ten by us human beings, and we are doomed to make mis­takes or omis­sions. The point of this arti­cle is not that soft­ware should be always bug free, but that we, coders, should always get them to the min­i­mum, and here I’m going to present some ways to deal with pro­gram­ming in general.

One huge prob­lem, as I’ve faced quite often, is that as a pro­gram grows in size and depen­den­cies, its devel­op­ers start los­ing trace of its com­po­nents, get fur­ther away from the big pic­ture, and ease the intro­duc­tion of bugs. Note, I’m not talk­ing here about bugs caused by a sin­gle human error that can be labeled as a cheap error by any­one who would look at the code. I’m talk­ing about the sort of nasty bugs that nobody can spot right away with a glance at the code. I’m talk­ing about sys­tem wide bugs, usu­ally emerg­ing as a result of hardly related sub­sys­tems of the pro­gram. Usu­ally con­nec­tions between depen­den­cies and libraries.

Any­way, the path to write bug free code, is the one you step when you write robust code. What do I mean by that? Robust code has some features:

  • Well designed
  • Neat and tidy
  • Well named
  • Well com­mented
  • Well tested
  • It never segfaults

As a result of some of these, robust code is also:

  • Exsten­si­ble
  • Reusable
  • Last­ing in time

Well designed.

Hav­ing already talked about this some­where else, I’ll be brief on this sec­tion. Writ­ing a com­plex pro­gram, a pro­gram made of hun­dreds of thou­sands lines of code, is a damn com­pli­cated thing: it takes many peo­ple and a lot of time. Usu­ally, the more peo­ple you involve in the project, the less robust code you’ll get in the end. Peo­ple will use dif­fer­ent con­ven­tions and dif­fer­ent styles. For this rea­son, not only it’s cru­cial to hire the right devel­op­ers, but it’s essen­tial to have a very strict and detailed spec­i­fi­ca­tion of the project. Pro­gram­ming is a cre­ative work, no doubt, and coders need to have free­dom so they can breathe. A con­strained coder is a chained coder, hence a dead coder and a threat to the qual­ity of the end prod­uct. But, in spite of how much we care for the free­dom and open­ness of ini­tia­tive from the devel­op­ers, we have to be aware that loos­ing con­trol means low­er­ing the qual­ity. A large project must be designed thor­oughly and care­fully, in every sin­gle details. Even though pro­gram­mers love free­dom, most of them also love exhaus­tive doc­u­men­ta­tion. If you want to make a good coder happy, and get the best out of him, flood him with docs and specs. Noth­ing pisses off the good coder as the lack of doc­u­men­ta­tion: it tears his moti­va­tion apart. “Why should I start to read their minds and run by guesses” — he thinks, “when they didn’t even get the time to write good specs?”. Fur­ther­more, a project with­out good specs looks super­fi­cial, des­tined to fail­ure and with­out a future. A very good coder is hardly going to stay in a com­pany that doesn’t make good design for the projects. He will think that it’s a loser com­pany, and start look­ing around.

But what does good design mean? A good design is:

  • Exhaus­tive
  • Non redun­dant
  • Non con­tra­dic­tory
  • Easy to understand
  • Related 1:1 to the implementation

We want to cover every pos­si­ble out­come in our spec­i­fi­ca­tion, let be them exhaus­tive so that noth­ing will be left to case. We don’t want to repeat the same infor­ma­tion more than once, and be redun­dant for sev­eral rea­sons, e.g. infor­ma­tion should be retriev­able in exactly one place, and it would ease up con­tra­dic­tions. Doc­u­men­ta­tion should be for the devel­op­ers, i.e. writ­ten in the most straight­for­ward way for the right audi­ence: sim­plic­ity of lan­guage and straight­for­ward­ness of tables and schemes will spare some curses from the devel­op­ers. Fur­ther­more, as a spec­i­fi­ca­tion is just a way to put a pro­gram in words before it’s writ­ten, devel­op­ers should be eas­ily able to trans­late what they see on paper to code. Think about a shop­ping list: when I get one, I just go to the shop and take care of trans­lat­ing each item on the list to a phys­i­cal item in my shop­ping cart. Direct and easy.

Neat and tidy

A good def­i­n­i­tion of neat is: in a pleas­ingly orderly and clean con­di­tion. How does that apply to soft­ware? What is neat soft­ware? One nice word that I like in that def­i­n­i­tion is “pleas­ingly”. Neat soft­ware pleases the eye and the mind. Don’t want to be cocky here, but neat soft­ware is some­thing writ­ten by a good pro­gram­mer, and will be appre­ci­ated by another good pro­gram­mer. If some­body known as a good pro­gram­mer points at some soft­ware and says “That’s neat” and you find your­self look­ing at it and reply­ing “Huh? That’s just code”, I’m sorry but chances are that you are not a good pro­gram­mer. A good pro­gram­mer appre­ci­ates the beauty of some code, both on a small scale and on a large scale. Neat­ness of soft­ware on a small scale means that you’re able to look at one func­tion and appre­ci­ate the sim­plic­ity of it. Neat pieces of code are eas­ily read­able and use good name con­ven­tions. Please read this arti­cle if you want to know more about good code on a small scale. Neat code on a larger scale, on the other hand, means neat inte­gra­tion between com­po­nents and sub­sys­tem of a project. A bad inte­gra­tion would mean, e.g., hav­ing a project-wide global vari­able that points to a cer­tain sub­sys­tem, and using it every­where in the project. Or hav­ing two sub­sys­tems that, in a messed and inter­twined way, mutu­ally call each other’s meth­ods vio­lat­ing sev­eral lay­ers of abstrac­tion. Prov­ing what neat code is, turns up to be very dif­fi­cult. It’s a bit like the oppo­site of what hap­pens with com­mon logic: if I want to prove you that, say, lions exist, I can just go to Africa, pick one and show it to you, then say “That’s a lion, ergo lions exist”. But how can I prove that uni­corns or dragon don’t exist? You prob­a­bly agree that it’s much more dif­fi­cult. It’s just the oppo­site with neat code. I can show you bad code, and you will eas­ily agree that it’s bad. But look­ing at neat code doesn’t it prove it neat right away. It takes prob­a­bly years and years of expe­ri­ence, writ­ing a lot of code and read­ing a lot.

Well named

This topic has already been dis­cussed here, but repetuta juvant. As code is man­aged by pos­si­bly dozens or more peo­ple, being under­stood is an impor­tant key to increase robust­ness of the code. Writ­ing robust code also means writ­ing code that will eas­ily stay robust when other peo­ple will mod­ify of expand it, unless they have no clue, of course. The most your code is under­stood by oth­ers, the most likely they will not break your ideas, and keep the code robust. There are sev­eral ways of mak­ing own code eas­ily under­stood, and hav­ing a good, con­sis­tent and solid nam­ing con­ven­tion is one of them. Of course, as dis­cussed later, code needs to be well doc­u­mented also.

Well com­mented

I know, I know. Every­body says that you should com­ment your code. That’s what I say and that’s what I’ve been told. Still I’m now com­ment my own code enough as I should. Before you can then tell me “Who are you, then, to tell me to com­ment my code, if you don’t do it enough with yours?” let me remind you that we learn from mis­takes. What they don’t tell you about the impor­tance of com­ment­ing code, is some sub­tle and psy­cho­log­i­cal lit­tle thing. If you are a bad pro­gram­mer, you’ll never pro­duce good code. But if you are a good pro­gram­mer, some­times being in a hurry will make you pro­duce really bad code. There are two rea­sons why this can hap­pen: 1) you are in a hurry because you’re late with your dead­lines. With this, there’s noth­ing to do. 2) you are in a hurry because you’re just cod­ing fast, on the rush of some ideas that flashed you. In this case, com­ment­ing your code a lot will improve dras­ti­cally the qual­ity of your code. Always write your com­ments before writ­ing the actual code. This will make you real­ize it, if your func­tion is not really going to do what it’s sup­posed to do. Writ­ing the com­ment will also help you think more about what you’re doing, and being more con­scious about it. It will keep your state of mind clear and pre­cise. I strongly rec­om­mend using Doxy­gen to gen­er­ate a browseable HTML ver­sion of your com­ments, espe­cially if you’re writ­ing a library. Oth­er­wise, it’s still going to keep you on a pro­fes­sional line, which is always a good thing.

Well tested

Write and use unit tests. If your code is well designed, there are good chances that each func­tion in your code, or each class, per­forms a spe­cific task in a cer­tain way, and noth­ing more. Given a cer­tain input, it will reli­ably return the same out­put. Right? You have to make sure of that, by writ­ing test cases. Test­ing the small­est units of your pro­gram doesn’t ensure that the whole is work­ing per­fectly, but helps. Pos­si­bly, append a hook to your Source Code Ver­sion­ing Sys­tem (SVN? Darcs?) so that the auto­matic test­ing suite will run auto­mat­i­cally on the server that hosts your repos­i­tory, before it accepts your patch. This is quite easy with Darcs.

It never segfaults

Of course this point applies to the lan­guages that allow seg­men­ta­tion fault, or Null­Point­erEx­cep­tion (in Java). It’s easy to get: if your code seg­faults, there are no excuses. No mat­ter how stu­pid the pro­vided input was, your pro­gram should not seg­fault. A good prac­tice, is that each and every function/method would check it’s argu­ment before doing any­thing. A solid excep­tion han­dling struc­ture is required. Again, you can object that I’m not really say­ing any­thing use­ful here: “Of course pro­grams shouldn’t seg­fault, I knew it!”, but think about it: it’s a mat­ter of atti­tude. You want to write a per­fect pro­gram, and there are some things you have to keep in mind. Be para­noid with seg­faults will implic­itly and secretly improve the gen­eral qual­ity of your code, with­out you even noticing.

Con­clu­sion

Writ­ing per­fect code is impos­si­ble. Espe­cially as the code grows in size and num­ber of pro­gram­mers. Achiev­ing the impos­si­ble, then, is beyond any good inten­tioned coder. What we can do, though, is just try to have the right atti­tude, which is about pre­ci­sion, care and, some­times, para­noia. Writ­ing com­plex pro­grams is not an easy thing, and, as such, should be han­dled with extreme care.

Tags: ,

One response so far

  1. […] When writ­ing source code, indent­ing is very impor­tant. Hav­ing a neat and clean pro­gram­ming style, let alone a pre­cise and uni­form one, is prob­a­bly one of the most impor­tant keys when attach­ing exam­ple source code with a job appli­ca­tion. I was myself asked to show some of my source code in my last two inter­views. Nobody ever asked me to show any run­ning pro­gram that I had made, though. Won­der why? A lot can be under­stood about the author just by glanc­ing quickly at some source code. […]

Leave a Reply