Insights

Technical Debt as Strategic Asset

Not all technical debt is bad. How to categorize, prioritize, and strategically manage it - including the collaboration engine at Deepnote that went from smart bet to architectural tax.

Vojtech Gintner
October 2023
Updated September 21, 2026
13 min read
Technical DebtStrategyArchitectureCase Study
Technical Debt as Strategic Asset

Technical debt has become a catch-all term for everything wrong with a codebase. But treating all debt equally is a mistake. Some debt is strategic, some is accidental, and some is truly toxic. Understanding the difference is key to building systems that can evolve without grinding to a halt. What follows is the taxonomy I use with the teams I work with, a case study of an architectural bet at Deepnote that was right when we made it and wrong five years later, and the part most writing on this subject skips entirely: how to get the work funded by people who do not read code.

The Problem with Technical Debt Discourse

Most engineering teams treat technical debt as an undifferentiated enemy to be eliminated. This leads to two equally problematic outcomes: either teams spend endless cycles "cleaning up" with no clear business value, or they ignore debt entirely until the system becomes unmaintainable.

The reality is more nuanced. Technical debt is simply a metaphor for the gap between the current state of the system and the ideal state given what we know now. Some of that gap is intentional, some is inevitable, and some is dangerous.

The key is developing a framework for thinking about different types of debt and making conscious decisions about which debt to address and when.

A Taxonomy of Technical Debt

I categorize technical debt into four types: Strategic, Tactical, Accidental, and Toxic. Each requires a different management approach.

Strategic Debt is consciously incurred to move faster. You know the code is not ideal, but shipping now is worth it. This is healthy debt, like a mortgage that lets you own a home sooner.

Tactical Debt is the accumulation of small shortcuts over time. No single instance is significant, but together they slow development. This is like credit card debt - manageable if addressed regularly.

Accidental Debt comes from not knowing better at the time. Old patterns that made sense years ago but are now understood to be problematic. This requires judgment about when to refactor.

Toxic Debt is code that actively prevents progress. Every new feature becomes exponentially harder. This is like predatory loans - it must be addressed before it destroys the business.

These categories are not permanent labels, and this is the part most technical debt discussions miss entirely. Debt migrates. Strategic debt turns toxic when the assumption that justified it stops being true. Accidental debt turns out to have been strategic when the ugly workaround proves load-bearing. The category describes the relationship between the code and your current reality, not a fixed property of the code itself.

Which means classification cannot be a one-time exercise. When a team consciously takes on strategic debt, I ask them to write down two things next to it: the assumption that makes this a good trade, and the date on which we will check whether that assumption still holds. Most teams record the shortcut and forget the reasoning. Two years later nobody remembers whether the trade was ever sound, so nobody can judge whether it still is. The shortcut becomes part of the furniture, and the debt quietly changes category without anyone noticing.

Case Study: The Collaboration Engine at Deepnote

The clearest example I have lived through of strategic debt decaying into toxic debt comes from Deepnote, where we build collaborative notebooks for data teams. Early on we made a deliberate architectural bet: real-time collaboration at the character and cell level, the way Google Docs and Notion work. Two people editing the same code block at the same moment, keystroke by keystroke. At the time this was a defensible call. It was a genuine differentiator, the category was moving in that direction, and we had the conviction to build it properly.

The bet did not pay off the way we expected. Years of usage data eventually told a different story than our product instincts had. People do collaborate in notebooks, heavily - but they collaborate at the level of notebooks and blocks, not within a few characters of one another. One person works on a data loading block while a colleague builds a chart further down. The simultaneous, shoulder-to-shoulder editing we had architected for turned out to be rare. We had built, and were maintaining, one of the most intricate parts of our system for a behavior our users did not actually exhibit.

Meanwhile the cost compounded. The synchronization layer touched the document model, and the document model touched nearly everything we wanted to ship. Engineers learned to walk on their toes around it. Any change in that area carried a quiet tax: extra design time, extra review, extra caution, and a real fear of breaking something subtle and hard to reproduce.

This is where the familiar standoff set in. My engineers were frustrated and increasingly vocal about the constraint. The product managers, reasonably, wanted features shipped on a schedule. Each side heard the other badly. Engineering sounded like it wanted to stop everything and rewrite the product. Product sounded like it did not care about the foundation it was standing on. Neither reading was fair, and the deadlock lasted a long time.

Then the situation got worse in an instructive way. During a large set of changes we broke character level collaboration deliberately, accepting that we would not repair it. But the architectural constraints it had imposed stayed exactly where they were. We had lost the capability and kept the tax. That is the precise moment strategic debt turns toxic: when you are still paying for something that no longer buys you anything.

Fixing it was not an engineering decision, it was a business case. We could not simply announce that we were going to spend months rearchitecting the core of the product. It took several rounds with product managers and leadership to scope the work, secure the budget, and produce an honest risk analysis. What actually moved the conversation was the usage analysis. Once we could show what users were and were not doing, the framing shifted from engineers wanting to clean up their code to something a product manager can act on: we are paying an ongoing tax on a capability nobody uses, and it is slowing down the roadmap you care about.

