The Computing Series

Exercises

Level 1 — Understand

1. What distinguishes technical debt from bad code? What makes the word “debt” precise as an analogy?

2. Describe the four quadrants of technical debt classification. Which is the only category the chapter describes as genuinely bad practice?

3. Name three concrete measures of technical debt described in the chapter. Why are abstract measures like “code quality” not actionable?

Level 2 — Apply

  1. Classify each of the following debt scenarios using the quadrant (deliberate/inadvertent × reckless/prudent): (a) A team skips writing tests to meet a launch deadline and intends to add them after; (b) An engineer uses a global variable for configuration because they do not know about dependency injection; (c) A team uses SQL string concatenation for queries instead of parameterised queries, not knowing about SQL injection risk; (d) A startup builds on a third-party authentication provider instead of building IAM, planning to replace it at 1M users.

  2. A payment module has been modified in 68% of all commits over the past year. Its test coverage is 12%. Three of the last five production incidents were in this module. Write a business-facing technical debt statement that explains the cost, the risk, and the proposed remediation — without using the words “refactoring”, “technical debt”, “code quality”, or “legacy”.

  3. A team says “we’ll fix it later” about a missing retry mechanism in their event consumer. Define the trigger conditions under which “later” becomes “now”. What observable business event would make the repayment urgent? How would you ensure the team revisits this debt item?

Level 3 — Design

  1. A SaaS application has accumulated four years of technical debt. Identify and prioritise debt in three categories: (a) safety-critical debt (causes data loss or security vulnerabilities); (b) velocity debt (slows feature development); (c) operational debt (increases incident frequency or duration). Design a 12-month repayment plan that balances debt reduction with ongoing feature development. Describe how you measure progress and how you prevent new debt from accumulating at the same rate.

A complete answer will: (1) give concrete examples in each category: safety-critical (unrotated API keys, no database backup verification, missing input validation on user-supplied SQL fragments); velocity (no abstractions over the database layer making test setup take 10 minutes, circular imports blocking refactoring); operational (no structured logging making incident investigation require SSH access, no health check endpoint causing load balancer routing to dead instances), (2) prioritise correctly: safety-critical debt is paid first (any data loss or security vulnerability takes precedence over velocity); operational debt that increases incident duration is paid before velocity debt (a 10-minute incident MTTR improvement has higher business value than a 10% faster CI pipeline), (3) design the 12-month plan as a percentage split: allocate 20% of each sprint to debt repayment with the remainder for feature development — safety-critical debt is handled as incidents (immediate, outside the 20% allocation); velocity debt is addressed in a rolling backlog sorted by impact (estimated developer hours saved per sprint); track progress by measuring the metrics associated with each debt item (CI test time, incident MTTR, mean time to add a new feature), and (4) prevent new debt accumulation: an architectural fitness function checks for known debt patterns on every PR (missing tests for new modules, new direct ORM calls in view layer, new hardcoded credentials in config files) — violations block merge; name FM8 (silent semantic drift) for unchecked debt accumulation and state the check frequency.

  1. A team is deciding whether to use a vendor-managed service (simpler now, locked in later) versus building their own solution (more work now, full control later). Frame this as a technical debt decision. Identify: what debt is being taken if the vendor is chosen, what the trigger for repayment would be, what the repayment cost would be, and what evidence would make the own-build decision correct instead. Use AT3 and AT7 in your analysis.

A complete answer will: (1) frame the vendor choice as a debt decision precisely: choosing the vendor is not free — it incurs vendor lock-in debt (code tightly coupled to vendor-specific APIs and data formats) and capability debt (features not available in the vendor become impossible without switching) in exchange for reduced build time; the debt is acceptable if the trigger condition for repayment is unlikely to occur within the expected service lifetime, (2) name AT3 (Simplicity/Flexibility): the vendor is simpler now (no infrastructure to manage, faster time to market) but reduces flexibility later (switching vendors requires rewriting all integration code); the own-build is more complex now but provides full flexibility — state the condition under which AT3 tips toward own-build: when the vendor’s constraints are already visible in the current requirements (e.g., the vendor does not support a data residency requirement that will be mandatory in 12 months), (3) name AT7 (Build/Buy) explicitly as the second governing tradeoff: buy gives faster time to market and outsourced operational burden; build gives full control and no vendor dependency — quantify the break-even point (at what monthly cost does the vendor’s pricing exceed the engineering cost of maintaining an equivalent own-build), and (4) state the evidence that makes own-build correct: the vendor’s pricing will exceed the break-even within 24 months at projected scale; the vendor cannot satisfy a known future regulatory requirement; the capability gap is in a core differentiator of the product (never buy core differentiators); or the vendor’s reliability SLA is below the team’s own availability target.

Read in the book →