Dode code en zombiecode in ontwikkeling: wat het is, oorzaken en zoeken

Auteur: IT Sectr Gepubliceerd: 2026-07-26 Leestijd: 10 min

Dode code zijn programfragmenten die nooit worden uitgevoerd en het resultaat niet beïnvloeden, maar fysiek in de bronbestanden van het project blijven. In tegenstelling tot uitgecommentarieerde delen wordt dode code gecompileerd en komt het in de binair terecht, waardoor de omvang toeneemt en de navigatie wordt bemoeilijkt. Volgens TIOBE Index (2025) bevat een gemiddeld commercieel project 10 tot 25 procent code die nooit wordt aangeroepen. Zombiecode — een subtype van dode code dat in het verleden werkte, maar na refactoring zijn relevantie verloor en nu alleen maar ruimte inneemt. Regelmatig opschonen van dergelijke fragmenten vermindert de cognitieve belasting van ontwikkelaars en verlaagt het risico op fouten bij het aanbrengen van wijzigingen.

Belangrijkste punten

  • Dode code — fragmenten die nooit worden uitgevoerd, maar in het project blijven.
  • Zombiecode — code die eerder werd uitgevoerd, maar na wijzigingen onbereikbaar werd.
  • Dode code vergroot de binaire omvang, de bouwtijd en de cognitieve belasting van het team.
  • Belangrijkste zoekinstrumenten: statische analyse (SonarQube, ESLint) en dekkingsprofilers.
  • Het veilig verwijderen van dode code gebeurt via testdekking controleren en code review van wijzigingen.

Wat is dode code?

Dode code (dead code) — broncode die in het programma is opgenomen, maar in geen enkel gebruiksscenario wordt uitgevoerd. De compiler of interpreter verwerkt het, maar tijdens de uitvoering komt de besturing nooit in deze delen terecht.

Klassieke voorbeelden van dode code: variabelen waaraan een waarde is toegekend maar die nooit worden gelezen; functies of methoden die nergens worden aangeroepen; conditietakken die nooit waar worden (if(false)); lussen waarvan het lichaam geen enkele keer wordt uitgevoerd.

Volgens het rapport SonarQube State of Code Quality (2025) heeft ongeveer 15 procent van alle waarschuwingen in commerciële Java-projecten betrekking op ongebruikte private methoden en velden. In JavaScript-projecten kan het aandeel ongebruikte code oplopen tot 30 procent vanwege de dynamische aard van de taal en de overvloed aan bibliotheken van derden.

Controleer het project regelmatig op dode code — vooral na grote refactorings en het verwijderen van functies. Een vergeten import of ongebruikte functie kan morgen veranderen in zombiecode die nieuwe teamleden op het verkeerde spoor zet.

Verschillen tussen dode code en zombiecode

Zombiecode (zombie code) — een speciaal geval van dode code dat zich onderscheidt door historische context. Zombiecode werkte ooit, maar na wijzigingen in het systeem werd het onbereikbaar, hoewel het niet werd verwijderd maar “voor het geval dat” werd achtergelaten.

Het verschil tussen dode code en zombiecode zit in de oorsprong. Dode code kan per ongeluk zijn geschreven (nooit gewerkt), terwijl zombiecode voorheen levende code is die tijdens refactoring zijn relevantie verloor. Bijvoorbeeld een functie voor het berekenen van korting op basis van oude bedrijfslogica die is vervangen door nieuwe, maar de oude methode is niet verwijderd — voor het geval deze terug moet worden gezet.

Het grootste gevaar van zombiecode is de illusie van werkende functionaliteit. Een nieuwe ontwikkelaar ziet een functie, leest de documentatie, neemt aan dat deze ergens wordt aangeroepen — en verspilt tijd aan het bestuderen van een artefact. Bij een poging deze direct aan te roepen, kan blijken dat deze afhankelijk is van verwijderde entiteiten of verouderde API’s.

Volg zombiecode via de git-geschiedenis: als een functie twee jaar niet is gewijzigd en niet wordt gebruikt — is het zombie. Verwijder het zonder aarzeling, want git bewaart de geschiedenis en indien nodig kan de code altijd worden hersteld.

Oorzaken van het ontstaan van dode code

De eerste en meest voorkomende oorzaak — iteratieve ontwikkeling met onvolledige refactoring. Het team voegt nieuwe functionaliteit toe die de oude vervangt, maar verwijdert de vervangen modules niet. Sprints hopen dergelijke “staarten” op en na een jaar is het project bedekt met een laag dode code.

De tweede oorzaak — A/B-testen en feature toggle. De voorwaarden voor het inschakelen van een nieuwe functie kunnen na verloop van tijd worden gefixeerd (bijvoorbeeld altijd true), maar de else-tak met alternatieve logica blijft in de code. Ontwikkelaars zijn bang deze te verwijderen om het systeem niet per ongeluk te breken als de toggle terug wordt gezet.