The execution was deliberately unglamorous. One engineer, several months, replacing every architectural piece that touched collaboration and synchronization one to one. Not a rewrite - a surgical substitution, component by component, with the system working at every step. On the day it shipped, users saw nothing at all. What we got was the relaxation of the architectural rules that had been constraining every decision near them, and room to breathe again.

The lesson I took from this is that strategic debt has a shelf life. Our original decision was not wrong when we made it; it was made with the best information available. It turned toxic because reality diverged from the assumption underneath it and we did not revisit that assumption for years. The failure was not the bet. The failure was never scheduling a date to check whether the bet was still good.

Measuring What Matters

You cannot manage what you do not measure. I work with teams to establish metrics that make technical debt visible and its impact quantifiable.

Cycle time is often the best proxy for debt impact. If the time from idea to production is increasing despite team experience, debt is likely the culprit. It is also movable by means that have nothing to do with debt: at Deepnote we took cycle time from four days to 45 hours by attacking flow and work in progress rather than the codebase. Worth knowing before you blame the architecture for a number that process changes can fix more cheaply.

Bug escape rate and time-to-fix are also telling. Systems with high debt typically have more production issues and take longer to resolve them because the code is hard to reason about.

Developer sentiment surveys, when done well, can reveal where technical debt is causing the most frustration and impacting velocity.

The Deepnote story points at a fourth measure that teams routinely skip: actual feature usage. Debt is only worth carrying if the thing it supports is worth having. Before you plan a paydown, check whether the capability underneath the complexity is still earning its keep. Sometimes the cheapest way to retire debt is to retire the feature it protects.

When Debt Is Not Worth Paying

The instinct after reading a taxonomy is to go looking for debt and fix it. Resist that. A large share of the debt in any mature codebase should be left exactly where it is, and knowing which share is most of the skill.

Debt in code nobody touches is not costing you anything. Ugly code that has been stable for three years, that no roadmap item goes near, is not slowing anyone down. It offends your sense of craft, which is not the same thing as harming the business. Check the commit history before you propose a cleanup. If a file has not meaningfully changed in two years, its ugliness is theoretical.

Debt in code you are about to replace is worse than free to leave alone. I have watched teams lovingly refactor a module three months before a product decision deleted it. Ask what the roadmap does to this area over the next two quarters before you invest a single sprint in it.

Debt you cannot describe in business terms is usually not ready to be worked on. This is not a rule about communication, it is a diagnostic. If you cannot articulate what the debt costs in cycle time, in incidents, or in features that are harder than they should be, you probably have not understood it well enough to fix it efficiently either. The inability to make the case is evidence about the quality of your analysis, not just the quality of your pitch.

The debt worth paying down sits where two things overlap: code that changes often, and code that hurts when it changes. Everything outside that overlap is a matter of taste, and you should be careful about spending the company money on taste.

Making the Case to People Who Do Not Read Code

Engineering teams routinely lose the technical debt argument for reasons that have nothing to do with the merits. They argue in the wrong currency.

When an engineer says the architecture is holding us back, a product manager hears a preference. When the same engineer says the last four features in this area each took roughly twice as long as comparable work elsewhere, and the next three items on the roadmap all land in that area, the product manager hears a schedule problem. A schedule problem is something they already own. Nothing about the underlying engineering reality changed between those two sentences. Only the currency did.

This is what moved the Deepnote work. We stopped asking for permission to improve the code and started describing a recurring cost attached to a capability the business no longer wanted. That is a trade a business person is equipped to evaluate, and they evaluated it correctly within a couple of conversations once the framing was right.

One measurement supports this argument better than any other: investment distribution, the share of engineering capacity going into maintenance rather than new work. When I started tracking it at Deepnote, being able to show that roughly 40 percent of our time went into necessary maintenance changed the discussion entirely. The question stopped being whether engineering was slow and became what the business wanted to do about a structural cost that everyone could now see in a number. Stakeholders cannot weigh a trade-off they cannot see.

The other half of the case is de-risking it. Resistance to large refactors is rarely about the value, it is about the shape of the bet: a substantial sum and several months disappearing into a black box against a vague promise of future speed. When I audited a stalled refactoring project as Fractional CTO at Realpad, the budget existed on paper but there was no mechanism to stop the work if it burned half the money for a tenth of the result. The fix was structural rather than technical: release funding in short increments, define what each increment has to demonstrate, and agree in advance on what triggers a pause and a review. Leadership will fund an experiment with a kill switch far more readily than a project with a completion date. I wrote about that engagement in more detail in Strategic Alignment Saves Critical Refactor at Realpad.

Finally, do not oversell. The Deepnote replacement shipped with no visible change for users, and we said so before we started. Promising a performance win or a feature unlock you cannot guarantee wins the budget once and costs you credibility on every request that follows. The honest version, that this removes a constraint making your roadmap more expensive and here is how you will know it worked, survives contact with reality.

The Debt Paydown Framework

With debt categorized and measured, we need a systematic approach to paying it down. I use a simple framework: Prevent, Prioritize, Pay Down.

