Kennisbank

Dode code: de vergeten instructies in software

Bijgewerkt: 14 augustus 2026 · 6 min leestijd

Stel je een huis voor met een kamer waar nooit iemand binnengaat, met een lichtschakelaar die op niets is aangesloten en een deur die permanent op slot zit. Alles staat er nog, maar het heeft geen functie meer. Zoiets bestaat ook in software: dode code is programmeercode die wel in de broncode van een programma staat, maar die nooit wordt uitgevoerd of waarvan de uitkomst nergens meer voor gebruikt wordt. De computer 'leest' die regels dus feitelijk nooit, of doet er niets zinnigs mee.

Dode code ontstaat bijna vanzelf in elk project dat lang genoeg meegaat. Denk aan een functie die is gebouwd voor een experiment dat later is losgelaten, een controle die overbodig werd nadat een collega ergens anders al dezelfde check toevoegde, of een oude taalversie die is vervangen maar waarvan de oude code nooit is opgeruimd. Programmeurs, compilers (programma's die broncode omzetten naar iets wat een computer kan uitvoeren) en gespecialiseerde tools proberen die dode code op te sporen en te verwijderen, omdat het de leesbaarheid, de veiligheid en soms ook de snelheid van software beïnvloedt.

Wat is het precies?

Binnen het begrip dode code onderscheiden ontwikkelaars meestal twee varianten. De eerste is onbereikbare code: instructies die door de structuur van het programma nooit aan de beurt komen. Een simpel voorbeeld is een stuk code dat alleen wordt uitgevoerd 'als x groter is dan 10 en x kleiner is dan 5' — die twee voorwaarden kunnen nooit tegelijk waar zijn, dus die code draait nooit. De tweede variant is ongebruikte code: berekeningen of resultaten die wel worden uitgevoerd, maar waarvan niemand de uitkomst ooit opvraagt of gebruikt, zoals een variabele die een waarde krijgt die daarna nergens meer wordt gelezen.

Het opsporen ervan gebeurt in een paar stappen. Eerst wordt de broncode 'geparsed', dat wil zeggen omgezet in een boomstructuur die de opbouw van het programma weergeeft. Daarna analyseert een tool de zogeheten controlestroom: welke route kan de uitvoering van het programma logischerwijs volgen, en welke stukken code liggen daarbuiten? Wat overblijft — code die op geen enkele route bereikbaar is, of waarvan de output nergens instroomt — wordt gemarkeerd als dood. Compilers doen dit automatisch als optimalisatiestap, een proces dat dead code elimination (DCE) heet en al decennialang standaard is in compilers zoals GCC en LLVM. Los daarvan bestaan er losse hulpprogramma's, linters genaamd, die ontwikkelaars tijdens het schrijven al waarschuwen voor dode code, zonder dat er meteen iets wordt verwijderd.

Wat wil men ermee bereiken?

Het belangrijkste doel is onderhoudbaarheid: hoe minder overbodige code een project bevat, hoe makkelijker het is voor ontwikkelaars om te begrijpen wat een programma daadwerkelijk doet. Dode code leidt geregeld tot verwarring, omdat nieuwe teamleden niet weten of een functie nog belangrijk is of allang overbodig, en soms per ongeluk juist die vergeten code weer gaan gebruiken of aanpassen.

Een tweede doel is prestatie. Bij software die naar de browser van een gebruiker wordt gestuurd — zoals een website die JavaScript gebruikt — telt elke overbodige regel mee in de bestandsgrootte die gedownload moet worden. Door dode code eruit te halen, een techniek die in deze context vaak tree shaking wordt genoemd, laden websites en apps sneller.

Een derde, minder voor de hand liggende reden is veiligheid. Dode code kan namelijk verraden dat er een fout in de logica van een programma zit: als een beveiligingscontrole per ongeluk onbereikbaar is geworden, wordt die controle dus nooit meer uitgevoerd, terwijl ontwikkelaars in de veronderstelling verkeren dat hij er nog is. Dat klinkt abstract, maar heeft in de praktijk al tot serieuze problemen geleid, zoals hieronder blijkt.

Voorbeelden uit de praktijk

Een van de bekendste gevallen is de zogeheten 'goto fail'-bug van Apple, ontdekt in februari 2014. In de beveiligingscode van Apple's besturingssystemen stond per ongeluk twee keer dezelfde regel ('goto fail;') achter elkaar. Daardoor sprong het programma altijd meteen naar het einde van een functie die de echtheid van een website-certificaat moest checken, nog voordat de eigenlijke controle was uitgevoerd. Die controle werd zo effectief dode code: hij stond er nog, maar werd nooit meer bereikt. Het gevolg was dat onveilige, vervalste verbindingen soms als veilig werden bestempeld.

Op het gebied van webontwikkeling introduceerde de JavaScript-bundelaar Rollup, gebouwd door ontwikkelaar Rich Harris, rond 2015 het concept tree shaking op grote schaal: het programma analyseert welke onderdelen van een bibliotheek een website daadwerkelijk gebruikt en verwijdert de rest voordat het bestand naar gebruikers wordt gestuurd. De populaire tool webpack nam deze aanpak vanaf versie 2 (2016) over, waarna tree shaking gemeengoed werd in de webindustrie.

Grote techbedrijven bouwen dode-code-detectie ook in hun eigen ontwikkelomgevingen in. Google's JavaScript-engine V8, die onder meer in de Chrome-browser draait, verwijdert en optimaliseert onbereikbare code als onderdeel van zijn compilatieproces, om scripts sneller te laten draaien.

In bedrijfsomgevingen wordt dode code vaak opgespoord met platforms zoals SonarQube, dat grote hoeveelheden broncode scant en dode code bestempelt als een 'code smell': geen directe fout, maar een signaal dat de kwaliteit van de code kan worden verbeterd.

Ook in de open source-wereld ontstaan gerichte tools, zoals Vulture voor de programmeertaal Python en Knip voor JavaScript- en TypeScript-projecten, die ontwikkelaars een overzicht geven van bestanden, functies en exports die nergens meer worden aangeroepen.

Hoe ver is de techniek?

Voor talen die vooraf volledig worden gecompileerd, zoals C, Rust of Java, is het opsporen van dode code een volwassen en zeer betrouwbare techniek. Compilers als LLVM en GCC passen dead code elimination al sinds de jaren tachtig en negentig toe, en de wiskundige basis — controlestroomanalyse — is goed begrepen en zelden fout.

Voor dynamische talen zoals JavaScript, Python of Ruby ligt dat lastiger. Deze talen laten toe dat code op basis van tekst of gebruikersinvoer dynamisch wordt geladen of aangeroepen (bijvoorbeeld via 'eval' of dynamische imports), waardoor een tool vooraf niet altijd met zekerheid kan vaststellen of een stuk code ooit gebruikt wordt. Detectietools moeten daarom voorzichtig, oftewel 'conservatief', te werk gaan: liever een keer iets missen dan per ongeluk code verwijderen die toch nog ergens wordt aangeroepen. Dat betekent dat geautomatiseerde tools in deze talen nooit alle dode code vinden, en dat menselijke controle nodig blijft voordat gevonden code echt wordt verwijderd.

De ontwikkeling gaat wel gestaag door. De opkomst van standaard ES-modules in JavaScript (een voorspelbaardere manier om code tussen bestanden te delen) heeft tree shaking de afgelopen jaren betrouwbaarder gemaakt, en snelle bundelaars zoals esbuild bouwen deze analyse tegenwoordig standaard in. Het grootste obstakel blijft de spanning tussen flexibiliteit van een taal en de voorspelbaarheid die nodig is om met zekerheid te zeggen: 'deze code wordt nooit gebruikt'.

Wie werken eraan?

Compilerteams bij grote partijen zoals Google (de V8-engine), Apple en de bredere LLVM-gemeenschap onderhouden de kernoptimalisaties voor dead code elimination in veelgebruikte programmeertalen. Microsoft draagt via zijn .NET- en TypeScript-compilers bij aan vergelijkbare analyses.

In de webwereld zijn het vooral open source-projecten die het tempo bepalen: Rollup, webpack en esbuild voor bundelen en tree shaking, en ESLint als de meest gebruikte linter voor JavaScript, met ingebouwde regels om ongebruikte variabelen te signaleren.

Commerciële spelers zoals SonarSource (met SonarQube en SonarLint) en JetBrains (bekend van ontwikkelomgevingen zoals IntelliJ) bouwen dode-codedetectie in tools die bedrijven gebruiken om hun softwarekwaliteit te bewaken. Daarnaast houden academische onderzoeksgroepen wereldwijd, waaronder in Nederland aan technische universiteiten, zich bezig met de bredere vraag hoe 'technische schuld' zoals dode code ontstaat en het beste kan worden opgespoord in grote, langlevende softwareprojecten.

Verder lezen