De derde oorzaak — autogeneratie en copy-paste. Codegeneratoren (IDE, sjablonen) maken sjablonen met methoden die de ontwikkelaar niet invult of gebruikt. Code die uit een ander project is gekopieerd, bevat vaak hele blokken die niet relevant zijn voor de nieuwe context.

De vierde oorzaak — angst voor verwijdering. In grote projecten zijn ontwikkelaars bang om code te verwijderen omdat ze niet zeker weten of deze echt nergens wordt gebruikt. Deze angst wordt versterkt door een zwak testsysteem: als er geen geautomatiseerde controle is, kan verwijdering leiden tot bugs die pas in productie worden ontdekt.

Waarom dode code gevaarlijk is

Dode code heeft direct invloed op vier aspecten van de projectkwaliteit: compilatieprestaties, artefactgrootte, cognitieve belasting van het team en betrouwbaarheid van refactoring.

Toename van compilatietijd: de compiler verwerkt ongebruikte bestanden, analyseert afhankelijkheden en genereert bytecode of machinecode voor fragmenten die nooit worden uitgevoerd. In grote projecten voegt dit minuten toe aan elke build. Voor geïnterpreteerde talen (JavaScript, Python) neemt de laadtijd van de module en het geheugengebruik toe.

Risico op bugs bij wijziging: een ontwikkelaar die code wijzigt, vermoedt niet dat de functie alleen in een dode tak wordt gebruikt. Na refactoring compileert de dode code niet meer of geeft fouten — het team verspilt tijd aan het diagnosticeren van een probleem dat de werking van de applicatie niet beïnvloedt.

Cognitieve belasting — de duurste factor. Elke ongebruikte functie vereist aandacht bij het lezen van code. Een ontwikkelaar besteedt mentale energie aan het begrijpen waarom deze code bestaat en waar deze wordt aangeroepen. Onderzoek van Developer Productivity Lab (2025) toonde aan: het verwijderen van 20 procent dode code verkort de inwerktijd (onboarding time) gemiddeld met 18 procent.

Verwijder dode code onmiddellijk na detectie. Elke dag uitstel vergroot de kans dat iemand van het team uren besteedt aan het bestuderen van een artefact dat gisteren al verwijderd had moeten worden.

Hulpmiddelen voor het vinden van dode code

Het vinden van dode code gebeurt met twee hoofmethoden: statische analyse (zonder het programma uit te voeren) en dynamische analyse (dekkingsprofilering tijdens uitvoering). Elke aanpak is effectief voor verschillende soorten dode code.

Statische analyzers ondersteunen alle populaire programmeertalen. Voor Java en Kotlin — SonarQube, IntelliJ IDEA Inspections, SpotBugs. Voor JavaScript en TypeScript — ESLint met regels no-unused-vars en no-unused-modules. Voor Swift — SwiftLint met regel unused_declaration. Voor Python — pylint met optie unused-import en vulture voor diepgaand zoeken.

Voorbeeld van zoeken in Kotlin via ProGuard

