📁 Sangam Dhakal - Portfolio v2.0 - Netscape Navigator 4.0
_
□
×

๐Ÿ“š Interview question

How do you manage technical debt as a senior engineer: identifying it, prioritising it and getting time to pay it down?

Technical debt quadrants, making debt visible, measuring interest, prioritising with business impact, debt registers, capacity allocation and communicating with product owners.

Senior Behavioral Advanced design-judgment prioritisation stakeholder-management technical-debt

๐ŸŽฏ Key points

  • Technical debt is the future cost of a shortcut; the interest is the extra effort it causes each change
  • Fowler's quadrant: deliberate or inadvertent, prudent or reckless
  • Make it visible in a register with impact, interest and owner
  • Prioritise by interest paid (change frequency, incidents, delay) not by ugliness
  • Communicate in business terms: lead time, incidents, risk, cost
  • Pay down continuously (capacity share, boy-scout rule) and tie big items to features

โฑ 30-second answer

Technical debt is the future cost of a shortcut, and the interest is the extra effort or risk it adds every time we work near it. I make it visible in a debt register with each item's impact, how often we pay its interest (change frequency, incidents, delays) and a rough cost to fix. I prioritise by interest, not by how ugly the code is: debt in a hotspot that slows every feature beats a messy module nobody touches. I get time by explaining it in business terms (lead time, incident risk, cost), by reserving a steady share of capacity, and by pairing debt fixes with features that touch the same area.

๐Ÿ—ฃ Full answer (senior)

How I would answer this in an interview

"Technical debt is the future cost of a shortcut or an outdated decision. Ward Cunningham's metaphor works best when you keep both halves. The principal is what it costs to fix. The interest is the extra effort, delay or risk we pay every time we work near it. That distinction drives everything I do. I identify debt with evidence: Git hotspots (churn ร— complexity), incident post-mortems, lead time per area, developer surveys, dependency and vulnerability scans, and .NET support lifecycle dates. I record it in a register with impact, interest, risk, rough fix cost and an owner. I prioritise by interest and risk, not ugliness: debt in a hotspot that slows every pricing feature beats a messy module nobody touches, and an out-of-support runtime with a date beats both. I get time by speaking business, not code quality: 'this adds three days to each pricing feature; we ship eight a quarter, so it costs 24 days a quarter, and fixing it takes 15'. Then I pay it down continuously (a steady capacity share, boy-scout fixes in code we touch, larger items bundled with related features) and prevent new debt with a definition of done, automated tests, architecture tests and automated dependency updates."


1. Kinds of debt

Fowler's technical debt quadrant:

Prudent Reckless
Deliberate "Ship now, refactor next sprint" (recorded, with a trigger) "No time for design"
Inadvertent "Now we know how it should have been" "What's layering?"

Other common forms: out-of-support runtimes (.NET Framework, end-of-life .NET versions), vulnerable/outdated packages, missing tests, missing observability, manual deployments, architecture that no longer fits the product or team structure, and documentation drift.

2. The process

Step What I do
Identify Hotspots, incidents, DORA metrics, surveys, dotnet list package --outdated --vulnerable --include-transitive, lifecycle dates
Record Register entry: description, area, interest (days/quarter or incidents), risk, fix cost, owner, trigger
Prioritise Interest ร— frequency + risk (security, compliance, end-of-support dates) relative to fix cost
Communicate Lead time, incident risk, cost of delay, deadlines; offer options
Pay down Steady capacity share ([15โ€“20%]), boy-scout rule, bundle with related features, funded projects for big items
Prevent Definition of done, code review, architecture tests, Renovate/Dependabot, CI gates on critical vulnerabilities

3. Prioritisation matrix

Interest Cost to fix: low Cost to fix: high
High Do now Plan and fund (with dates)
Low Boy-scout when nearby Record and leave

Risk overrides: anything with a security/compliance deadline (end of support, critical CVE) jumps the queue regardless of interest.

4. Talking to product owners

Avoid Say instead
"The code is terrible" "Pricing features take 3 extra days each; that's 24 days a quarter"
"We need a cleanup sprint" "15 days of work pays back in under a quarter"
"It's best practice to upgrade" "Support ends on [date]; after that, security patches stop and our [customer] audit fails"
One option Options: fix now, fix with feature X, or accept the risk explicitly (and record who accepted it)

Production example

Our [order service] ran on an out-of-support .NET version with [14] vulnerable packages. Earlier upgrade requests had been framed as "code quality" and kept losing to features. When a customer security questionnaire flagged unsupported software, I reframed it as a security and compliance risk with a date and a cost: the vulnerabilities, the end-of-support date, the audit finding, and a [six-week] plan. It was approved. We upgraded project by project to .NET 10 LTS (using the .NET Upgrade Assistant and multi-targeting where needed), fixed the vulnerable packages, and added Renovate plus a CI gate that fails on critical vulnerabilities. Lifecycle dates now live in the debt register, so the next upgrade is planned, not urgent.

