> John knew his code had a few bugs. But nearing the deadline, another project appeared and it took a lot of John’s time, so he couldn’t go back and fix the problems.
This is a problem, but this is not inherently technical debt. That's just delivering a bad/incomplete feature (Not necessarily John's fault if he's been asked to make changes). Code with Technical debt works or mostly works, but relies on non-maintainable or less ideal than patterns.
Simplified example. Adding a "Cancel" Button to a form. This button involves adding a new "secondary" class style to the button.
* Technical Debt - Button is in place. Works correctly. Instead of a <Button> component and tweaking it to handle the new "secondary" class. John simply copies and pastes the <Button> code directly into the implementation.
* Bug/Bad Feature - John references the button correctly, but fails to handle certain state resets properly when the form is cancelled.
-----
The prior is technical debt because it works correctly, but doesn't follow a good pattern or does something unexpected (refactoring that button will be much, much harder). The latter is likely just bad code.
The case where the latter is not bad code is if the company has made an intentional decision to not handle cancel edge cases. Even here, I would argue that is product debt - not technical debt.
----
Every software product in the world has debt. Just like every software product in the world has bugs. You need to account for your debt as you grow. Otherwise it will eat you.