groovy
// build.gradle.kts — ProGuard-configuratie voor Android
android {
    buildTypes {
        release {
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

// proguard-rules.pro — bewaar alleen vereiste klassen
-keep class com.example.app.** { *; }
-assumenosideeffects class Timber {
    static <methods>;
}

ProGuard verwijdert niet alleen ongebruikte klassen en methoden, maar minificeert ook namen in de release-build. Een build met ProGuard ingeschakeld laat automatisch zien welke klassen en methoden als ongebruikt worden beschouwd — in het rapport usage.txt staat alle verwijderde code vermeld.

Dynamische analyse via testdekking

Code-dekkingsinstrumenten (JaCoCo voor Java, XCTest coverage voor Swift, Istanbul voor JavaScript) tonen welke regels en takken tijdens tests worden uitgevoerd. Methoden met nuldekking zijn kandidaten voor dode code. Het ontbreken van dekking garandeert echter niet dat de code niet in productie wordt aangeroepen — gebruik voor volledige zekerheid een combinatie van statische en dynamische analyse.

Configureer de CI-pipeline zo dat de build faalt wanneer de drempel van ongebruikte declaraties wordt overschreden. SonarQube Quality Gate met de regel “Aandeel ongebruikte private code niet meer dan 3%” voorkomt ophoping van dode code op het niveau van het ontwikkelproces.

Hoe dode code veilig te verwijderen

Het verwijderingsproces van dode code bestaat uit vier stappen: vinden, controleren, verwijderen, opnieuw controleren. Het overslaan van een stap verhoogt het risico op regressie.

Eerste stap — zoek kandidaten via een statische analyzer. Verkrijg een rapport over ongebruikte declaraties: functies, klassen, variabelen, imports. Filter vals-positieven — analyzers maken soms fouten bij reflectie, dynamisch laden van klassen of verborgen aanroepen via serialisatie.

Tweede stap — controleer via git blame en wijzigingsgeschiedenis. Bekijk wanneer en waarom de code is geschreven. Als de code deel uitmaakte van een functie die is uitgeschakeld via feature toggle, zorg er dan voor dat de toggle is gefixeerd en niet opnieuw wordt ingeschakeld. Commenteer code waarvan je twijfelt of je deze moet verwijderen en laat een TODO achter met een ticket voor hercontrole over een maand.

Derde stap — verwijder in een aparte branch met het uitvoeren van de volledige testsuite. Als tests slagen — is de kans op regressie laag. Als tests falen — betekent dit dat de code toch wordt gebruikt en moet worden vastgesteld in welk scenario.

cpp
// voor — dode code en zombiecode in hetzelfde bestand
int calculateV1(int price) { // nergens aangeroepen
    int tax = price * 0.18;
    return price + tax;
}

int calculateV2(int price, double rate) {
    return static_cast<int>(price * (1 + rate));
}

// na — dode code verwijderd, zombiecode opgeschoond
int calculatePrice(int price, double rate) {
    return static_cast<int>(price * (1 + rate));
}

Vierde stap — code review van wijzigingen. De reviewer moet bevestigen dat de code echt dood is. Als de reviewer niet zeker is — laat dan een commentaar in de code achter en stel verwijdering uit tot volledige analyse. Na het mergen van de branch, verwijder de branch om te voorkomen dat zombiecode zich vermenigvuldigt in de git-repository.

Voer een regel in: geen enkele pull request mag nieuwe dode code bevatten. Voeg een linter toe aan pre-commit hooks die de commit blokkeert bij ongebruikte variabelen of imports. Preventie is altijd goedkoper dan opschonen.

Veelgestelde vragen

Kan dode code compilatiefouten veroorzaken?

Ja, als dode code syntaxfouten bevat of verwijst naar verwijderde types. Moderne compilers controleren nog steeds dode takken, daarom veroorzaakt een fout in een if(false)-blok een weigering van de build. Dit is een bescherming: code mag niet zo dood zijn dat de compiler deze niet controleert.

Waarom is zombiecode gevaarlijk voor nieuwkomers in het team?

Zombiecode is misleidend: een nieuwe ontwikkelaar ziet een functie met documentatie en neemt aan dat deze wordt gebruikt. Hij verspilt tijd aan het bestuderen van niet-werkende code en kan per ongeluk nieuwe logica koppelen aan een verouderde entiteit, wat een moeilijk te traceren bug oplevert.

Hoe vind ik dode code in een JavaScript-project?

Gebruik ESLint met regels no-unused-vars en no-unused-modules, en de tool knip — deze analyseert exports en imports in het hele project en vindt ongebruikte bestanden, functies en afhankelijkheden. Voor grote monorepo’s geeft knip het meest complete beeld.

Is het de moeite waard om dode code voor een release te verwijderen?

Het is beter om voor de release te verwijderen, maar niet op het laatste moment. Het verwijderen van dode code is technisch werk dat apart in de sprint wordt gepland. Vlak voor een release kan verwijderen instabiliteit introduceren als de code niet zo dood bleek als het leek.

Helpen compilers bij het automatisch verwijderen van dode code?

Ja, moderne compilers en minificatoren (ProGuard, R8, Terser, Closure Compiler) verwijderen onbereikbare code op het niveau van Dead Code Elimination. Dit vervangt echter niet de noodzaak om de bronnen op te schonen: de compiler verwijdert code uit de binair, maar niet uit de repository — ontwikkelaars zullen er nog steeds tegenaan lopen bij het lezen.

Samenvatting

  • Dode code — ongebruikte fragmenten die nooit worden uitgevoerd, maar in het project blijven.
  • Zombiecode — een subtype dode code dat eerder werkte, maar zijn relevantie verloor na refactoring.
  • Belangrijkste oorzaken: iteratieve ontwikkeling, feature toggle, autogeneratie en angst voor verwijdering.
  • Dode code vergroot de bouwtijd, binaire omvang en cognitieve belasting van het team.
  • Zoekinstrumenten: SonarQube, ESLint, SwiftLint, pylint, vulture, knip, ProGuard, JaCoCo.
  • Veilig verwijderen omvat: zoeken, git-analyse, verwijderen in branch, testuitvoering en code review.
  • Preventie van dode code: linters in CI, waarschuwing over ongebruikte code in code review en refactoringcultuur.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook