Work Methodologies DefinedTerm

Technical Debt (Debito Tecnico)

Conosciuto anche come: Tech Debt, Code Debt, Design Debt, Debito Tecnico

Costo implicito del rework futuro necessario quando si sceglie una soluzione rapida ma limitata invece di un approccio più robusto.

Updated: 2026-01-04

Definizione

Technical Debt (debito tecnico) è metafora coniata da Ward Cunningham nel 1992 per descrivere il costo futuro implicito di rework necessario quando team di sviluppo scelgono soluzioni rapide, incomplete o sub-ottimali invece di approcci più robusti ma time-consuming. Come il debito finanziario, il technical debt accumula “interessi”: ogni modifica futura costa di più perché deve lavorare attorno a design inadeguato.

La metafora è potente: prendere debito tecnico può essere decisione razionale (accelerare feature critica per deadline), ma va “ripagato” intenzionalmente tramite refactoring, altrimenti gli interessi crescono fino a paralizzare development. Il codice diventa progressivamente più difficile da modificare, i bug aumentano, velocity diminuisce.

Technical debt non è solo “bad code”: include architectural shortcut, test coverage insufficiente, dependency obsolete, documentazione mancante, infrastruttura fragile. È qualsiasi scelta che privilegia short-term speed su long-term maintainability.

Tipologie di Technical Debt (Quadrante di Fowler)

Martin Fowler classifica technical debt in matrice 2x2:

Reckless (sconsiderato) vs. Prudent (prudente)

Reckless Debt: preso senza awareness delle conseguenze. “Non abbiamo tempo per design”. Tipicamente risultato di incompetenza o pressure estremo.

Prudent Debt: decisione consapevole di tradeoff. “Shippiamo ora, refactoriamo next sprint”. Richiede disciplina nel ripagarlo.

Deliberate (deliberato) vs. Inadvertent (inadvertente)

Deliberate Debt: scelta intenzionale. Es: usare quick-and-dirty solution per validare feature, poi rewrite se successful.

Inadvertent Debt: scoperto retrospettivamente. “Ora capiamo come avremmo dovuto farlo”. Frutto di learning.

I quattro quadranti:

  1. Reckless-Deliberate: “Non abbiamo tempo per fare bene” → worst case, evitare
  2. Reckless-Inadvertent: “Cos’è layering?” → incompetenza, risolvere con training
  3. Prudent-Deliberate: “Dobbiamo shippare ora, deal con consequences” → acceptable se ripagato
  4. Prudent-Inadvertent: “Ora sappiamo come fare meglio” → inevitabile, parte di learning

Come si manifesta

Sintomi visibili

Velocity decrescente: ogni sprint, il team completa meno story point. Più tempo speso a “combattere il codice” che creare valore.

Increasing bug rate: più tech debt, più surface area per bug. Fixes in una area causano regression in altra.

Fear of changing code: “Non tocchiamo quel modulo, è fragile”. Team evita refactoring per paura di rompere tutto.

Longer onboarding: new hire impiega settimane a capire codebase per accidental complexity, non domain complexity.

Build/deploy fragility: CI/CD pipelines che falliscono random, deploy manuale perché automation non è trusted.

Fonti comuni

Shortcut architetturali: monolith quando serviva microservices, sync quando serviva async, SQL quando serviva NoSQL (o viceversa).

Test debt: code coverage sotto 50%, no integration test, no automated regression. “Testiamo manualmente”.

Dependency debt: librerie outdated con security vulnerability. “Se funziona, non toccare”.

Documentation debt: codice senza commenti, API senza spec, architettura non documentata. Tribal knowledge.

Infrastructure debt: manual provisioning, no IaC, single point of failure, no monitoring.

Misurazione e prioritizzazione

Quantificare tech debt

Code quality metrics: SonarQube, CodeClimate misurano code smells, complexity, duplication. Target: meno di 5% duplication, cyclomatic complexity sotto 15.

Test coverage: JaCoCo, Coverage.py. Target: oltre 80% line coverage, oltre 70% branch coverage per critical path.

Dependency freshness: Dependabot, Renovate. Metriche: % di dependency outdated, severity di vulnerabilità (CVE score).

DORA metrics proxy: lead time for changes, deployment frequency. High tech debt correlato con slower lead time.

Developer survey: quarterly survey “quanto tech debt ti rallenta? (scala 1-10)”. Qualitativo ma utile.

Prioritizzare il ripagamento

Non tutto il tech debt va ripagato. Prioritizzare basandosi su:

Pain × Frequency: codice modificato spesso e doloroso ha massima priorità. Codice legacy non toccato può rimanere.

Business criticality: debt in payment flow > debt in admin dashboard usato 1x/mese.

Compound interest: debt che genera altro debt (es: mancanza di CI/CD genera deployment debt) va risolto prima.

Enabler for strategy: se vuoi scalare 10x, architectural debt diventa critico anche se oggi non fa male.

Gestione pratica

Strategie di ripagamento

Dedicare capacity: allocare 15-20% di sprint velocity a tech debt. Es: se team ha 50 story point/sprint, 10 punti per tech debt.

Boy Scout Rule: “lascia il codice più pulito di come l’hai trovato”. Ogni PR include micro-refactoring opportunistico.

Tech debt sprints: ogni 4-5 sprint di feature, 1 sprint dedicato a debt paydown. Controverso, può creare silos.

Strangler fig pattern: per big rewrites, gradualmente sostituire old system con new, mantenendo entrambi in parallel durante transizione.

Stop taking new debt: prima di ripagare, smettere di accumulare. Enforce quality gate in CI (code coverage, linting).

Rendere visible

Tech debt backlog: items separati nel backlog con tag “tech-debt”. Transparent per Product Owner.

Debt ratio metric: tracciare % di tempo speso su tech debt vs. feature. Visualizzare trend.

Architectural Decision Records (ADR): documentare deliberate debt: “Abbiamo scelto X invece di Y perché…, pianifichiamo revisione in 6 mesi”.

Incident retrospective: dopo outage, identificare tech debt che ha contribuito. Crea urgency per ripagamento.

Considerazioni pratiche

Product Owner buy-in: PO deve capire che velocity sostenibile richiede debt paydown. Mostrare trend: velocity diminuisce se ignoriamo debt.

Non perfectionism: goal non è zero debt, ma sustainable level. Too much refactoring è premature optimization.

Bilanciamento: startup early-stage può accumulare deliberate debt per speed. Mature product deve privilegiare maintainability.

Evitare big rewrites: “Dobbiamo riscrivere tutto da zero” raramente funziona. Preferire incremental refactoring.

Technical debt è inevitabile: software evolve, requirement cambiano, tecnologie migliorano. Anche perfect code diventa debt quando context shift.

Fraintendimenti comuni

”Technical debt significa codice scritto male”

Parzialmente. Include anche architectural debt (design che non scala), test debt (mancanza di automation), infrastructure debt (manual process), documentation debt. Un codice pulito in architettura inadeguata è tech debt.

”Basta non prendere tech debt”

Impossibile e controproducente. Prudent deliberate debt accelera learning e time-to-market. Il problema è non ripagarlo. Zero debt significa over-engineering e paralisi decisionale.

”Il refactoring risolve automaticamente il tech debt”

No. Refactoring riduce code debt, ma non architectural debt (serve redesign), non test debt (serve scrivere test), non dependency debt (serve upgrade). Serve strategia multi-pronged.

”Tech debt è problema solo degli sviluppatori”

Falso. Impatta business: slower feature delivery, più outage, difficoltà hiring (good developer evitano legacy mess), customer churn da bug. È problema di product, non solo engineering.

Termini correlati

Fonti