Taking on Technical Debt
The Metaphor
In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development.
—Martin Fowler
When programmers talk about technical debt, it's overwhelmingly negative. We talk about accruing technical debt and paying down technical debt. This reflects the reality of software development: most debt accrues unintentionally as bugs are fixed and requirements change.
But there's more to it than that. To continue the metaphor, we talk about the interest from technical debt, but not the capital. We focus entirely on the long-term downsides of unintentional technical debt without considering the short-term opportunities that intentional debt can provide.
Why Technical Debt
The metaphor also explains why it may be sensible to do the quick and dirty approach. Just as a business incurs some debt to take advantage of a market opportunity developers may incur technical debt to hit an important deadline.
—Martin Fowler
Martin Fowler suggests that technical debt can be used to hit deadlines, but I think that's an incomplete picture.
Software development is fundamentally a process of change: either from nothing to something, or from one thing to another. Developing iteratively and incrementally helps manage this process. But often the real difficulty is knowing (1) what the end product should be and (2) how to transform what you have into what you want.
Building Knowledge
If you don't know what to implement, you lack knowledge about the system, problem space, or algorithm. Programming is often the most efficient way to learn; trying to solve a problem will introduce you to all its pieces and challenges.
But I often resist building a solution because I don't know how to build a good solution. I need to be okay with building something that's flawed. Instead of worrying about the good solution, I need to worry about my understanding of the problem.
The difference between that initial version and the one I'm happy with is technical debt that I've taken on. It has let me learn what I need to build a better solution. This leaves me with some debt to pay down, but iterating tends to be faster than designing everything upfront.
Technical debt lets you build your knowledge to arrive at a good solution.
Decomposing Change
As the size of a change increases, the effort required to complete and test it increases dramatically. Build failures and broken pieces multiply the work required to arrive at a working state.
Breaking down a change into smaller pieces helps you develop efficiently. But even within a well-designed system, changes don't always decompose well. New requirements can span multiple components, or even the whole system, leaving you unable break down the change into discrete, well-designed pieces.
By focusing on one part of the system, and adding cruft to the other parts where necessary, you can make small, functional changes. Faking or working around an interface insulates the rest of system, but leaves you with technical debt to clean up.
Technical debt lets you break down work into manageable pieces.
The Power of Capital
Just as a monetary loan can help businesses accelerate their plans, technical debt can speed up the development of new features and software. I believe this is true on both the small and large scale, within a pull request or across a release. It's important to write good code, but don't be afraid to take on technical debt to help you get there.
I've often felt stuck because I didn't know how to write something well. Rather than getting stuck trying to write great code initially, I should be happy to start with bad code and make it into great code. Make it work, make it right, and then make it fast.