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.
Product requests a last-minute improvement for launch with a two-week deadline, and you must decide what technical debt and compromises are acceptable. List the decision criteria you would use, short-term mitigations to reduce the long-term risk, how you would document the debt you incur, and a remediation timeline to resolve it after launch.
Sample Answer
Direct answer
Under a genuine two-week deadline, decide acceptable compromises with explicit criteria (is the shortcut isolated and reversible, does it touch anything safety- or compliance-critical), apply short-term mitigations that bound the risk rather than eliminate it, document exactly what was skipped and why, and commit to a specific post-launch remediation timeline rather than an open-ended "later."
Structured elaboration
- Decision criteria: is the affected code path isolated (low blast radius) or does it touch critical infrastructure shared by other features? Is the shortcut reversible (can it be feature-flagged off if something goes wrong) or does it lock in a hard-to-undo decision (a schema change, a public API shape)? Does it touch anything with compliance or safety implications, where "acceptable" bars are much lower regardless of deadline pressure?
- Short-term mitigations: if skipping full validation testing, add a targeted monitoring alert on the specific failure mode most likely to occur; if skipping a scalability concern, add a hard rate limit or circuit breaker so a worst-case failure is contained rather than cascading.
- Documentation: what specifically was skipped, the reasoning, and the acceptance criteria from step 1, filed as a ticket at launch time, not reconstructed from memory afterward.
- Remediation timeline: a specific date (typically the very next sprint, given the urgency that created this debt in the first place), owned by name, reviewed regardless of whether other priorities have since emerged.
Worked example
A checkout-redesign launch under a two-week deadline: the team skips full regression coverage on a secondary, low-traffic payment path (saved-card autofill) and ships with full coverage on only the two highest-traffic payment paths. Given this touches a customer-facing payment flow (a moderate-to-high stakes category, though not classified as a hard compliance blocker in this case), the mitigation is a monitoring alert on the error rate for that specific payment path in production, and the documented remediation is the full regression suite completed and reviewed within the next sprint, owned by name, with an explicit note that if the monitoring alert fires before then, the affected path is disabled immediately regardless of the sprint boundary.
Trade-offs & pitfalls
The pitfall in any monitoring-as-mitigation plan is treating "we'll monitor it" as sufficient without a genuinely actionable trigger; a monitoring alert that nobody's specifically on the hook to act on the moment it fires is not meaningfully different from no monitoring at all, so the trigger needs an owner and a predefined action (pause the launch or disable the affected path), not just visibility.
Design a debt gate policy for pull requests that prevents merges which would increase a repository's technical debt beyond defined thresholds. Define which thresholds you would enforce (for example a coverage delta, a complexity delta, or a security-scan failure), the enforcement mechanism, an exception flow, and how you would measure whether the gate is effective without creating a delivery bottleneck.
Sample Answer
Direct answer
A debt gate policy needs explicit, defensible thresholds tied to the same signals a quality gate would use, a lightweight but real exception flow for legitimate edge cases, and an effectiveness measurement that tracks both whether debt actually stopped accumulating AND whether the gate became a delivery bottleneck, since a gate that succeeds at one and fails at the other isn't actually working.
Structured elaboration
- Thresholds: a coverage-delta floor on touched files, a complexity-delta ceiling, and a hard block on any new critical/high-severity security-scan finding, each threshold set from a baseline period of observed data rather than an arbitrary round number, so the org can defend why 5% coverage drop is the line and not 3% or 10%.
- Enforcement mechanism: an automated CI check that blocks merge, with the specific violated threshold and value reported directly in the PR, not a vague "debt gate failed" message.
- Exception flow: a designated role (a tech lead or a small review group) can approve an override, required to log a specific reason, visible in the PR history; the override isn't a silent bypass, it's a tracked, auditable decision that itself becomes data (a team overriding the gate frequently on a specific threshold is a signal that threshold may be miscalibrated for that context, like a legacy file everyone already knows is below the bar).
- Measuring effectiveness without creating a bottleneck: track two things together: the trend in the underlying metrics the gate protects (is coverage/complexity actually stabilizing or improving org-wide) AND the override rate and PR cycle-time impact (is the gate adding meaningful delay or friction). A gate succeeding on the first measure while override rate climbs toward 50% isn't actually working, since the threshold has effectively become optional.
Worked example
Six months post-launch: org-wide coverage-delta violations dropped from 22% of PRs in month 1 to 6% by month 6 (the gate is working as intended, teams are adapting), median PR cycle time increased by only 4 minutes (the gate's CI check overhead, a negligible bottleneck), and the override rate sits steady at 3% (mostly legitimate cases like intentional dead-code removal), not climbing over time. This combination, improving compliance, minimal cycle-time cost, and a low, stable override rate, is what "working without creating a bottleneck" looks like in the data, distinguishing it from a gate that's either being routinely bypassed or genuinely slowing delivery.
Trade-offs & pitfalls
The pitfall specific to this question is measuring only the compliance trend and declaring success, without also tracking the override rate and delivery-speed cost; a gate that's "succeeding" because everyone has learned to override it whenever it's inconvenient is not actually preventing debt, it's just adding friction with no real enforcement.
You must decide whether to rewrite or incrementally refactor a system suffering from memory leaks and frequent restarts. Outline a decision framework that includes discovering what the system actually does today, cost estimation, risk profiling, a rollback plan, testing requirements for either path, and a stakeholder communication plan.
Sample Answer
Direct answer
For a system with memory leaks and frequent restarts, don't jump to a rewrite: first characterize what the system actually does today (since "suffering from memory leaks" is a symptom, not necessarily evidence the whole design is wrong), estimate cost and risk for both paths, and require a rollback plan and testing strategy before committing either way.
Structured elaboration
- Discover current behavior first: profile the memory leak specifically (which allocation pattern, which code path) before assuming it requires a full rewrite; many "the whole system is broken" symptoms trace to a small number of specific, fixable causes (an unclosed resource handle, an unbounded cache) that an incremental fix resolves without touching the rest of the design.
- Cost estimation for both paths: incremental fix cost is usually estimable directly (profile, patch, verify); rewrite cost requires estimating re-implementation of every behavior the current system has, which is systematically harder to estimate accurately precisely because some of that behavior isn't documented anywhere except the existing code.
- Risk profiling: a rewrite of a serving system carries cutover risk (a new set of bugs, however well-tested) on top of whatever risk motivated the rewrite; an incremental fix carries lower cutover risk but the possibility the underlying design genuinely can't be patched into good health.
- Rollback plan: for the incremental path, ship the fix behind a flag or as a small, independently revertible commit, so a bad patch can be pulled within minutes without redeploying the rest of the service; for the rewrite path, keep the old implementation live and swappable (a feature flag or traffic split) for a defined post-cutover window, with an explicit automatic trigger (a crash-rate or memory-growth threshold) that forces a revert to the old path rather than relying on a judgment call made under incident pressure.
- Testing requirements for either path: for the incremental path, a load test that specifically reproduces the leak pattern, run before and after the fix, to prove it's actually resolved rather than just less frequent; for the rewrite path, a full behavioral parity test suite built from the current system's observed behavior.
- Stakeholder communication: state the finding from step 1 plainly, since "we profiled it and found a specific fixable cause" is a much easier sell than "we need to rewrite this" and should be the default recommendation whenever the profiling supports it.
Worked example
Profiling reveals the memory leak traces to a single connection pool that isn't releasing connections on a specific error path, present in roughly 15% of requests under load. That's a targeted, incremental fix (patch the error-handling path, add a regression test that specifically exercises it under load), not evidence the serving layer's overall design is unsound. The frequent restarts are a symptom of this one leak, not of pervasive architectural rot, so the decision framework correctly routes to incremental refactor once the discovery step is done, even though the initial framing ("suffering from memory leaks and frequent restarts") sounded like a case for a rewrite.
Trade-offs & pitfalls
The pitfall this question is testing is reacting to a scary-sounding symptom (frequent restarts) with a scary-sounding fix (full rewrite) without first doing the cheap diagnostic work that, in a large fraction of real cases, reveals a narrower, more tractable root cause.
Describe a decision checklist you would use before deliberately accepting new technical debt to meet a launch date, for example by skipping some integration tests. Include the criteria to evaluate, which stakeholders must sign off, what documentation you would require (including a repayment plan), and the maximum lifespan you would allow the accepted debt to have before it must be revisited.
Sample Answer
Direct answer
A decision checklist for deliberately accepting debt needs four things: explicit criteria for what makes debt acceptable right now, a named sign-off from both engineering and the business stakeholder requesting the deadline, required documentation including a repayment plan, and a hard maximum lifespan after which the debt must be revisited regardless of other priorities.
Structured elaboration
- Criteria to evaluate: is the affected area isolated (low blast radius if something goes wrong) or does it sit on a critical path? Is the shortcut reversible (can it be safely undone if it causes problems) or does it lock in a hard-to-change decision? What's the realistic worst case if this debt is never paid down?
- Required sign-off: both an engineering lead (confirming the technical risk assessment) and the business stakeholder driving the deadline (confirming they understand and accept the trade-off, not just that they want the date met), so the acceptance isn't a unilateral engineering decision nor a business decision made in ignorance of the risk.
- Required documentation: what specifically is being skipped, why, the acceptance criteria from step 1, and a repayment plan with an owner and target date, filed as a ticket at the moment of acceptance.
- Maximum allowed lifespan: a hard date (not "soon") after which the debt is automatically escalated for review regardless of competing priorities; a common default is one quarter for most debt, shorter for anything touching a critical or customer-facing path.
Worked example
A team wants to skip load-testing a new endpoint to hit a launch date. Checklist walkthrough: isolated (yes, new endpoint, no existing traffic depends on it) and reversible (yes, can be feature-flagged off); worst case if debt persists is a capacity incident under unexpectedly high launch-day traffic. Sign-off: engineering lead confirms the technical risk is bounded given current traffic projections, and the product stakeholder explicitly acknowledges the capacity risk in writing. Documentation: ticket filed noting the skipped load test, owner assigned, repayment (running the load test) scheduled for the following sprint. Maximum lifespan: two weeks, shorter than the default quarter, because this item touches a customer-facing launch path.
Trade-offs & pitfalls
A checklist with no enforcement mechanism (no actual sign-off required, no automatic escalation at the lifespan deadline) becomes theater that gets rubber-stamped under the same deadline pressure it's meant to check; the maximum-lifespan escalation needs to be automated (a bot, a recurring calendar review) rather than relying on someone remembering to revisit it.
You are planning a data model refactor that touches customer records and carries a risk of data loss or inconsistency. Design a risk analysis and mitigation plan, including testing approaches such as canaries and shadow writes, reconciliation checks, backup strategy, a rollback plan, and how you would communicate the risk to stakeholders during the migration.
Sample Answer
Direct answer
A data model refactor touching customer records needs a risk plan built around never trusting a single write path during the transition: use shadow writes or dual writes to validate the new schema against real traffic before cutting reads over, reconcile continuously rather than only at the end, and keep a tested rollback path available at every stage.
Structured elaboration
- Testing approach: shadow writes first (write to both old and new schema, but only read from and serve the old one), comparing outputs to catch discrepancies with zero customer-facing risk; only after a clean shadow-write period, consider a canary of real reads against the new schema for a small internal or low-risk user segment.
- Reconciliation checks: an automated job comparing old and new schema data continuously during the dual-write period, alerting on any divergence immediately rather than discovering it only at final cutover, since a divergence caught early is a bug to fix, while one discovered at cutover is a potential data-loss incident.
- Backup strategy: a verified, tested-restorable backup of the pre-migration state taken immediately before any schema change begins, not assumed to exist from routine backup processes that may not have been validated against this specific scenario.
- Rollback plan: since this is dual-write, rollback at any point before full cutover is just "stop reading from the new schema and continue serving from old," cheap and low-risk; define explicitly how far into the process rollback remains cheap versus when it becomes genuinely costly (typically once the OLD schema stops being written to, which should be the very last step, done only after full confidence).
- Stakeholder communication: a clear timeline shared with stakeholders showing each stage (shadow write start, reconciliation period, canary read, full cutover, old-schema decommission) so nobody is surprised by the pace, and a clear escalation path if reconciliation ever shows a divergence.
Worked example
Week 1-2: dual writes begin (new schema populated alongside old, old schema remains source of truth for reads); automated reconciliation runs hourly, comparing a sample of records. Week 3: reconciliation shows a 0.02% divergence rate, traced to a timezone-handling difference between old and new write paths, fixed and re-verified before proceeding (not glossed over as "close enough"). Week 4: canary read migration for 1% of traffic (internal tooling users first), verified for a week with no customer impact. Week 5-6: gradual read migration to 100%, keeping dual writes active as an active rollback path. Week 7-8: two full weeks of 100% reads from the new schema with zero incidents, the soak period before committing to cutover. Week 9: old-schema writes finally stop, the point of no easy return, executed last and deliberately.
Trade-offs & pitfalls
The single most dangerous mistake in this kind of migration is treating reconciliation as a one-time final check rather than a continuous, running safeguard throughout the transition; a divergence caught on day 3 of dual-writes is a minor bug fix, the same divergence undiscovered until final cutover on week 9 is a customer-data incident.
Unlock Full Question Bank
Get access to all 21 Technical Debt Management and Refactoring interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.