I don’t know whether it’s just developers, or whether it’s all humans, but we have a tendency to minimize things we shouldn’t minimize. (This tendency is nicely balanced by our tendency to blow other things out of proportion.) One thing I have heard minimized many times, and yes, that I have minimized many times, is carelessly placed, small pieces of complexity. “It’s only an if statement…”—No. It’s never just an if statement. It’s not just what the complexity is. It’s where you put it and how you handle it. And importantly, whether or not you iterate on it.
Inventory tracking logic doesn’t belong in purchase order code. Okay, you say, but what’s the big deal? In isolation, one if statement out of place is not a big deal. It can be repaired fairly easily. But the attitude that says it is unimportant and then neglects to fix it is a big deal. We have all seen the effects of this, and we hate those effects. But somehow, we fail to realize that one of the main causes of rot and complexity in our systems is carelessly placed complexity.
Now there is such a thing as legitimately taking on technical debt—that is, knowingly shortcutting the right way of handling your complexity with the knowledge that you will need to shortly come back and iterate on it. But this knowing acceptance of technical debt counts the cost and does not try to claim that it’s just an if statement.
The best wisdom in the software industry says that the way to build a valuable product is to iterate, and to make each iteration smaller than we intuitively guess it needs to be. But though this understanding is incontestable, mostly we don’t internalize the power of the small and the iterative—for good or bad. Small bits of misplaced or mishandled complexity pile themselves on like barnacles, eventually creating a heavy buildup of accretions. An “if” out of place is a complexity magnet; it is like the speck of sand that starts a pearl; it is like a broken window inviting more broken windows. Are you iterating toward a product your users will love, or a product that you will hate?
We’ve all seen systems so complex that no one wants to work on them (and probably the users aren’t big promoters either), but most of them didn’t start out that way. They were relatively well-designed in the beginning. Of course, hindsight is 20/20 and we can always critique what we’ve done in the past and take the moral high ground towards it. But if we are honest with ourselves, often a system in its early days is a good first pass. The problem with complex legacy systems is often not so much that they started on the wrong foot. It’s not even that they didn’t evolve. It’s that they didn’t evolve in the right direction—they devolved over the course of months or years.
Again, I don’t know whether this is just developers, or whether it’s all people, but we so often think that there was one big event that made everything awful, and that we need a big event to make everything good again. This is why we so often fall for the allure of the big rewrite; I refer you to Joel Spolsky on things you should never do. We’re kidding ourselves. Occasionally a big event will cause a lot of damage, but a big event almost never repairs anything. We need to give up thinking in terms of big events. Think in iterations.