Nature doesn't refactor


There's a very simple assumption that you could make about good design: good design lets you change software cheaply in the future. If it is hard to change a program, then you could say it isn't properly designed. Since most software is subject to a lot of change during its lifecycle, spending time thinking on good design is definitely worth it.

The ongoing debate about how to design applications could use a different angle, though. Nature can teach us valuable lessons. Complexity theory tells us big design up front is mostly a waste of time, the theory of evolution tells us to refactor with a cause.

Butterflies and big plans don't mix

Most people distinguish between planned and evolutionary design. Planned design is also called Big Design Up Front. The basic idea is to design the application first, then code it. As opposed to this, evolutionary design is supposed to evolve over time and converge step by step to a final result.

Usually, a project with a planned design is performed in separate phases, by different people. The design is not necessarily considered completely fixed, but at least mostly fixed. The better the design, the less it will change during coding, is the credo.

Planned design's weak spot is that creating a big, well-planned, readable, explicit design up front is actually really hard, maybe even impossible.

Both in science and life it can be seen, that a chain of events can contain a critical point at which small changes can have immense consequences. This is caused by a strong dependence on initial variables in a complex system.

For example, let us play a game of pool billiard. If there were a way for professional pool players to reliably sink all 15 balls in one shot, at least a handful of them would have learned to do it by now. Forecasting the first three or four caroms will usually pose little problem. Even if the player is off by the merest fraction of a degree in his reckoning, however, his mis- estimation will be greatly magnified by successive hits of the obstacles. Soon the ball will run up against an obstacle that it wasn't supposed to hit or miss one that it was supposed to hit, and all bets will be off.

Any time you're trying to achieve a very precise outcome in a complicated process that takes place outside a laboratory, you're going to run up against all kinds of invisible, hard-to-control factors. That's why even pro bowlers rarely score a perfect 300, and why top major league hitters only get a hit once every three times at bat.

This phenomenon is delicately called the Butterfly Effect. It's a saying amongst weather scientists about how a butterfly stirring the air with its wings in the African jungle today will have consequences for the storm systems over Boston within three weeks. Because we cannot possibly know about all those African butterflies, detailed long-term weather forecasting is never going to work!

What does this have to do with software design? Well, it suggests that it might be literally impossible to predict requirements for the long-term future. Because requirement changes are unpredictable, the design of a software system is unpredictable as well. Even the slightest misassumption could cause a different, wrong approach of the entire system on the long run. It might be one of the reasons why most software projects don't succeed before deadlines and within initial cost estimations.

A jungle instead

Obviously, planned design doesn't really work for more or less complex systems. The reaction to this is development by use of evolutionary methods. A design at the beginning isn't necessary, but expected to grow, evolve and react on change during a project.

But how did the word "evolution" get into this? Most people have a strange idea about natural evolution. They think that when circumstances change, creatures adapt. That is exactly the way it is normally used in "evolutionary" software development: requirements change, and then the design adapts as quickly as possible.

In the theory of evolution, it doesn't work like that. By coincidence, every now and then a creature is born with some features that don't seem to have any purpose, or without a feature that its parents did have. These mutations are initiated by mistake: radiation, or genetic failure. What is important to realize, that these changes are absolutely random. The randomness of the process suggests that rarely these mutations are for the best. Usually the mutant dies. Evolution is not really a steered process, it's more of a massacre.

Sometimes, in very rare occasions, these mutations can be a necessity for survival. When circumstances change, these creatures live on that coincidentally had such a "failure" which turned out to be a blessing. The ones that were perfectly suitable for circumstances before the change, but not anymore, simply die. This leads to a new population of creatures, in which the former mutants become the new standard. Then the whole process starts over again.

What is the lesson we can learn from this? In fact, there are many. For example, the winning design is not the design that adapts to change, but the design that already adapted before the change even occurred. So, nature rigorously wipes out the designs that didn't adapt before requirements changed.

However, most of nature's design experiments up front are futile, and the cost of survival is thus enormous. It's a jungle out there, so to speak.

Another observation could be, that the natural evolution doesn't lead to a "product" which has the best design possible. It leads, however, to a product with a design that is just good enough to survive. Yes, this sounds very agile indeed. Features that are useless, but harmless, will remain. It's exactly the reason why we still have a tailbone.

Instead of just updating a model only when it hurts (like Scott Amblers Agile Modeling web site teaches us), we could conclude that nature also demands the design itself to update only when it hurts. These design updates have to be performed just before it starts to hurt, though. If you don't update beforehand, nature takes you out before you can blink and then it's too late: you're dead.

Don't refactor your tailbone

If we put refactoring against the theory of evolution, some interesting observations can be made.

According to Martin Fowler, author of Refactoring (June 1999; coauthored with Kent Beck, et al.), published by Addison Wesley, refactoring is making changes to a body of code in order to improve its internal structure, without changing its external behavior.

Basically, refactoring improves the design. It divides a program into seperated parts, makes it readible, preferably more explicit and robust. Refactoring is definitely a way of updating the design before you know what is going to happen in the future. By refactoring, you prepare your application for the upcoming change, but you don't really change it.

If a system is bound to change in the future (and most of them are) refactoring can be very rewarding. So if you expect some new features or even just some bugs, please do so. Don't forget about all those past hours of bugfixing!

However, there are some back draws to refactoring. If refactoring isn't steered properly, it could be just a waste of time and money. Let's consider our tailbone. It isn't part of our interface, and we could say it's internal structure. I think for most software developers, it would be one of the first things on the refactory removal list. But maybe we shouldn't remove it. The payback for refactoring this particular item might never come. The tailbone is useless, but it doesn't hurt anybody and it doesn't limit our performance by any means. The tailbone's message is: nature doesn't refactor.

Is it possible to refactor without wasting resources? I think it is. Future requirement changes cannot be predicted, but on a relatively short term you could see these changes coming. For example, forget about the tailbone and start working on a better spine that can handle sitting behind a desk all day. Refactoring could only be really useful if it is based on the assumptions of what is coming up next.

The art of timing

For complex systems, we can conclude that Design Up Front might lead us into big trouble. A small miscalculation at the beginning of a project could have huge consequences in the end on cost and time. Evolutionary design is more or less the way to go.

Nature teaches us a valuable lesson, though: you refactor only if there's some direct benefit. The theory of evolution suggests that the focus shouldn't really be on refactoring per se, but on the short term estimation of upcoming requirement changes. Your refactoring efforts should support these predictions.

If only the strong survive, it's crucial to get just strong enough before disaster strikes.

Sander Nagtegaal, 2003

You are trying to view the newsticker in a browser that doesn't support it. I am sorry.