Technical Debt Management and Refactoring Questions
Identifying, prioritizing, and paying down technical debt sustainably. Covers recognizing debt, making the case to invest in it, refactoring safely behind tests, and balancing debt reduction against feature velocity. Includes keeping a codebase maintainable over the long term.
You inherit a large technical debt backlog while maintaining strict SLOs. Propose a prioritization approach that balances small, high-impact reliability fixes against larger refactors, explain how you would allocate error budget toward debt remediation, how you would stage the work in production, and how you would define metrics that show progress and return on investment.
Sample Answer
Direct answer
With a large debt backlog and strict SLOs to maintain simultaneously, prioritize small, high-impact reliability fixes ahead of larger refactors, allocate a defined slice of error budget specifically to debt remediation (not ad hoc), and stage riskier work carefully so it can't itself become the incident that consumes the SLO it's trying to protect.
Structured elaboration
- Prioritization: rank debt items by SLO impact first (does this item directly threaten reliability) and size second, favoring several small, high-confidence reliability fixes over one large, uncertain refactor when both compete for the same limited budget, since small fixes have more predictable risk profiles.
- Error-budget allocation for remediation: reserve an explicit slice of the error budget for planned remediation work, so debt work has a legitimate, budgeted claim on risk tolerance rather than competing informally against the margin reserved for unplanned incidents.
- Staging work in production: any remediation with real production risk gets staged (canary, gradual rollout) with the SAME rigor as a feature launch, since "it's just a refactor, not new functionality" is a common but false justification for skipping staging discipline.
- Metrics for progress and ROI: track two separate things. For progress: the SLO compliance trend (is reliability actually improving as debt is paid down), the reserved-budget utilization (is remediation staying within its allocated slice), and the backlog's overall risk-weighted size (is the total risk surface shrinking, not just the item count). For ROI specifically: incident-response hours (or a standard dollar cost per incident-hour) avoided in the period after a fix ships, compared against the period before, divided by the engineer-time invested in that fix; this is what tells leadership whether the invested capacity is actually paying back in reduced incident cost, rather than assuming it is simply because the backlog is getting smaller.
Worked example
A backlog of 40 debt items against a 99.9% availability SLO with currently healthy budget headroom: prioritization surfaces 5 small items directly tied to the two SLO-threatening incidents from last quarter (highest priority, tackled first using a modest reserved-budget slice), while a much larger architectural refactor (addressing a broader but less acutely SLO-threatening set of items) is scheduled later, staged carefully with canary rollout once undertaken, specifically BECAUSE its larger blast radius makes it the item most likely to itself cause an SLO miss if rushed. For those 5 items, the ROI metric is reported explicitly alongside the SLO trend: engineer-time invested versus incident-response hours avoided in the following quarter compared to the quarter before, so the remediation's payback is visible as a number, not just implied by "the backlog shrank." Concretely: the 5 items took 3 engineer-weeks (120 hours) to fix; incident-response hours in the affected area dropped from 40 hours the quarter before to 10 hours the quarter after, a 30-hour reduction. At a fully-loaded cost of $85/engineer-hour, that's 30 * 85 = $2,550 in incident-response cost avoided against 120 * 85 = $10,200 invested, an ROI ratio of 30 / 120 = 0.25 (25%) of the invested cost recovered in the first quarter alone, a payback rate that keeps compounding in every subsequent quarter since the fix is permanent but the invested hours were one-time.
Trade-offs & pitfalls
The pitfall specific to an SRE context is treating debt remediation as inherently safe because it's "cleanup" rather than new feature work; a large refactor executed carelessly under SLO pressure can itself become the incident that burns the budget it was meant to protect, which is why staging discipline for remediation work needs to match, not fall below, the discipline applied to feature launches. A second pitfall specific to this question: reporting only progress/compliance metrics under an "ROI" label without an actual return-relative-to-investment figure lets the backlog look like it's succeeding even if the invested capacity isn't paying back in reduced incident cost.
Design an error-budget policy that explicitly incorporates technical-debt remediation windows for a platform team. Explain how planned remediation affects the error-budget calculation, how you would schedule remediation without harming SLAs, and how you would report exceptions and adjustments to stakeholders.
Sample Answer
Direct answer
Incorporate technical-debt remediation into an error-budget policy by treating planned remediation work as a scheduled, budgeted DRAW on the error budget (like a planned maintenance window), distinct from unplanned incidents, so debt work can proceed without silently eating into the margin reserved for genuine unplanned risk.
Structured elaboration
- Error-budget calculation with remediation windows: reserve a small, explicit slice of the error budget (for example 10-15%) specifically for planned remediation activity, calculated and tracked separately from the unplanned-incident portion, so a bad month of genuine incidents doesn't get blamed on debt work, and vice versa.
- Scheduling remediation without harming SLAs: schedule remediation windows during historically low-traffic periods where possible, and require any remediation activity with a plausible availability impact to have an explicit rollback plan and a pre-agreed abort threshold (if the reserved budget slice is exhausted mid-window, the remediation pauses, it doesn't continue into the unplanned-incident reserve).
- Reporting exceptions and adjustments: if a remediation window runs over its reserved budget, that's reported explicitly and separately from a genuine incident post-mortem, since the response and lessons are different (a scheduling/estimation problem, not a reliability failure), and any adjustment to future reserved allocation is based on that data.
Worked example
A platform team's monthly error budget is 43 minutes of downtime (99.9% SLO on a 30-day month). They reserve 6 minutes (about 14%) specifically for planned remediation activity, tracked in a separate ledger. A database migration planned as part of debt remediation is scheduled for a low-traffic window, budgeted for up to 4 minutes of expected brief unavailability; it runs slightly over at 5 minutes, still within the reserved 6-minute allocation, so no unplanned-incident budget is touched and no incident review is triggered, just a routine note in the remediation log. If it had run to 8 minutes, exceeding the reserved slice, the response is a scheduling/estimation retrospective specifically, not a reliability incident review, since the SLA breach traces to planned work exceeding its own budget, not to an unplanned failure.
Trade-offs & pitfalls
Without separating planned-remediation budget from unplanned-incident budget, teams either become too conservative about debt work (afraid any planned activity will look like it caused an SLA miss) or too cavalier about scheduling remediation (silently eating into the margin meant for real incidents); the explicit separation is what lets debt work proceed confidently within a reliability-conscious org.
What signals and telemetry would you monitor to detect accumulating technical debt across multiple teams and repositories? Name at least five, explain why each is useful, and what tooling you would use to collect it. Also explain how you would guard against teams gaming these metrics once they know they are being tracked.
Sample Answer
Direct answer
Monitor at least five signals: the trend (not just the snapshot) of cyclomatic complexity, the trend of test coverage, mean build and deploy time, PR size or review latency, and incident frequency. Each one is useful because it is a leading or lagging proxy for the thing you actually care about (developer velocity and system reliability), and together they cover code, process, and operational health rather than just one dimension.
Structured elaboration
| Signal | What it approximates | Why it's useful | Tooling |
|---|---|---|---|
| Cyclomatic complexity trend | How hard code is to reason about and test | Rising complexity predicts rising bug rate and slower changes | Static analysis (SonarQube, CodeClimate, radon) |
| Test coverage trend | How much of the system is safety-netted | Falling coverage predicts riskier changes and slower reviews | Coverage tools wired into CI (coverage.py, jacoco, istanbul) |
| Mean build and deploy time | Developer feedback loop speed | A slowing loop is often the earliest visible symptom of debt, before bugs show up | CI dashboards (GitHub Actions insights, Jenkins) |
| PR size or review latency | How safely work can be decomposed and reviewed | Growing PR size or review time signals coupling and unclear boundaries | Git provider analytics (GitHub Insights, LinearB) |
| Incident frequency | Real-world reliability cost of the debt | Ties abstract code metrics to concrete business impact | Incident tracker (PagerDuty, Opsgenie) |
For ML/AI-flavored teams, add training-time-per-epoch and retrain frequency as domain-specific analogues of build time and deploy frequency.
Worked example
A team's dashboard shows cyclomatic complexity flat for six months, test coverage dropping from 78% to 61% over the same period, and mean build time climbing from 6 to 14 minutes. None of these individually triggers an incident, but together they predict that the team's next quarter will show slower PR cycle time and a rising bug rate, roughly two months before that actually shows up in the incident tracker. That lead time is the entire point of tracking trends instead of point-in-time snapshots.
Trade-offs & pitfalls
The moment a metric becomes a target, people optimize the metric rather than the underlying thing it measures (Goodhart's law). Coverage percentage is the classic case: teams write low-value tests (asserting a getter returns what was just set) purely to move the number, without reducing real risk. Guard against this by pairing coverage with a second signal, such as mutation-testing score (deliberately inserting small bugs into the code and checking what fraction the test suite actually catches) or bug-escape rate, that is harder to game, and by treating any single metric as a conversation starter rather than a scorecard.
What is technical debt? Give a concise definition, then name the distinct categories of debt you would track separately, with one concrete example of each, how each typically accumulates, and at least one metric or signal you would collect per category so the debt is measurable, not just described.
Sample Answer
Direct answer
Technical debt is the implied cost of extra rework caused by choosing an easy or fast solution now instead of a better one that would take longer. Like a financial loan, it has a principal (the shortcut itself) and interest (the ongoing extra cost of building on top of it until it is paid down). It shows up in several distinct categories, and treating them as one blob is itself a common mistake.
Structured elaboration
The categories worth tracking separately, because they accumulate differently and need different owners:
| Category | What it looks like | Typical accumulation path | A signal to collect |
|---|---|---|---|
| Code debt | Duplicated logic, tangled functions, inconsistent style | Rushed features, copy-paste under deadline | Cyclomatic complexity, duplication percentage |
| Design/architecture debt | Wrong module boundaries, a component doing too much | Requirements drift past the original design | Cross-module dependency count, change-amplification (how many files a typical PR touches) |
| Test debt | Missing or shallow tests, brittle end-to-end suites | Skipping tests to hit a date | Test coverage delta, flaky-test rate |
| Infrastructure/build debt | Slow builds, manual deploys, outdated CI | Infra work deprioritized versus features | Build time trend, deploy frequency |
| Documentation/knowledge debt | Undocumented decisions, tribal knowledge | Single-owner components, high turnover | Time-to-first-PR for new hires, bus-factor per component |
Two of the signals above use terms worth defining plainly: cyclomatic complexity (roughly, how many independent decision paths run through a function; more branches and loops means a higher number) and bus-factor (how many people could leave the team before no one is left who understands this component). Each category needs its own signal because a healthy test-coverage number can coexist with severe architecture debt, and vice versa; a single composite "debt score" without category breakdown hides which lever to pull.
Worked example
A payments service might show: code debt (a 400-line processOrder function mixing validation, pricing, and persistence), design debt (the pricing logic is duplicated in the checkout service because there was no shared module), test debt (checkout has 40% coverage while the rest of the codebase averages 75%), and documentation debt (the only engineer who understands the tax-calculation edge cases left the company eight months ago). Four different categories, four different remediation owners and timelines, even though a single dashboard might report "technical debt: high" for the whole service.
Trade-offs & pitfalls
The most common mistake is treating debt as inherently bad. Deliberately taking on debt to hit a real deadline, with a plan to repay it, is a normal engineering trade-off, not a failure. The pitfall is debt taken on silently, with no tracking and no repayment plan, which is what actually causes long-term damage. A second pitfall is conflating technical debt with a bug: a bug is a defect against the current spec, while debt is a legitimate design choice that becomes more expensive to live with over time.
Design an organization-level technical debt dashboard that aggregates data from source control, CI, bug trackers, and runtime incidents across 100+ repositories and 20 teams. Describe the key metrics and visualizations, the data pipeline and update cadence, and how you would reduce alert fatigue so the dashboard stays actionable rather than noisy.
Sample Answer
Direct answer
An org-level debt dashboard needs three layers: source-of-truth data ingestion (source control, CI, bug trackers, incidents), a small set of aggregated, comparable metrics per repository, and a presentation layer tuned to reduce alert fatigue, since a dashboard nobody trusts is worse than no dashboard.
Structured elaboration
- Data pipeline: pull commits/PRs from source control, build/test results from CI, ticket data from the bug tracker, and incident data from the on-call system, on a nightly batch cadence for most signals (real-time isn't needed for a trend dashboard and adds unnecessary infrastructure cost).
- Key metrics, aggregated consistently across all 100+ repos: cyclomatic complexity trend, test coverage trend, mean build/deploy time, PR cycle time, and incident count, each rolled up per-repo and per-team, plus a composite score for at-a-glance ranking.
- Visualizations: a portfolio-level heat map (repos as tiles, color by composite score) for leadership's five-second scan, with drill-down per repo into the underlying metrics for engineers who need the detail. Avoid a single "debt: red/yellow/green" indicator with no drill-down path, since it invites disputes with no shared evidence.
- Update cadence: nightly for most metrics; incident data can be near-real-time since it's naturally low-volume and high-signal.
- Alert-fatigue reduction: alert only on TREND changes that cross a meaningful threshold (a repo's composite score moving into the worst quartile), not on every metric fluctuation; batch alerts into a weekly digest rather than firing individually; and let teams set their own repo-level thresholds within org-wide guardrails, since a threshold tuned for a payments service is wrong for an internal tooling repo.
Worked example
A 120-repo portfolio dashboard shows a heat map where 15 repos sit in the worst quartile. Rather than alerting on all 15 individually, the weekly digest surfaces only the 3 repos that NEWLY entered the worst quartile this week, since those are the actionable, novel signals; the other 12 are known, already-tracked debt that a standing prioritization process is already handling.
Trade-offs & pitfalls
The most common failure is over-alerting in the first month (every metric fluctuation fires a notification), which trains everyone to ignore the dashboard within weeks. Launch with alerts OFF, calibrate thresholds against a month of historical data first, and add alerting incrementally once the baseline noise level is understood.
Unlock Full Question Bank
Get access to all 7 Technical Debt Management and Refactoring interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.