Nothing fattens up code like a code donut. Tasty and sweet they satisfy your feature needs temporarily but leave you wanting more and more and more. They also turn your lean runner’s body into something better suited to “Sweating to the Oldies”.
I’ve used the term code donut for a while to describe a certain kind of feature request: the kind that moves you sideways from where you want to go (or sometimes backwards). When a company has a well defined need for something of moderate size, it’s very common to build something stopgap that takes care of the “low-hanging fruit” without solving the whole problem. These kinds of solutions are frequently both necessary and useful since the ideal solution may be to complex to build all at once. These aren’t code donuts, but they are the precursors to code donuts. The code donut is the small well defined improvement to the initial temporary solution that comes as a follow up (and the one after that, and the one after that, and so on). Developers often like these little additions because they are well defined and straightforward. Small simple projects are fun since you get that nice sense of completion. The problem is that all of the little changes that come after the interim solution usually do nothing to move you towards what you really need, they just fatten up the current solution and often other parts of your code as well.
Companies build on top of these interim solutions for a few different reasons. Sometimes the temporary solution just doesn’t do the job. Continuing to build off of a poor solution that doesn’t do the job is almost certainly a case of spending good money to try to recover bad. The idea of the temporary solution was that half a solution was good enough, if that’s not the case it probably never will be. Another reason for these small enhancements is that the temporary solution does what it’s supposed to and people are using it and finding other things it needs to do. This is the bigger and more insidious case. It means that people and processes are going to adapt themselves to the temporary solution which virtually guarantees that it will be anything but temporary. When these changes move gradually and inexorably towards the desired solution they are all great things. When they don’t they are probably code donuts making you fatter and not really taking you where you need to go. The demand for more is an indication that the problem is an important one. It’s an indication that spending the time and energy to get what you need is a good idea.
I recently had a contract with a company that had been code donuting itself to death for a long time. They had a large system that amounted to little more than glorified email, but they had managed to intertwine themselves with it from a data, code and process standpoint to a degree that made it difficult to consider the many superior alternatives that could have made their jobs easier. No one wanted the system any more, but neither could they find their way out from under it. The code was one thing, but even more challenging was the way people had become dependent on it. Any alternative would be framed in terms of the current system, funneling conversation down a narrow and deep hole and keeping people from understanding that there are other ways of doing things.
Agile processes are highly vulnerable to code donuts. The nature of the short development cycle and the near term prioritization encourage finding the best solution for now and then expanding on it. Several agilists I know have even challenged the legitimacy of the notion, apparently subsumed in their belief that as long as the code is well factored the short term decision is always the right one. Unfortunately I’ve seen too many broken systems fashioned gradually around a temporary solution to believe that weak dogma.
Some of the ways you can avoid code donuts are:
- Craft interim solutions that are part of an ideal solution rather than instead of and ideal solution. This is hard and not always possible, but look for ways to do it. It’s the single best approach you can take.
- As soon as an interim alternative starts to become critical to your internal processes invest in the preferred solution.
- Leave interim internal solutions unpolished. Strange as this sounds, if you believe something is temporary then making it feel that way keeps people from getting too attached. It also saves development time. Quality fanatics feel free to fax me a copy of your hand so I can slap myself silly with it.
- Avoid integrating interim solutions. When they stand alone they are easier to replace and they don’t pollute the rest of the code stream.
- If you really have no plans to do “the right thing” then acknowledge that and do the closest thing you can. Sometimes what you want is beyond your reach. In these cases you need to stop acting like the temporary solution is temporary and recognize that it is a real product, giving it the care and attention it deserves and not just a long running series of code donuts.
If you fail to follow these simple dietary suggestions, be prepared to fight a long and running battle with bloat.