Technical Debt: Nhận Diện, Đo Lường Và Trả Nợ Kỹ Thuật
Ward Cunningham coined "technical debt" năm 1992: "Shipping first-time code is like going into debt. A little debt speeds development but interest makes it expensive." Theo McKinsey 2024, 20-40% giá trị enterprise technology bị tiêu hao bởi technical debt — tương đương $1.52 nghìn tỷ USD chi phí bảo trì toàn cầu (Stripe Developer Report). Technical debt không chỉ là code xấu — nó là bất kỳ quyết định kỹ thuật nào tăng chi phí bảo trì trong tương lai: missing tests, hardcoded values, tightly coupled modules, outdated dependencies, undocumented APIs, và "tribal knowledge" chỉ 1 người biết.
Phân Loại Technical Debt
Martin Fowler phân loại tech debt theo 2 trục: Deliberate vs Inadvertent và Prudent vs Reckless. Hiểu phân loại giúp chọn đúng chiến lược trả nợ.
🎯 Intentional (Cố ý)
"Ship nhanh MVP, refactor sau." Chấp nhận shortcut có ý thức — hardcode config thay vì build settings page, skip unit tests để kịp deadline. Okay nếu: documented, có timeline trả nợ, stakeholders aware. Ví dụ: startup cần ship feature tuần này, kế hoạch refactor sprint sau — prudent deliberate debt.
😅 Accidental (Vô ý)
Developer không biết best practice. Senior không review. Copy-paste Stack Overflow mà không hiểu. Tạo debt mà không nhận ra. Dangerous nhất: nowhere documented, nobody knows it exists. Fix: strong code review culture, mentoring, pair programming.
📦 Bit Rot (Mòn dần)
Dependencies outdated, frameworks deprecated, best practices evolved. Code "tốt" 3 năm trước giờ là "legacy." Ví dụ: jQuery code trong era React, callbacks trong era async/await. Unavoidable — technology evolves. Cần budget liên tục cho upgrades.
🏗️ Environment Debt
Build scripts unreliable, CI/CD flaky (random failures), dev environment setup mất 2 ngày, no staging environment, manual deployment steps. Thường bị bỏ qua nhất nhưng impact productivity toàn team → multiplier effect lớn.
Đo Lường Technical Debt
"You can't manage what you can't measure." Đây là lý do nhiều team không trả nợ — vì không thấy nó. Các metrics quantify tech debt thành con số business hiểu:
Cycle Time trend: Thời gian từ commit đến deploy. Sprint 1: deploy 3 ngày. Sprint 10: deploy 2 tuần. Trend tăng = debt accumulating — mỗi feature cần more workarounds, more regression testing, more manual steps. DORA metrics: elite teams deploy multiple times/day, low performers deploy monthly.
Bug Rate per Sprint: Bugs/sprint tăng + feature velocity giảm = hệ thống brittle. Thiếu tests, coupling cao, "fix 1 chỗ broke 3 chỗ khác." Track ratio: bugs fixed vs bugs introduced. Healthy ratio: < 0.5 (fix 2 bugs, introduce < 1 new).
Code Coverage trend: Mỗi feature mới thêm 500 LOC + 0 tests. Coverage giảm từ 80% → 45% trong 6 tháng. Mỗi refactoring giờ là gamble — no safety net. Onboarding Time: Dev mới cần bao lâu để productive? 1 tuần → healthy codebase. 2 tháng → quá phức tạp, thiếu docs, quá nhiều "tribal knowledge." Code Churn: Files thay đổi liên tục (> 20 commits/tháng) = hotspots. Hotspots correlated with high bug density — focus refactoring vào đây.
4 Chiến Lược Trả Nợ
① Boy Scout Rule: "Leave the code cleaner than you found it." Mỗi PR cải thiện 1 thứ nhỏ: rename confusing variable, extract helper function, add missing test case, update outdated comment. Không cần sprint riêng cho refactoring — tích lũy dần mỗi ngày. Compound effect: 1 small improvement/PR × 10 PRs/week × 50 weeks = 500 improvements/year.
② 20% Rule: Allocate 20% capacity mỗi sprint cho tech debt. 4 ngày features + 1 ngày refactoring. Google (20% time), Spotify (hack time), Atlassian (ShipIt days) đều áp dụng biến thể. BanhCuonFlow team: mỗi Friday là "tech debt Friday" — dev chọn debt item từ backlog, refactor, submit PR.
③ Tech Debt Sprint: Khi debt tích lũy quá nhiều (critical mass), dành 1 sprint (2 tuần) cho pure refactoring. Risky vì stakeholders thấy "0 features shipped." Communicate ROI rõ ràng, bằng số cụ thể: "Sau refactoring, build time giảm 70%, deploy errors giảm 90%, feature development speed tăng 40% từ sprint sau."
④ Strangler Fig Pattern: Thay vì rewrite toàn bộ (Big Bang — 85% failure rate), wrap legacy code bằng new interfaces. Dần dần replace từng phần — legacy shrinks, new system grows. BanhCuonFlow: migrate từ stored procedures sang EF Core queries — mỗi sprint migrate 2-3 queries, giữ backward compatibility, zero downtime.
Communicate với Non-Technical Stakeholders
Không nói "code cũ xấu quá, cần rewrite." Nói: "Feature X mà bạn muốn cần 3 tuần thay vì 3 ngày, vì chúng tôi phải work around legacy code. Nếu refactor trước (1 tuần), feature tương tự trong tương lai chỉ mất 2 ngày." Stakeholders hiểu ngôn ngữ business: time, cost, risk. Translate tech debt sang business impact — development slowdown costs, production incident frequency, talent retention (devs quit projects với overwhelming tech debt).