What is technical debt and when is it worth taking on?
Technical debt is the accumulated cost of choosing an expedient implementation over a better one. The metaphor, coined by Ward Cunningham, is precise and worth taking seriously: you borrow time now and pay interest in the form of slower future work, until you repay the principal by refactoring.
The interest is the important part. Debt is not simply "bad code". It is code whose shortcomings impose an ongoing tax on every subsequent change — more time to understand, more places to update, more bugs, more testing. Code that is ugly but never touched again costs nothing.
Cunningham's original meaning was narrower than common usage. He described shipping to learn, with the explicit intent of revising once you understood the problem better. Deliberately incurring debt to gain knowledge is a strategy; accidentally incurring it through carelessness is not the same thing, though both are now called technical debt.
A useful classification distinguishes deliberate versus inadvertent and prudent versus reckless:
Deliberate and prudent — "we ship now and deal with the abstraction after launch." This is legitimate and often correct.
Deliberate and reckless — "we don't have time for design."
Inadvertent and prudent — "now we know how we should have built it." This is unavoidable and arguably the most common kind.
Inadvertent and reckless — the team did not know better.
When taking it on is right: validating an unproven idea, a genuine deadline with real consequences, code in a part of the system unlikely to change, or where you do not yet understand the domain well enough to design properly. Building the wrong abstraction early is more expensive than building none.
When it is not: in core abstractions everything depends on, in security and data integrity, and when you have no intention of repaying it.
Track it explicitly — untracked debt compounds silently until velocity collapses.