Magie in programmeren — is geen metafoor, maar een precieze term die waarden (getallen, strings, vlaggen) aanduidt waarvan de betekenis niet duidelijk is uit de context en externe kennis vereist om te begrijpen. De meest voorkomende vorm van magie — magic numbers: numerieke constanten die direct in de code zijn geschreven zonder uitleg waarom precies deze waarde is gekozen. Volgens het onderzoek SonarSource Code Quality Report (2025) heeft ongeveer 8 procent van alle waarschuwingen van statische analyseurs betrekking op onverklaarde literals. Magische waarden maken code breekbaar: wijziging vereist het zoeken naar alle voorkomens en een nieuwe ontwikkelaar begrijpt niet of het getal aangeraakt mag worden of dat het kritisch is voor de werking van het systeem.
Belangrijkste
Magie (magic) — is elke waarde in de broncode waarvan de betekenis niet duidelijk is zonder aanvullende kennis van het domein. De term is ingeburgerd in de gemeenschap: als een ontwikkelaar naar een getal kijkt en niet begrijpt waar het vandaan komt — is het magie.
Magie komt in verschillende vormen voor: numeriek (magic numbers), string (magic strings), Booleaans (magic flags) en configurationeel (hardcoded parameters die in instellingen zouden moeten staan). Alle vier de typen delen één probleem: bij een wijziging van een vereiste moet de ontwikkelaar alle plaatsen vinden waar de waarde wordt gebruikt en deze handmatig vervangen. Het missen van zelfs maar één voorkomen leidt tot een bug.
Volgens het rapport JetBrains Code Quality Survey (2025) beschouwt 73 procent van de ontwikkelaars magic numbers als een indicator van lage codekwaliteit, terwijl 41 procent toegeeft ze zelf af en toe achter te laten. De belangrijkste reden — haast: „Ik zet de constante later wel” — maar later komt niet, en na een maand blijft het getal 0.85 zonder uitleg in de body van de methode staan.
De sleutelregel: elke literalwaarde, behalve 0, 1, true, false en de lege string, moet worden geëxtraheerd naar een benoemde constante. Uitzonderingen: tellerophoging (i + 1), wiskundige nullen (controle op 0) en beginwaarden van accumulatoren. Al het andere — kandidaat voor benoeming.
Magic number — is een numerieke literal waarvan de waarde niet duidelijk is uit de context. Klassiek voorbeeld: 86400 in code die verantwoordelijk is voor een timeout. De ontwikkelaar ziet het getal en moet raden dat dit het aantal seconden in een dag is. Als hij een fout maakt en 84600 plaatst — zal de bug moeilijk te vinden zijn, omdat de timeout 18 minuten eerder zal afgaan.
Waarom magic numbers gevaarlijk zijn: ten eerste schaden ze de leesbaarheid. Het getal 1024 kan de grootte van een kilobyte betekenen, een pagineringsdrempel of het maximale aantal elementen. Zonder context — is het gewoon een getal. Ten tweede creëren ze duplicatie: als 1024 op vijf plaatsen wordt gebruikt, moet bij het wijzigen van de drempel naar 2048 de ontwikkelaar alle vijf vinden en vervangen. Als één plaats wordt gemist — werkt het systeem incorrect, maar zonder duidelijke fout.
// voor — magie in zuivere vorm
fun calculateTimeout(base: Int): Int {
return base * 3 + 5000
}
// na — waarden vervangen door constanten
private const val RETRY_MULTIPLIER = 3
private const val BASE_TIMEOUT_MS = 5000
fun calculateTimeout(base: Int): Int {
return base * RETRY_MULTIPLIER + BASE_TIMEOUT_MS
}
Het derde gevaar — onmogelijkheid van testen. Als de drempelwaarde in de code als literal is ingebed, kan de test deze niet overschrijven om randvoorwaarden te controleren. Een constante geëxtraheerd naar een companion object of configuratiebestand maakt de code testbaar: de test plaatst een andere waarde en controleert het gedrag van het systeem op de grens.
Ontwikkel een gewoonte: elke keer dat u een getal schrijft dat niet 0, 1, 100 of 2 is — stop en denk of het de moeite waard is om het naar een constante te extraheren. Als het getal verband houdt met bedrijfslogica (limiet, drempel, timeout, grootte) — extraheer het dan verplicht. Als het getal een wiskundige constante is (pi, e) — gebruik dan de standaardbibliotheek (Math.PI, Math.E).
Magic strings — stringliterals die in de code zijn ingebed zonder extractie naar constanten of bronnen. Typische voorbeelden: URL's van endpoints, namen van SharedPreferences-sleutels, Intent Actions, bundle keys, bestandsnamen en SQL-query's.
Het gevaar van magische strings ligt in het ontbreken van controle tijdens compilatie. Een typefout in de string „user_prefs” wordt pas tijdens runtime ontdekt. Als de string op tien plaatsen wordt gebruikt en de ontwikkelaar heeft op één plaats „user_pref” (zonder s) geschreven — crasht de applicatie niet, maar worden de gegevens niet opgeslagen. Zo'n bug kan maanden in productie leven, omdat hij geen crash veroorzaakt.
Voor Android-projecten moeten magische strings worden geëxtraheerd naar bronnen (strings.xml, arrays.xml) of naar constanten in companion object. Voor iOS — naar stringbronnen (Localizable.strings) of enum-constanten. Voor backend — naar configuratiebestanden (.env, application.properties). Geen enkele sleutel, URL of pad mag in de code als stringliteral voorkomen.
// voor — magische strings door de hele klasse
let prefs = UserDefaults.standard
prefs.set(token, forKey: "auth_token")
prefs.set(userId, forKey: "current_user_id")
// na — strings geëxtraheerd naar enum
enum PrefKeys: String {
case authToken = "auth_token"
case currentUserId = "current_user_id"
}
prefs.set(token, forKey: PrefKeys.authToken.rawValue)
prefs.set(userId, forKey: PrefKeys.currentUserId.rawValue)
Besteed speciale aandacht aan strings die worden gedupliceerd. Als dezelfde sleutel „user_settings” in drie bestanden voorkomt — is er met 99 procent kans vroeg of laat in een ervan een typefout. Extractie naar een enum of constante garandeert dat alle verwijzingen dezelfde waarde gebruiken.
Magic flags — Booleaanse parameters waarvan de waarde niet duidelijk is uit de context van de aanroep. Klassiek anti-patroon: het doorgeven van true of false aan een methode zonder uit te leggen wat deze vlag precies in- of uitschakelt.
Voorbeeld: userDao.fetch(includeDeleted = false). De ontwikkelaar ziet false en begrijpt niet of dit „include verwijderde niet” of „include actieve niet” betekent. Een maand later wordt false omgezet in true en beginnen verwijderde records in de resultaten te verschijnen. De bug wordt pas in productie ontdekt.
Oplossing — vervanging van Booleaanse vlaggen door enum of sealed class. Gebruik in plaats van een Boolean-parameter UserFilter.includeDeleted of UserFilter.activeOnly. Zo documenteert de code zelf de intentie en suggereert de IDE de beschikbare opties bij automatisch aanvullen.
Als een Booleaanse vlag door meerdere lagen wordt doorgegeven — is dit nog een signaal dat de abstractie verkeerd is. In plaats van de vlag door drie niveaus van aanroepen te slepen, bedenk of de filterkeuze niet op het hoogste niveau moet worden genomen en als een kant-en-klare configuratie moet worden doorgegeven. Hoe minder Booleaanse vlaggen in de code — hoe minder magie.
Voer een regel in: geen enkele Booleaanse parameter wordt aan een methode doorgegeven zonder benoemd argument (als de taal named arguments ondersteunt). In Kotlin en Swift wordt aan deze vereiste automatisch voldaan. Gebruik in Java Builder of enum-constanten in plaats van true/false.
Het zoeken naar magische waarden wordt geautomatiseerd door statische analyseurs die zijn geconfigureerd om literals op onverwachte plaatsen te identificeren. Elke taal biedt zijn eigen hulpmiddelen met configureerbare uitzonderingen.
| Instrument | Talen | Regel |
|---|---|---|
| SonarQube | Java, Kotlin, Swift, Python, JS | MagicNumber, HardcodedString |
| ESLint | JavaScript, TypeScript | no-magic-numbers, no-hardcoded-strings |
| Detekt | Kotlin | MagicNumber, ComplexCondition |
| SwiftLint | Swift | magic_number (ingeschakeld opt-in) |
| PMD | Java, Apex, PLSQL | MagicNumber (lijst van toegestane getallen configureerbaar) |
| PhpStorm Inspections | PHP | NumericLiteralWithContext (ingebouwde inspectie) |
Het configureren van uitzonderingen is van cruciaal belang — zonder zal de analyseur waarschuwingen geven bij elke ophoging (-1, +1) en wiskundige nul. Voor SonarQube de lijst met toegestane getallen: 0, 1, -1, 2 (voor verdubbeling), 100 (procenten), 60 en 24 (tijd). Voor alle andere waarden — eis een benoemde constante met de modifier public static final (Java) of const val (Kotlin).
Voeg voor analyse op CI-niveau een stap toe met controle op magie als waarschuwing, maar niet blokkerend voor de build. De eerste uitvoering zal honderden waarschuwingen in legacy-code tonen. Stap voor stap, ticket voor ticket, migreer de code naar constanten en verhoog de kwaliteitsdrempel. Wanneer het aantal magic numbers onder de 10 komt — schakel de regel in als buildfout.
Refactoring van magie — een van de veiligste operaties: het vervangen van een literal door een constante verandert het gedrag van de code niet. Niettemin moet de aanpak systematisch zijn om verborgen afhankelijkheden niet over het hoofd te zien (bijvoorbeeld als hetzelfde magic number in niet-gerelateerde contexten wordt gebruikt, maar toevallig dezelfde waarde heeft).
Stap-voor-stap proces: vind alle voorkomens van de magische waarde, begrijp de context van elk, verdeel over verschillende constanten (zelfs als de waarden overeenkomen — de contexten zijn verschillend en de constanten moeten anders worden genoemd), vervang de literals door constanten, controleer via tests. De fout bij stap 2 — de meest voorkomende: twee verschillende concepten (timeout in milliseconden en drempel in bytes) kunnen numeriek samenvallen (bijvoorbeeld 5000), maar semantisch zijn het verschillende grootheden en ze kunnen niet in één constante worden samengevoegd.
// voor — hetzelfde getal in verschillende contexten
public class Config {
public void setupCache() {
cache.setMaxSize(5000); // 5 MB
}
public void setupTimeout() {
client.setReadTimeout(5000); // 5 seconden
}
}
// na — verschillende constanten voor verschillende contexten
public class Config {
private static final int CACHE_MAX_SIZE_MB = 5;
private static final int READ_TIMEOUT_SECONDS = 5;
public void setupCache() {
cache.setMaxSize(CACHE_MAX_SIZE_MB * 1024 * 1024);
}
public void setupTimeout() {
client.setReadTimeout(
READ_TIMEOUT_SECONDS * 1000
);
}
}
Voor nieuwe code is de regel eenvoudig: elke literal, behalve 0, 1, -1, true, false, null en de lege string, wordt naar een constante geëxtraheerd. Uitzonderingen: wiskundige constanten (altijd via de standaardbibliotheek), testgegevens (literal mag in de test blijven, maar met een verklarende variabelenaam) en grenswaarden voor ophoging (i + 1 in een lus — normaal).
Veelgestelde vragen
Ja, 100 is ook een magic number als het zonder context wordt gebruikt. Schrijf in plaats van 100 MAX_PERCENT of PROBABILITY_SCALE. Uitzondering: wanneer 100 een voor de hand liggend percentage in de context is (bijvoorbeeld in een procentberekeningsformule), maar zelfs in dit geval verbetert een constante de leesbaarheid.
Gebruik in tests ook liever benoemde variabelen. Schrijf in plaats van assertEquals(42, result) val expected = 42; assertEquals(expected, result). Uitzondering: tests voor grenswaarden (0, null, lege string) — deze kunnen als literals blijven, omdat ze leesbaar zijn in de testcontext.
Ja, getallen die verband houden met de UI (afmetingen, marges, animatieduur) moeten in bronnen staan (dimens.xml, integers.xml). Bedrijfsconstanten (timeouts, limieten) — in companion object of configuratiebestand. Het belangrijkste criterium: als het getal kan veranderen zonder de logica te wijzigen — is het een bron.
Start SonarQube met de regel MagicNumber of ESLint met no-magic-numbers. Ontvang een rapport, sorteer op gebruiksfrequentie en begin met getallen die op drie of meer plaatsen voorkomen. Zij zijn met de grootste waarschijnlijkheid kandidaten voor extractie naar een constante.
Nee. Toegestane literals: 0, 1, -1 (ophoging/verlaging, leegheidscontrole), true, false, null, lege string. Alle andere vereisen benoeming. Als het getal 0 niet als leegheidscontrole wordt gebruikt (bijvoorbeeld 0 — is de ID van de hoofdcategorie), dan moet 0 ook een constante zijn: ROOT_CATEGORY_ID = 0.
Samenvatting
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.
Lees ook