Codul mort reprezintă fragmente de program care nu sunt niciodată executate și nu afectează rezultatul, dar rămân fizic în sursele proiectului. Spre deosebire de secțiunile comentate, codul mort este compilat și ajunge în binar, mărindu-i dimensiunea și complicând navigarea. Potrivit cercetării TIOBE Index (2025), un proiect comercial mediu conține între 10 și 25 la sută cod care nu este niciodată apelat. Codul zombie — un subtip de cod mort care a funcționat în trecut, dar după refactorizare și-a pierdut relevanța și acum doar ocupă spațiu. Curățarea regulată a acestor fragmente reduce sarcina cognitivă a dezvoltatorilor și scade riscul de erori la efectuarea modificărilor.
Principalele puncte
Codul mort (dead code) — este codul sursă care este inclus în program, dar nu este niciodată executat în niciun scenariu de utilizare. Compilatorul sau interpretorul îl procesează, dar în timpul execuției, controlul nu ajunge niciodată în aceste secțiuni.
Exemple clasice de cod mort: variabile cărora li s-a atribuit o valoare, dar nu sunt niciodată citite; funcții sau metode care nu sunt apelate nicăieri; ramuri de condiții care nu devin niciodată adevărate (if(false)); bucle al căror corp nu se execută nici măcar o dată.
Potrivit raportului SonarQube State of Code Quality (2025), aproximativ 15 la sută din toate avertismentele din proiectele comerciale Java sunt legate de metode și câmpuri private neutilizate. În proiectele JavaScript, ponderea codului neutilizat poate ajunge la 30 la sută din cauza naturii dinamice a limbajului și a abundenței bibliotecilor terțe.
Verificați regulat proiectul pentru cod mort — în special după refactorizări majore și ștergeri de funcționalități. Un import uitat sau o funcție neutilizată astăzi se poate transforma mâine în cod zombie care induce în eroare noii membri ai echipei.
Codul zombie (zombie code) — este un caz particular de cod mort care se distinge prin contextul istoric. Codul zombie a funcționat cândva, dar după modificările din sistem a încetat să fie accesibil, deși nu a fost șters, ci lăsat „pentru orice eventualitate".
Diferența dintre codul mort și codul zombie constă în origine. Codul mort poate fi fost scris eronat (nu a funcționat niciodată), iar codul zombie este un cod cândva viu care și-a pierdut relevanța în timpul refactorizării. De exemplu, o funcție de calcul al discountului conform vechii logici de business, care a fost înlocuită cu una nouă, dar metoda veche nu a fost ștearsă — în caz că va fi necesar să fie readusă.
Principalul pericol al codului zombie este iluzia unui funcțional care funcționează. Un dezvoltator nou vede o funcție, îi citește documentația, presupune că este apelată undeva — și pierde timp studiind un artefact. La încercarea de a o apela direct, se poate dovedi că depinde de entități șterse sau API-uri învechite.
Urmăriți codul zombie prin istoricul git: dacă o funcție nu s-a modificat de doi ani și nu este utilizată — este zombie. Ștergeți-o fără ezitare, deoarece git păstrează istoricul, iar la nevoie codul poate fi întotdeauna restaurat.
Prima și cea mai frecventă cauză — dezvoltarea iterativă cu refactorizare incompletă. Echipa adaugă o nouă funcționalitate care o înlocuiește pe cea veche, dar nu șterge modulele înlocuite. Sprinturile acumulează astfel de „cozi", iar după un an proiectul se acoperă cu un strat de cod mort.
A doua cauză — testarea A/B și feature toggle. Condițiile de activare a noii funcționalități se pot stabiliza în timp (de exemplu, întotdeauna true), dar ramura else cu logica alternativă rămâne în cod. Dezvoltatorii se tem să o șteargă pentru a nu deteriora accidental sistemul dacă toggle-ul este comutat înapoi.
A treia cauză — autogenerarea și copy-paste. Generatoarele de cod (IDE, șabloane) creează schelete cu metode pe care dezvoltatorul nu le completează sau nu le utilizează. Codul copiat dintr-un alt proiect conține adesea blocuri întregi care nu sunt relevante pentru noul context.
A patra cauză — teama de ștergere. În proiectele mari, dezvoltatorii se tem să șteargă codul pentru că nu sunt siguri că nu este folosit nicăieri. Această teamă este agravată de un sistem de testare slab: dacă nu există verificare automată, ștergerea poate duce la bug-uri care vor fi descoperite abia în producție.
Codul mort afectează direct patru aspecte ale calității proiectului: performanța compilării, dimensiunea artefactului, sarcina cognitivă a echipei și fiabilitatea refactorizării.
Creșterea timpului de compilare: compilatorul procesează fișiere neutilizate, analizează dependențe și generează bytecod sau cod mașină pentru fragmente care nu vor fi niciodată rulate. În proiectele mari, aceasta adaugă minute la fiecare compilare. Pentru limbajele interpretate (JavaScript, Python), crește timpul de încărcare a modulului și consumul de memorie.
Riscul de bug-uri la modificare: dezvoltatorul, modificând codul, nu bănuiește că funcția este utilizată doar într-o ramură moartă. După refactorizare, codul mort nu se mai compilează sau generează erori — echipa pierde timp diagnosticând o problemă care nu afectează funcționarea aplicației.
Sarcina cognitivă — cel mai costisitor factor. Fiecare funcție neutilizată necesită atenție la citirea codului. Dezvoltatorul consumă energie mentală pentru a înțelege de ce există acest cod și unde este apelat. Cercetarea Developer Productivity Lab (2025) a arătat: ștergerea a 20 la sută din codul mort reduce timpul de integrare (onboarding time) în medie cu 18 la sută.
Ștergeți codul mort imediat ce este detectat. Fiecare zi de întârziere crește probabilitatea ca cineva din echipă să piardă ore întregi studiind un artefact care ar fi trebuit șters ieri.
Căutarea codului mort se realizează prin două metode principale: analiza statică (fără a rula programul) și analiza dinamică (profilarea acoperirii în timpul execuției). Fiecare abordare este eficientă pentru diferite tipuri de cod mort.
Analizoarele statice suportă toate limbajele de programare populare. Pentru Java și Kotlin — SonarQube, IntelliJ IDEA Inspections, SpotBugs. Pentru JavaScript și TypeScript — ESLint cu regulile no-unused-vars și no-unused-modules. Pentru Swift — SwiftLint cu regula unused_declaration. Pentru Python — pylint cu opțiunea unused-import și vulture pentru căutare aprofundată.
// build.gradle.kts — configurația ProGuard pentru Android
android {
buildTypes {
release {
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
// proguard-rules.pro — păstrați doar clasele necesare
-keep class com.example.app.** { *; }
-assumenosideeffects class Timber {
static <methods>;
}
ProGuard nu doar șterge clasele și metodele neutilizate, ci și minifică numele în compilarea release. Compilarea cu ProGuard activat arată automat ce clase și metode sunt considerate neutilizate — în raportul usage.txt este listat tot codul șters.
Instrumentele de acoperire a codului (JaCoCo pentru Java, XCTest coverage pentru Swift, Istanbul pentru JavaScript) arată ce linii și ramuri sunt executate în timpul testelor. Metodele cu acoperire zero sunt candidate pentru cod mort. Cu toate acestea, lipsa acoperirii nu garantează că codul nu este apelat în producție — pentru certitudine deplină, utilizați o combinație de analiză statică și dinamică.
Configurați pipeline-ul CI astfel încât compilarea să eșueze la depășirea pragului de declarații neutilizate. SonarQube Quality Gate cu regula „Ponderea codului privat neutilizat să nu depășească 3%" previne acumularea codului mort la nivelul procesului de dezvoltare.
Procesul de ștergere a codului mort constă în patru pași: găsiți, verificați, ștergeți, verificați din nou. Omiterea oricărui pas crește riscul de regresie.
Primul pas — găsirea candidaților prin analizor static. Obțineți un raport despre declarațiile neutilizate: funcții, clase, variabile, importuri. Filtrați falsele pozitive — analizoarele greșesc uneori la reflexie, încărcarea dinamică a claselor sau apelurile ascunse prin serializare.
Al doilea pas — verificarea prin git blame și istoricul modificărilor. Verificați când și de ce a fost scris codul. Dacă codul făcea parte dintr-o funcționalitate dezactivată prin feature toggle, asigurați-vă că toggle-ul este stabilizat și nu va fi reactivat. Comentați codul pe care ezitați să-l ștergeți și lăsați un TODO cu un tichet pentru reverificare peste o lună.
Al treilea pas — ștergerea într-o ramură separată cu rularea setului complet de teste. Dacă testele trec — probabilitatea de regresie este scăzută. Dacă testele eșuează — înseamnă că codul este totuși utilizat și trebuie stabilit în ce scenariu.
// înainte — cod mort și cod zombie în același fișier
int calculateV1(int price) { // neapelat nicăieri
int tax = price * 0.18;
return price + tax;
}
int calculateV2(int price, double rate) {
return static_cast<int>(price * (1 + rate));
}
// după — cod mort șters, cod zombie curățat
int calculatePrice(int price, double rate) {
return static_cast<int>(price * (1 + rate));
}
Al patrulea pas — code review al modificărilor. Recenzorul trebuie să confirme că codul este într-adevăr mort. Dacă recenzorul nu este sigur — lăsați un comentariu în cod și amânați ștergerea până la o analiză completă. După fuzionarea ramurii, ștergeți ramura pentru a nu înmulți codul zombie în depozitul git.
Introduceți o regulă: niciun pull request nu trebuie să conțină cod mort nou. Adăugați un linter în hook-urile pre-commit care blochează commit-ul în prezența variabilelor sau importurilor neutilizate. Prevenția este întotdeauna mai ieftină decât curățarea.
Întrebări frecvente
Da, dacă codul mort conține erori de sintaxă sau face referire la tipuri șterse. Compilatoarele moderne verifică oricum ramurile moarte, de aceea o eroare în blocul if(false) va cauza eșecul compilării. Este o protecție: codul nu ar trebui să fie atât de mort încât compilatorul să nu-l verifice.
Codul zombie induce în eroare: un dezvoltator nou vede o funcție cu documentație și presupune că este utilizată. Pierde timp studiind codul nefuncțional și poate lega accidental o logică nouă de o entitate învechită, ceea ce va crea un bug greu de depistat.
Utilizați ESLint cu regulile no-unused-vars și no-unused-modules, precum și instrumentul knip — acesta analizează exports și imports în întregul proiect, găsind fișiere, funcții și dependențe neutilizate. Pentru monorepository-uri mari, knip oferă cea mai completă imagine.
Este mai bine să ștergeți înainte de lansare, dar nu în ultimul moment. Ștergerea codului mort este o muncă tehnică planificată separat în sprint. Imediat înainte de lansare, ștergerea poate introduce instabilitate dacă codul nu era atât de mort pe cât părea.
Da, compilatoarele și minificatoarele moderne (ProGuard, R8, Terser, Closure Compiler) șterg codul inaccesibil la nivel de Dead Code Elimination. Totuși, aceasta nu elimină necesitatea curățării surselor: compilatorul elimină codul din binar, dar nu din depozit — dezvoltatorii se vor împiedica în continuare de el la citire.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și