Engineering · Best Practices

Technical Debt: Nhận Diện, Đo Lường Và Trả Nợ Kỹ Thuật

Technical Debt - Nhận diện 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 InadvertentPrudent 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).

Quản lý Technical Debt với BanhCuonFlow

Track tech debt tasks, sprint planning, KPIs và code review — engineering team management trong 1 platform.