Prevent: Establish coding standards and review processes that prevent toxic debt from being created. Some strategic debt is fine, but accidentally writing unmaintainable code is not. Prevention also means declining complexity you do not need yet. When I set the microfrontend strategy at VIG, the first rule I wrote down was not to split an application for its own sake - if a monolith suffices, use it. Architecture adopted for elegance rather than for a problem you actually have is just debt you took on with better branding.

Prioritize: Not all debt needs to be addressed. Focus on debt that is actively blocking progress or creating risk. Use the impact on cycle time and bug rates to guide priorities.

Pay Down: Allocate capacity systematically. I typically recommend 20-30% of sprint capacity for debt paydown in healthy teams, more for teams with significant debt burden.

The key is making debt work visible and celebrated. Teams should be rewarded for improving the system, not just shipping features.

On method, prefer substitution to rewrite. The Deepnote work succeeded because it replaced architectural pieces one at a time with the system running at every step, rather than building a parallel implementation and attempting a cutover. Rewrites fail in a characteristic way: they run long, the old system keeps changing underneath them, and the switchover concentrates every accumulated risk into a single frightening day. Incremental substitution looks slower on the plan and is dramatically more likely to finish.

Then watch the execution risks that have nothing to do with code. Long refactors are lonely and they burn people out, because the work is unglamorous by design and the feedback loop is measured in months instead of hours. They also concentrate knowledge. If one engineer spends months inside a subsystem, you have improved the architecture and narrowed the bus factor at the same time. The Deepnote effort was genuinely a single-engineer project, which kept it coherent and focused, and it meant we had to be deliberate about review and documentation so the understanding did not walk out with one person. Rotating engineers through the work, and having other teams adopt each piece as soon as it lands, are not niceties. They are how you avoid trading one kind of fragility for another.

Strategic Refactoring: The Boy Scout Rule Plus

The Boy Scout Rule - leave code better than you found it - is a good start but not sufficient. Strategic refactoring requires identifying leverage points where small investments yield large returns.

Look for code that is frequently changed or frequently the source of bugs. These are your leverage points. Improving these areas has multiplicative effects on velocity.

I encourage teams to combine refactoring with feature work when possible. If you are adding a feature to a messy area, budget extra time to clean it up. This prevents debt accumulation and improves the system incrementally.

Document refactoring decisions and their impact. This builds organizational knowledge about what types of improvements are most valuable.

Building a Debt-Conscious Culture

Ultimately, managing technical debt is a cultural challenge. Teams need permission to incur strategic debt when it makes sense, and support to address toxic debt before it becomes critical.

I make technical debt a regular part of planning discussions. Every sprint, we explicitly discuss: What debt are we choosing to incur? What debt are we paying down? What debt should we monitor?

Leadership support is critical. When business stakeholders understand that addressing technical debt improves velocity and reduces risk, they become partners in the effort. But that understanding has to be earned with evidence, not asserted with conviction. As the Deepnote work showed, the argument that unlocked months of budget was not an engineering opinion about architecture. It was data about what users were doing, translated into the cost of the roadmap the business already wanted.

The goal is a sustainable pace where debt is managed continuously, not in expensive and disruptive "rewrite" projects.

Conclusion

Technical debt is not inherently bad. Like financial debt, it can be a strategic tool when taken on consciously. But the categories are not permanent. Today's smart trade becomes tomorrow's tax when the assumption underneath it quietly stops being true, and the only real defense is deciding in advance when you will check. The teams that handle this well are not the ones with the cleanest code. They are the ones that can tell the difference between debt that costs money and debt that merely offends, and that can explain that difference to the people holding the budget. The second skill is rarer than the first, and it usually decides whether the work gets funded at all.

Key Takeaways

  • Categorize debt into Strategic, Tactical, Accidental, and Toxic
  • Categories are not permanent - strategic debt turns toxic when its assumption expires
  • Record the assumption behind every deliberate shortcut, and the date you will recheck it
  • Leave debt alone in code that is stable or scheduled for deletion
  • Check whether the feature underneath the complexity is still used before planning a paydown
  • Pay down where two things overlap: code that changes often and hurts when it changes
  • Argue in the currency of roadmap cost, not architectural preference
  • Fund refactors in short increments with an agreed kill switch
  • Prefer incremental substitution over rewrite - the system should work at every step
  • Long refactors concentrate knowledge and burn people out - rotate and document deliberately
  • Do not oversell the outcome; credibility compounds across future requests
Vojtech Gintner

About the Author

Vojtech Gintner - CTO @ Finviz

"Turning Engineering Chaos into Business Value"

Real-world leadership, not just theory. As the active CTO of Finviz, I don't just advise on strategy—I execute it daily. I navigate the same market shifts, technical bottlenecks, and leadership challenges that you do.

With 20 years of hands-on engineering experience (from React/Node to distributed infrastructure), I specialize in turning chaotic software organizations into scalable, high-performing assets. I bridge the gap between business goals and technical reality—speaking the language of your board and your developers.

Interested in similar results for your organization?

Let's discuss how I can help your engineering team overcome challenges and achieve ambitious goals.

Get in Touch