In my first programming job the code was older than I was.
It was a Credit Card system and it was written in Cobol. Although it was a good job on a prestigious graduate scheme I was unpleasantly surprised to discover just how hard it was to work on an old COBOL system when I was used to the elegance of more modern languages such as C, Pascal, Modula 2 and (a little bit of) Ada. I worried that I was turning into a coding dinosaur.
One program – called BZCH10 – was over 25,000 lines long. The program read in a credit card record, applied that day’s new credit card transactions to the record, and wrote out updated credit card record. Somewhere in the middle of it there was a single, large, multi-page GOTO statement “GOTO … DEPENDING ON X1” which literally would GOTO another part of the code depending on the value of a variable called X1. There were around 200 valid values of X1 and, needless to say, the variable X1 was littered throughout the 25000 lines of the program. X1 was the driver of a finite-state-machine that ran for each transaction. Try and imagine it.
I remember thinking, as I got more experienced at the job, that my skills were deteriorating and I’d slipped from being an exceptionally good programmer at university to being a not-much-better-than-average COBOL programmer. But, I’ve come to realize recently that my assessment was wrong: it takes a lot of skill to be an average COBOL maintenance programmer because of the sheer complexity of the code. The truth was that I was a good developer in a good team working on a very complex system.
Peter Senge, the Fifth Discipline / System’s thinking guru, talks about two kinds of complexity. The easiest is detail complexity, where the system is made up of many variables and individual items, and even though it’s the easiest kind of complexity, it’s still damned hard work. All non-trivial software systems have detail complexity. Good design makes it easier to understand these complex systems because it breaks the code down into manageable chunks and hides the detail of each chunk unless you need to look at it.
Good design works on the second, harder type of complexity: dynamic complexity, where the cause and effect at play within the system is subtle, unpredictable and often downright confusing. For instance, I once spent 6 weeks trying to fix an obscure bug in BZCH10. It took about 3 weeks to find the problem, about 30 minutes to add the extra 6 lines of code fix it, and another 3 weeks to ensure that I hadn’t broken anything else. A good bit of the time taken was caused by the detail complexity because it was extremely difficult work to track my way through the mass of code and find the problem. But, the bulk of the work was due to the dynamic complexity of the code because the convoluted design of the code meant that I couldn’t be confident that my 6 new lines of code wouldn’t cause some very unpleasant side-effects (which you want to avoid when dealing with hundreds-of-thousands of customers and millions of dollars worth of transactions each day); that is, the design of the program made the cause-and-effect very difficult to un-tangle.
So, good design is important. It makes us more productive because it simplifies complexity.
BZCH10 really didn’t stand much of chance because the original COBOL programming it used didn’t lend itself to good design.COBOL was created in 1959, before structured programming or even object oriented programming/design came along. However, nowadays, modern COBOL (the 2002 standard apparently) does allow OO design and coding. I wonder what the design (and therefore complexity) of BZCH10 would be like today if object-oriented COBOL was around when it was first built.
Okay, forget about COBOL, imagine that we’re starting a new project next week using a modern programming language and our team is made up of world class developers.
How good will the system’s design be in 30 years time?
What could possibly go wrong?
to be continued …
… but, I’d love to
see your answers