๐Ÿ” What the interviewer is checking

Checks leadership, prioritisation and stakeholder communication.

Green flags

  • Distinguishes principal and interest.
  • Prioritises with evidence (hotspots, incidents, support dates).
  • Communicates in business terms and offers options.
  • Describes continuous paydown and prevention.

Red flags

  • "We need a rewrite."
  • Debt only discussed among engineers with no plan.

๐Ÿ“š Learn in depth

1. Origin of the metaphor

Ward Cunningham (1992) introduced "technical debt" to explain to business stakeholders why shipping early with imperfect understanding is fine if you repay it by refactoring as you learn. The metaphor was about learning, not about permission to write sloppy code. Martin Fowler's quadrant later separated prudent/reckless and deliberate/inadvertent debt.

2. Principal vs interest

Meaning Example
Principal One-off cost to fix 15 days to split the pricing god class
Interest Recurring cost of not fixing 3 extra days per pricing feature; 2 incidents a quarter
Payback period Principal รท interest per period 15 รท 24 per quarter โ‰ˆ 0.6 quarters

High-principal, low-interest debt (messy code nobody touches) can stay. Low-principal, high-interest debt should go first.

3. Evidence sources

Source Shows
Git churn ร— complexity (hotspots) Where interest is paid most often
DORA metrics (lead time, change failure rate, MTTR) Delivery drag and instability
Incident tags by component Reliability interest
Build/test duration trends Feedback-loop interest
dotnet list package --vulnerable --include-transitive Security risk
.NET support policy Deadlines: LTS releases supported 3 years; STS releases 24 months (since .NET 9)
Developer surveys Where people avoid working

4. Keeping a debt register useful

  • Lives where the team plans work (backlog label, not a forgotten wiki page).
  • Each entry: area, description, interest (quantified, even roughly), risk, fix estimate, owner, trigger ("when we next change pricing" or "before [date]").
  • Reviewed regularly (e.g. monthly) with product owners.
  • Closed items celebrated with measured outcomes (lead time down, incidents down).

5. Paying down without stopping delivery

Mechanism Best for
Boy-scout rule Small improvements in code you're already changing
Steady capacity share Medium items; predictable progress
Bundle with features Debt in the area a feature touches ("refactor pricing as part of loyalty discounts")
Funded project with dates Runtime upgrades, architecture migrations
Stop-the-line Critical vulnerabilities, data-loss risks

6. Prevention

  • Definition of done includes tests, observability and docs where relevant.
  • Code review checks for recorded shortcuts.
  • Architecture tests keep boundaries from eroding.
  • Renovate/Dependabot keep packages current in small steps.
  • CI fails on critical vulnerabilities and outdated target frameworks.
  • Deliberate shortcuts are logged with an owner and trigger the moment they're taken.

7. Try it yourself

  1. Run dotnet list package --vulnerable --include-transitive and --outdated on your solution.
  2. List your top three hotspots from Git history.
  3. Write one register entry with interest in days per quarter and a payback period.
  4. Check the support end date of every runtime you deploy.
  5. Draft the business-language explanation for your top item and test it on a non-engineer.

๐Ÿ’ป Code

// A lightweight debt register entry model used to score and sort the backlog.
var register = new List<DebtItem>
{
    new("Pricing god class", Area: "Pricing", InterestDaysPerQuarter: 24, FixDays: 15, Risk: Risk.Medium),
    new("Out-of-support runtime", Area: "Orders", InterestDaysPerQuarter: 2, FixDays: 30, Risk: Risk.Critical),
    new("Messy CSV importer", Area: "Admin", InterestDaysPerQuarter: 0.5, FixDays: 10, Risk: Risk.Low)
};

foreach (var item in register.OrderByDescending(d => d.Score))
    Console.WriteLine($"{item.Score,6:F1}  {item.Title} ({item.Area}) payback {item.PaybackQuarters:F1} quarters");

public enum Risk { Low = 1, Medium = 2, High = 4, Critical = 8 }

public sealed record DebtItem(string Title, string Area, double InterestDaysPerQuarter, double FixDays, Risk Risk)
{
    // Interest paid per year, weighted by risk, relative to cost to fix.
    public double Score => (InterestDaysPerQuarter * 4 + (int)Risk * 5) / FixDays * 10;
    public double PaybackQuarters => InterestDaysPerQuarter > 0 ? FixDays / InterestDaysPerQuarter : double.PositiveInfinity;
}

The exact formula matters less than making interest and risk explicit and comparable.

โš  Common mistakes

1. Asking for a "cleanup sprint"

What happens: all messy code labelled debt; a vague request for time. Why it is wrong: sounds like gold-plating; rarely approved or finished. Do instead: specific items with interest, risk and payback, funded steadily.

2. Prioritising by ugliness

What happens: effort goes to the code that offends engineers most. Why it is wrong: often code that rarely changes, so little return. Do instead: prioritise hotspots and dated risks.

3. Technical language with business stakeholders

