On Architecture and Technical Debt
Author’s note: I started writing this out of my own interest in reconsidering what technical debt should be. It’s one of the most confusing terms in technology that people may encounter, and even amongst engineers, there often isn’t a clear consensus on what technical debt exactly is, other than bad–we’re all clear that technical debt is bad, because it sounds pretty bad.
In a modern software engineering organization, engineers are tasked with building many things. This can be code that you ship; or the code that ships code; or the infrastructure on which you run the code. This can include third-party services–really, anything you use to help build, test, deploy, or monitor a product. Let’s call this collection of things architecture.
We want the architecture we build to last a long time, and carry with it a minimum of fuss. If we can accomplish this task, we will free ourselves to spend more time writing new code with confidence. There are three properties that such architecture should have to give it the best chance at that long life:
- Architecture should be adaptable to current and future requirements.
- Architecture should be testable, so that you can understand how well it fills requirements.
- Architecture should be modern, using technology that is well-understood and relevant for those engineers who must work on it.
The properties above can be considered as spectrums, and through the natural course of building things, engineers will be called to make tradeoffs for each of them.
What if you need a one-off script to do one thing, one time? If you’ve worked as a software engineer for any period, the chances are good that you can think of many times when that’s happened. The tradeoff of writing that script is that, when you find it needs to be run many times, or needs to be automated, you may need to rewrite the code, or write much more code to enable all that to happen.
That small example is a good demonstration of technical debt. Technical debt is a decision you made when building architecture that later needs to be revisited.
The outcome of technical debt is often that architecture must be rewritten or revised. We can invert our three properties for long-lasting architecture to explain how technical debt can impact your work:
- Technical debt is architecture which is no longer adaptable to current or future requirements.
- Technical debt is architecture which is not testable, in which defects cannot be quickly understood and the mean-time-to-repair (MTTR) is unacceptably long.
- Technical debt is architecture which is not modern, using technology that few engineers understand and which cannot easily be hired for.
All architecture, over time, accrues technical debt. Eventually, the technology that underpins your architecture falls out of vogue. Eventually, some new requirement will be introduced that your architecture can’t adapt to. Eventually, you will find a defect that your measurements missed.
Every engineering organization, at all times, works with and remediates technical debt. Sometimes this remediation happens implicitly, as engineers notice issues and decide to clean them up along the way. Sometimes remediation happens explicitly, when engineers decide that they need to focus for a long stretch of time in order to improve adaptability or testability, or to upgrade the underlying technology.
The worst-case scenario for technical debt is a rewrite. That happens when engineers can no longer salvage the underlying code. This can happen for any number of reasons:
- Explicit assumptions about requirements were made early on and hard-coded into architecture, causing that architecture to ossify and be unable to handle the current requirements that are needed.
- Code was written without any unit tests, leading to units of code which have large footprints that are awkward or impossible to test as written.
- Frameworks or languages were chosen which are no longer favored by engineers, making it difficult to find motivated and educated individuals to work on the architecture.
The best way to combat technical debt is to slow down its spread; to do that, one should consider a process by which all new architecture is designed with adaptability and testability in mind, using modern technology. When tradeoffs must inevitably be made, care must be given to be mindful of the effects those tradeoffs can have on the accrual of technical debt. In cases where speed is of the essence, technical debt can and should be taken on–but with an obligation to remediate that debt as soon as you are able.