My last few posts introduced technical debt and then explained what you should do about it. This recent theme hasn’t completely satisfied my desire write about the topic because I think there is a lot more to this ‘debt metaphor’ than most realize. So I’d like to dig into it a little more here.
The commonly understood definition of ‘technical debt’ does not actually describe all aspects of what you might experience in the world of product development and engineering. Technical debt is classically defined as writing sub-optimal code with the goal of paying it back (refactoring) at some point in the future. And depending on how far along you are with your project/application/business, this may be all you ever get exposed to. But as time goes on, and we increase the altitude of our perspective, we find that this classic definition actually doesn’t tell the whole story.
Technical debt doesn’t tell the whole story
As your organization matures, you are (hopefully) going to have very different needs for your technology. Let’s take the example of a rapidly growing social networking platform:
On day 1, all you cared about as a founder was building neat features that peopled cared about. The whole goal was ‘stickiness,’ because if people didn’t like the experience enough to come back, you’d be out of business in no time. Let’s say, in this example, that you were very fortunate and your social network really took off, spreading across college campuses around the country. Before you knew it, your focus changed really quickly. You had to figure out how to keep the site up. Scaling the application became the bane of your existence.
Eventually, you solved that problem, and new challenges arose. It became about keeping people hooked on the experience even after they were veteran users. Then peoples preferences evolved, and they wanted continuous streams of information, so you had to deliver that also. Then you realized you had a platform on your hands, and it made sense to build in targetted ad-serving technology. People were already standing in line to advertise, and they had quite a lot of feature requests, so your initial implementation of this system had to evolve many times over. Somewhere in there, you realized that you could open up the platform to the world and enable them to build social-powered applications on top of your platform. Then you realized that people actually freak out about privacy, so you had to make everything customizable…
Needless to say, even in the over-simplified view of the world above, we see that the evolution of a business brings with it many different stages where you must change your focus and evolve your product vision.
The evolution of a business creates architectural debt
If we zoom out and look at the whole picture in a scenario like this, we see that the reality is much deeper and more complex than ‘simply writing sub-optimal code for the sake of velocity.’ We have technology needs that change with time, whether they are new features or entirely new systems/sub-systems of the core application. Over time, features can drastically change their manifestation. As the user group grows, inevitably, everything is more customizable than it ever had to be before. That’s not to mention the architectural changes that need to be made in order to scale.
You see, it’s all about the altitude of our perspective. Even if we attacked the new features and technical needs in the most optimal way as each of them came along, we’d still be in a situation where the architecture of the application would be sub-optimal after some amount of time. Even if each new component worked perfectly (in the most elegant and optimal way), the way they fit together is likely to be imperfect because not all of them could have been foreseen. It all depends on how far up we go in terms of altitude-of-perspective. Eventually, if we look at a large enough series of time, there is no way to avoid the architecture being lacking in some significant way. So we see here that the simple term ‘technical debt’ won’t do anymore. So I’m coining a new one: architectural debt.
The simplest acid test I can think of for architectural debt is asking yourself this question: If I was to rebuild my application/platform from scratch today, would the architecture be exactly the same as it is now? If your answer is no, that probably means that your business and its needs have evolved over the last few years, and you are in a much better place to think about it holistically today than you were when you started. Welcome to having architectural debt.
Refinance your architectural debt
So, you have architectural debt. Now what? Well, that’s easy, right? Just pay it down like you would any other kind of debt. Well… not quite. The world gets a little more complex when you are dealing with architectural debt.
Architectural debt is much more challenging to deal with because it involves a lot more ‘capital’ in order to pay it down. It takes a much bigger block of effort because it’s not as easily chunked into smaller blocks that you can tackle within your normal workflow. Worse yet, you are likely to have architectural debt in the first place because your business has been growing rapidly and its needs have been changing just as quickly. So you have pressure to maintain velocity in developing new features. Obviously, in an ideal world, you could just stop all new development and work on paying down your architectural debt. Alas, this is not likely to be so in your case.
So what you have to do pay down technical debt is akin to refinancing your loan. With a refi, you end up paying down all of your debt at once by taking out a loan at a lower interest rate. You still have debt, but it is cheaper to pay it off in the long-run. The technical equivalent of this is to re-architect the core of your application, which generally includes the data model and the most frequently used/accessed components. You will probably have to leave most of the other components alone due to lack of resources that can be committed to the project. So you’ll just have to write legacy adapters into the core (re-architected) part of the application so it can still effectively talk to the other components. But all components written from this point forward should be using the new architecture.
With time, you’ll be able to pay down the rest of the debt by refactoring all of the other components of the application (and systematically removing the legacy adapters as you go.) You’ll begin by refinancing your debt, and ideally, refactoring the other components of the application is like making ‘lower payments’ because of a lower interest rate. It should be easier to do and a lot more pleasurable for the engineering team. And eventually, you’ll end up being debt-free instead of bankrupt!