What happens: "coupling", "god class", "SOLID violations". Why it is wrong: they can't weigh it against features. Do instead: lead time, incidents, cost, deadlines, options.

4. Ignoring support dates

What happens: runtimes and packages drift out of support. Why it is wrong: quiet debt becomes urgent security/compliance risk. Do instead: track lifecycle dates; automate dependency updates.

5. Unrecorded deliberate shortcuts

What happens: "we'll fix it later" with no ticket. Why it is wrong: nobody remembers; interest compounds. Do instead: log each shortcut with an owner and trigger.

6. Proposing a rewrite

What happens: "it's beyond saving". Why it is wrong: high risk, long freeze, lost behaviour. Do instead: incremental refactoring with strangler fig / branch by abstraction.

7. Debt discussed only among engineers

What happens: frustration without a plan or a decision-maker involved. Why it is wrong: no funding, no accountability. Do instead: review the register with product owners regularly.

8. Treating all debt as bad

What happens: refusing any shortcut under deadline pressure. Why it is wrong: prudent, deliberate debt can be the right business call. Do instead: take it consciously, record it, plan repayment.

9. No measurement after paydown

What happens: improvements made but not shown. Why it is wrong: the next request lacks credibility. Do instead: report outcomes (lead time, incidents, build time).

10. Letting accepted risk go unowned

What happens: "we'll live with it" with no named decision-maker. Why it is wrong: when it bites, nobody knew it was a choice. Do instead: record who accepted the risk and when to revisit.

๐Ÿ› Senior insight: trade-offs

Seniors manage debt like a financial portfolio: some debt is a sensible loan, some is ruinous. The skill is quantifying interest, communicating it in business terms, and paying it down without stopping delivery.

Debt type Typical strategy
Hotspot code design Refactor with related features
End-of-support runtime Dated plan, treated as security work
Vulnerable packages Automate updates; fix critical immediately
Missing tests Add with each change to the area
Architecture misfit ADR, phased migration
Low-churn messy code Record and leave

๐Ÿ”— Follow-ups the interviewer may ask

  1. When: Candidate pays down a large debt item Why: Probes refactoring execution
    How to answer

    I treat a large refactoring as a series of small, behaviour-preserving steps merged to main continuously, not a big-bang branch. First I pin current behaviour with characterisation tests. Then I pick a technique: strangler fig to route traffic piece by piece to a new implementation, branch by abstraction to put an interface in front of the old code and swap implementations behind it, or parallel change (expand, migrate, contract) for APIs and database schemas. Feature flags and shadow comparisons let old and new paths run side by side. I prioritise hotspots (code that changes often and hurts), keep refactoring commits separate from feature commits, and define an end state so it does not drag on forever.

  2. When: Candidate lists over-complex design as debt Why: Checks over-engineering detection
    How to answer

    Over-engineering is complexity that today's requirements do not justify. I detect it through symptoms with numbers behind them: a one-field change touching many files, interfaces with one implementation, configuration options nobody sets, patterns like CQRS or event sourcing without the problems they solve, and microservices that always deploy together. I reverse it incrementally rather than with a rewrite: inline single-use abstractions, merge layers that only pass data through, consolidate services that share a release cycle, and delete unused options, each step behind tests. I also address why it happened, because otherwise it grows back.

  3. When: Candidate mentions architecture misfit Why: Moves to evolutionary architecture
    How to answer

    Evolutionary architecture (Ford, Parsons and Kua) is architecture designed to support guided, incremental change, rather than a fixed upfront design. The key tool is fitness functions: automated checks that protect the characteristics you care about, such as dependency rules (architecture tests), latency budgets, or startup time, run in CI or production. Around that, I keep boundaries modular (often a modular monolith first), make decisions reversible where possible and defer irreversible ones to the last responsible moment, record decisions in ADRs, and rely on continuous delivery, feature flags and observability so each change is small and safe.

๐Ÿ›  Real-world problems: how you handle them

Out-of-support runtime reframed as security risk
Situation
An [order] service ran on an out-of-support .NET version with [14] vulnerable packages.
Signals
Security scan failures; a customer security questionnaire flagged unsupported software.
Investigation
Inventory of runtime versions and vulnerable dependencies across services.
Resolution
Presented as compliance risk with dates; incremental upgrade to .NET 10 LTS; Renovate for package updates.
Prevention
Lifecycle dates tracked in the debt register; CI fails on critical vulnerabilities.

How to tell it (STAR)

Our order service was on an unsupported .NET version with [14] vulnerable packages, and earlier requests to upgrade had been framed as code quality. I reframed it as a security and compliance risk with a deadline and a cost, and got [six] weeks approved. We upgraded project by project to .NET 10 and automated package updates so it does not happen again.

โ†ฉ Usually asked after

More in Senior-Level Judgment

Last updated 31 Oct 2026.

๐ŸŒ Sangam's Webring

โช Previous ๐Ÿ  Main Next โฉ
๐Ÿ’ฌ Chat with me