ted.neward@newardassociates.com | Blog: http://blogs.newardassociates.com | Github: tedneward | LinkedIn: tedneward
define Technical Debt and distinguish it from "just bad code"
understand the financial analogy of debt and apply it to software development
identify how tech debt is incurred
learn strategies to manage and pay down debt without stopping innovation
slides are available at https://www.newardassociates.com/presentations/BusyManagersGuide/TechDebt.html
an LLM-based chat engine (OpenWebUI/glm-4.7-flash) wanted to call this talk a couple of different things:
"The Invisible Bank Account"
"The Good, The Bad, and The Cost of Speed"
... if that helps you get the drift of where we're going
Scenario: You are building a startup.
you have limited time
you have limited money
you have a small but excited group of customers
you have a Board that is constantly looking over your shoulder
You have features you absolutely have to deliver ASAP
Scene 1: You launch a feature today rather than next week.
Customers love it.
The Board is happy.
Your team is tired and a little grumpy, but good.
Everyone is happy.
Scene 2: You launch a different feature in a week.
Customers are pretty good with it.
The Board is happy.
Your team is tired and more grumpy, but still... good?
Scene 3: You try to launch an even newer feature, but...
... it crashes a lot
Customers are complaining.
Your team is yelling at you about something.
The Board is grumpy.
Scene 3: You try to re-release an improved feature from Scene 1.
It takes you 4 days.
Next month, it takes 6 days.
Before long, you can't change anything without breaking the whole system.
Customers are leaving.
Your team threatens to quit.
The Board is contemplating profiles on LinkedIN.
The Problem:
Core Question: "Why did building fast make us slow in the long run?"
coined by Ward Cunningham in 1992
used as a metaphor to explain why certain tasks would take longer
... primarily to an accounting-centric audience
the key example: Y2K double-digit year fields
"Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite... The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object-oriented or otherwise."
"The WyCash Portfolio Management System" (http://c2.com/doc/oopsla92.html)
Technical debt ~= Financial debt
A "feature" is an expense (or investment).
"Maintenance" is the interest.
"Refactoring" is paying off the principal.
And "bankruptcy" is when you can't pay off the debt
explaining:
why your build process needs automating
why you need a continuous integration server
why regression tests are important
... is often lost on non-developers
a metaphor can help get the idea across (sometimes)
Requirement Debt
People Debt
Communication debt
Architectural debt
Design debt
Process debt
Build Debt
Code debt
Testing debt
Defect Debt
Documentation debt
Infrastructure Debt
Security debt
Ward never had subcategories or a full ontology of the concept
Others (particularly vendors) have explored/expanded the list
... not surprisingly, usually to correlate with the very kinds of things that vendor sells products to help avoid!
Many in the agile community were quick to cite "tech debt" as reasons for agile
Many in the "anti-agile" community were quick to do the same
Intentional shortcuts: Making a quick decision to meet a deadline, even if a better but longer solution exists.
Unintentional mistakes: Inexperienced developers, poor architectural choices, or insufficient knowledge can lead to debt.
Insufficient documentation: Lack of documentation makes it difficult for others to understand and maintain the code.
Lack of refactoring: Not regularly addressing and improving existing code can lead to it becoming outdated and difficult to manage.
Rapid changes: Unforeseen or last-minute changes to features can introduce bugs and complexities that are not properly addressed.
Pressure to minimize development time/schedule pressure
Unexpected and ill-defined features and changes: The implementation of last-minute specification changes or changes that are insufficiently documented or tested
Gaps in knowledge or skills: May manifest as a lack of process understanding, insufficient knowledge, poor technological leadership, or inadequate mentoring or knowledge sharing practices.
Issues in the development process: Such as sub-optimal solutions, insufficient requirements (from process inefficiencies), conflicting requirements on parallel branches, deferred refactoring, or delayed upstream contributions.
Ignoring common practices: Such as insufficient software documentation, poor collaboration practices, lack of ownership, rewrites for outsourced software, inadequate attention to code quality, tightly coupled components, lack of a test suite, or failure to align to standards (including ignoring industry standard frameworks).
Technical debt is almost always a strategic choice
prioritizing time
prioritizing cost
prioritizing features
... over other things
Ideally that choice is deliberately made
But ....
https://martinfowler.com/bliki/TechnicalDebt.html
a two-axis, four-cell graph
"prudent" vs "imprudent"
"deliberate" (intentional) vs "inadvertent" (accidental)
note that this is different for each possible choice in the system
vendor choices
architecture
software design
UI/UX
... and many, many more
"Prudent-Intentional"
The team thought about this one
The debt was small, easily-managed, or not yet a concern
They realized the tradeoff was worth the debt
Nobody ever talks about this
"Imprudent-Intentional"
The team thought about this one
The debt was large, critical, or much bigger than they expected
They thought the tradeoff was worth the debt (but later discovered otherwise)
Some horror stories come from here
"Imprudent-Accidental"
The team didn't spend any time thinking
Over time, they realized this was turning into a disaster
The debt was large and intractable
This is where the worst horror stories come from
"Prudent-Accidental"
The team didn't spend any time thinking
Over time, they realized they made good choices
The debt was small and easily-managed
Nobody ever talks about this
Decisions are being made all the time
These decisions are not always explicit
Most decisions are recoverable; nothing is ever set in stone
Changing a decision will always have some kind of cost
search "Avoiding technical debt"
get lots of wildly different answers
so who's right?
pioneered by "Uncle" Bob Martin
https://en.wikipedia.org/wiki/Software_craftsmanship
there's even a manifesto
https://manifesto.softwarecraftsmanship.org/
in short, if you are not always taking pride in your craft...
... take up farming
lots of debt is "bad debt"
credit cards
venture capital
US federal budget deficit
lots of debt is "good debt"
mortgage
car loan
business loans
debt is a necessary instrument in modern financial systems
Keep in mind, some will overlap
And some will not be a problem for you (yet, or possibly never)
As with all things, "forewarned is forearmed"; just knowing to watch out for it can help address it
Symptoms:
asking five questions for every line of code
inability to describe the feature being built
constant rework after demo
Cause: Unclear vision or requirements
Correction: "Explain it to me like I'm five years old."
Symptoms:
individuals' estimates wildly off; "you've been at 80% done for three weeks now"
constant rework of certain individuals' work
people looking stuff up (Google or LLM) constantly
Cause: Not having the right people to work on particular problems, usually owing to a lack of skill or experience
Correction: training or hiring
Symptoms:
"I'm trying to reach them but they're not answering"
"We'll have to wait until tomorrow to get an answer"
"We should ask but that's such a pain. Let's just wing it"
Cause: Poor means or habits of communication between the people working on the project
Correction: Either:
embrace an asynchronous approach to the work
enforce a more synchronous approach to the work
Symptoms:
modifying one component requires modifying numerous others
components/modules cannot be reused, or constantly shift with requirements changes
poor performance, poor scalability
Cause: Poor architecture, usually due to hurried decisions, unrealized requirements, or lack of foresight
Correction: architectural refactoring
NOTE: many people consider this a deeply non-trivial suggestion
Symptoms:
lack of accessibility
bad usability (nobody can figure out how to do anything)
customer complaints; bad NPS scores; low customer satisfaction (or dropping numbers)
Cause: UI/UX issues; usually when design decisions or designs are made hastily and without proper user research
Correction:
get some first-hand observation of customers using your product
embrace "eating your own dog food"
Symptoms:
"Wait, I thought you did that part."
"You were waiting on me? I was waiting on you."
"What do you mean, three different people from our company have given the customer different answers?"
Cause: lack of clear process to accomplish particular tasks, often from a lack of clear distinction between teams/roles
Correction:
RACI diagrams
Symptoms:
inconsistent builds (never quite the same bits twice)
creating a build takes too long and/or requires manual steps
only one person is "authorized" to produce a release
Time to First Pull Request
Cause: the build process is not documented, deliberate, or automated
Correction:
continuous integration (CI) pipeline technology (Jenkins, GitHub Actions, etc)
Symptoms:
performance issues
extensibility is extremely difficult
Cause:
Correction:
insufficient familiarity with language idioms
inconsistent practices
rare, if ever, refactoring
Symptoms:
"sigh That bug is back?!?"
a customer posts a bug a review and describes a bug never seen before
Cause: a lack of formalized or automated testing at any scope
Correction:
unit testing
integration testing
end-to-end testing
Symptoms:
"bug burn-down chart" goes up to the right rather than down
known issues keep getting bumped to "next sprint"
Cause: insufficient prioritization of existing issues
Correction: prioritize!
Symptoms:
newcomers to the code take "forever" to onboard
Time to First Meaningful Change
developer-facing API but no external documentation
documentation drift
Cause: documentation is not prioritized or is an afterthought
Correction: prioritize!
Symptoms:
"dangit, the server crashed again"
"what do you mean the system has been slow for three days?"
"Charlie left, great, now we have to go through and manually remove his access from everything."
Cause: insufficient infrastructure and automation; maintaining infrastructure takes a back seat
Correction:
move to the cloud
automation
monitoring tools
Symptoms:
authentication/authorization problems (e.g. weak passwords, lack of easy recovery)
compliance risks/churn (such as losing a deal to "lack of compliance")
offboarding automation (both customer and employee)
Cause: insufficient security measures or a lack of security awareness
Correction:
automated security testing
penetration testing
The "One Little Bit" Rule
Tactic: If you see something ugly, fix it while you are there
Rule: Never finish a ticket unless the code is clean enough for you to pass a code review on it the next day
Author: Andrew Hunt, The Pragmatic Programmer
The "Payback" Plan
Tactic: Don't just accrue debt. Budget time to pay it back.
Example: "For every 4 hours of feature development, we spend 1 hour refactoring."
Author: James Grenning, The Phoenix Project
Test-Driven Development (TDD)
Concept: Writing tests first forces you to think about the design of the code.
Benefit: It prevents creating debt because the code is designed to be testable.
Continuous Delivery
Concept: If you can't deploy your changes in an hour, your debt is too high.
Benefit: High deployment frequency forces you to keep code clean so you don't break production.
"The challenge developers are experiencing isn't shaped like a predictable increase in costs over time, it's...
... a loss of predictability,
... a loss of sustainability, and
... a loss of control."
"The lack of visibility--and the difficulty explaining the problems--makes it hard to communicate the severity of the situation, and often prevents the investment of time and resources that could make the situation better."
"The software industry urgently needs better conceptual foundations grounded in cognitive science--frameworks that could explain the developer’s experience in a way that does not require having lived it firsthand."
"By surfacing and naming the confusion experience inherent in troubleshooting in terms of neurological and attentional dynamics, our theory explains how prolonged troubleshooting can deplete cognitive resources and lead to cognitive fatigue. This reframes the mental strain developers are experiencing as a capacity constraint, rather than simply an emotion." --https://artystarr.com/blog/giving-developers-words
Your team's constant troubleshooting, regardless of what they're troubleshooting, is the interest on the decision/debt made earlier
This is what Nicole Forsgren calls "developer friction"
"Troubleshooting time becomes a leading indicator of sustainability risk and loss of control in software systems—because it reflects the developer’s ability to sustain understanding amid increasing complexity.
"Where the technical debt metaphor invites teams to locate problems in specific pieces of code, our theory suggests a broader, experience-oriented perspective: what matters is not just the state of the code, but how hard it is for developers to make sense of what the system is doing."
If your team has to constantly (re-)learn how the system is working, they're spending cycles learning rather than troubleshooting.
This has huge implications for coding-agent-generated code, too
Do you prefer cozy stories with insight laced and dripping throughout them?
https://www.softwareenchiridion.com/p/the-words-we-didnt-have
Treat "troubleshooting" as normal work, not exception-driven
Measure "restoration of understanding"
Create feedback loops around everything to allow for observation and experimentation
Look for "friction points" that can be removed without too much effort
Look for big "friction points" that take up a lot of developer cognition
Look for "friction points" that can be smoothed without requiring developer effort
Judge any tool by whether they preserve comprehension or muddy it
technical debt doesn't just happen; you made it happen
but that's not all bad (if you thought about it deliberately)
and even then some still happens regardless
but it's manageable (if you think about it responisbly)
Frictionless, by Forsgren, Noda; 2025; ISBN 978-1662966378
https://www.amazon.com/Frictionless-Remove-Barriers-Outpace-Competition/dp/1662966377
Software Design X-Rays, by Tornhill; 2018; ISBN 978-1680502725
https://www.amazon.com/Software-Design-X-Rays-Technical-Behavioral/dp/1680502727
Anything by W. Edwards Deming
best author on business and management you've never heard of
Subscription to Harvard Business Review (magazine)
100+ years old, and still a great source for ideas and inspiration on business and management
Cunningham, W. 1993. The WyCash portfolio management system.
ACM SIGPLAN OOPS Messenger 4(2): 29–30.
"Giving Developers Words"
https://artystarr.com/blog/giving-developers-words
"Theory of Troubleshooting: The Developer's Cognitive Experience of Overcoming Confusion"
https://dl.acm.org/doi/epdf/10.1145/3800945
https://arxiv.org/pdf/2602.10540
"From Technical Debt to Cognitive and Intent Debt: Rethinking Software Health in the Age of AI"
https://arxiv.org/pdf/2603.22106
"I propose a triple debt model for reasoning about software health, built around three interacting debt types: technical debt refers to problems in the code layer, cognitive debt refers to inadequate understanding across a team, and intent debt refers to a lack of externalized rationale, information that both humans and AI systems need to work safely and efficiently with the code. Technical debt makes systems harder to change. Cognitive debt makes systems harder to understand. Intent debt makes it difficult to know what the system is actually for."
"Technical Debt"
https://martinfowler.com/bliki/TechnicalDebt.html
"Technical Debt Quadrant"
https://martinfowler.com/bliki/TechnicalDebtQuadrant.html
"Technical Debt: The Man, the Metaphor, the Message"
https://neopragma.com/2019/03/technical-debt-the-man-the-metaphor-the-message/
Architect, Engineering Manager/Leader, "force multiplier"
http://www.newardassociates.com
http://blogs.newardassociates.com
Books
Developer Relations Activity Patterns (w/Woodruff, et al; APress, 2026)
Professional F# 2.0 (w/Erickson, et al; Wrox, 2010)
Effective Enterprise Java (Addison-Wesley, 2004)
SSCLI Essentials (w/Stutz, et al; OReilly, 2003)
Server-Based Java Programming (Manning, 2000)