Search This Blog

The Evolution of a Software Program

Analogies, anecdotes, and parables are all incredibly powerful literary devices that can be used to deepen your understanding of a complex topic and increase your ability to recall more details about it when you need to. When exposed to a new idea, your brain needs something for the new idea to hold onto, otherwise it takes a lot of repetition to lodge it into your long term memory. These devices work by relating the new idea to something you already know so that you can make associations between this weird new thing that you're trying to plant in your mind and something familiar that already has strong roots in your memory. The stronger the connections, the faster you can understand the new idea, and the longer you're going to remember it.

Beyond the mental connections that they make, analogies, anecdotes, and parables all tell stories about what the writer is trying to convey to the reader, instead of droning on with technical prose that will most likely put the reader to sleep. Stories show you what the writer is conveying rather than tell you what you should know. It's a far more interesting way to learn something, and you are much more likely to stay engaged and actually absorb the ideas when you're interested in what you're reading. I felt like I got so much out of The Pragmatic Programmer, because of the authors' use of stories to make their points.

I especially like analogies for enhancing understanding because they are so easy to find in everyday objects and activities. Both of the books I talked about last week made analogies between software development and other endeavors. Andy and Dave likened it to gardening in The Pragmatic Programmer, and Steve related it to building construction in Code Complete 2. Other analogies abound; just do a Google search for what software development is like for a little light reading. I think the variety and sheer volume of associations is excellent. Anything that helps you make new insights and become a better programmer is a plus in my book.

One way to think about software development that I would like to explore is that it is like evolution. Much has been written about software evolution, as in how a software system evolves over time, or the evolutionary model of software development. Those ideas are definitely part of what I'm talking about, but I want to go further and compare software development directly with the theory of evolution. Let's start with some simple associations and see how far we can stretch this analogy.

In the beginning, the theory goes, there was the primordial soup. In it were various organic compounds that had resulted from chemical reactions in the atmosphere. Over time these compounds reacted and combined into more complex polymers and amino acids, the building blocks of life. In the same way, the building blocks of a program are the programming language, libraries, and frameworks that are used to create it. You could go really basic with the building blocks and think of them as the assembly language instructions, or even the machine code that makes up a program, but then we would be describing the evolution of software development in general from machine code to assembly language to higher level languages and abstractions. I think that's a valid association, but I want to look at the evolution of an individual program written in a particular language. It could be any language, but the language is not what's evolving.

Every program has to start somewhere. A simple little proof-of-concept program that takes some input and produces some output is like a single-celled organism, or bacterium, that consumes fuel and produces waste. Okay, maybe 'waste' isn't the best association for a program's output. How about by-product? No, that's not much better. The point is that our little bacterium takes inputs from its environment and converts them in some way to produce something that it emits back into its environment - just like a barely useful initial program does.

From this basic program, the designer can add code to increase its capabilities, either by added features or improving performance. These improvements are the mutations in the program's evolution. Some mutations will be successful and will be kept, saved in the historic record of the version control system. You are using version control, right? Other mutations won't work so well, and will be discarded as cancelled features or mutated further into bug fixes.

As the program grows and evolves, it will become increasingly complex and interconnected, with newer systems built on top of older systems, just like the human brain is built up from older nervous systems, starting with the spinal cord and brain stem, then adding the limbic system, cerebellum, and finally, the cerebrum. Often times code loses its usefulness, but it remains in the program, Or it becomes redundant, but it isn't optimized out. We see similar examples in our own evolutionary history with many redundant parts, and other parts that we can't quite explain.

The compiled code of a program is similar to an organism's DNA. It can be replicated easily, and the compiled code is an exact description of how to create an instance of a running program on a computer. The code can be copied from one computer to another through various methods, and there we have the equivalent of reproduction. Each instance of a running program can vary based on its configuration and unique inputs, which could equate to variations in an organism's DNA and the environment it grows up in.

Evolutionary history also goes through cycles of dramatic explosions of mutations and rapid evolutionary progress followed by periods of relative calm and stability that end with mass extinctions. Software development cycles follow a similar pattern with periods marked by rapid evolution of the code base followed by slower periods when programmers take a rest and hopefully go on vacation. Mass extinctions can be thought of as happening at the release of a new software version when it replaces much of the installed base of the old version, sometimes more effectively and sometimes less.

To really be a useful analogy, evolution should lead us to new insights about software development, and I think it does. Starting with a small proof-of-concept program and then building on it, growing it into something more useful and complex with each iteration, is a highly effective way to develop software. Having a working system at every step of development is extremely beneficial. It may seem like building on top of working systems results in a convoluted mess of software layers, but these systems usually have a deeper elegance that takes study and time to appreciate. And of course, these systems have the unmistakable advantage of actually working. How many times have project teams attempted to build monolithic monstrosities only to watch as they collapse under their own weight? Software that evolves incrementally from one working version to the next has a much better chance of succeeding in the long run.