Magie v programování — co to je, proč jsou magic numbers nebezpečné a náhrada

Autor: IT Sectr Publikováno: 2026-07-27 Doba čtení: 10 min

Magie v programování — není metafora, ale přesný termín označující hodnoty (čísla, řetězce, příznaky), jejichž význam není z kontextu zřejmý a vyžaduje vnější znalosti k pochopení. Nejrozšířenějším druhem magie jsou magic numbers: číselné konstanty vepsané přímo do kódu bez vysvětlení, proč byla zvolena právě tato hodnota. Podle studie SonarSource Code Quality Report (2025) souvisí přibližně 8 procent všech varování statických analyzátorů s nevysvětlenými literály. Magické hodnoty činí kód křehkým: změna vyžaduje hledání všech výskytů a nový vývojář nechápe, zda se čísla může dotknout nebo je kritické pro fungování systému.

Hlavní

  • Magie — implicitní čísla, řetězce a příznaky v kódu, jejichž význam je skryt před čtenářem.
  • Magic numbers — číselné literály bez názvu: 86400, 3.14, 0.85, 1024.
  • Magické řetězce — hardcode cest, klíčů, URL bez vyjmutí do konstant.
  • Nástroje vyhledávání: SonarQube (pravidlo MagicNumber), ESLint (no-magic-numbers), Detekt.
  • Řešení: vyjmout každou magickou hodnotu do pojmenované konstanty s vysvětlujícím názvem.

Co je magie v programování?

Magie (magic) — je jakákoli hodnota ve zdrojovém kódu, jejíž význam není zřejmý bez dodatečných znalostí o doméně. Termín se v komunitě ustálil: pokud se vývojář podívá na číslo a nechápe, odkud se vzalo — je to magie.

Magie může být několika typů: numerická (magic numbers), řetězcová (magic strings), booleovská (magic flags) a konfigurační (hardcoded parametry, které by měly být v nastavení). Všechny čtyři typy spojuje jeden problém: při změně požadavku musí vývojář najít všechna místa, kde se hodnota používá, a ručně je nahradit. Vynechání byť jen jednoho výskytu vede k chybě.

Podle zprávy JetBrains Code Quality Survey (2025) považuje 73 procent vývojářů magic numbers za indikátor nízké kvality kódu, přičemž 41 procent přiznává, že je sami občas zanechávají. Hlavní důvod — spěch: „Konstantu dám později” — ale později nepřichází a po měsíci zůstává číslo 0.85 bez vysvětlení v těle metody.

Klíčové pravidlo: každá literální hodnota, kromě 0, 1, true, false a prázdného řetězce, by měla být vyjmuta do pojmenované konstanty. Výjimky: inkrementace čítače (i + 1), matematické nuly (kontrola na 0) a počáteční hodnoty akumulátorů. Vše ostatní — kandidát na pojmenování.

Magic numbers a proč jsou nebezpečné

Magic number — je číselný literál, jehož hodnota není z kontextu zřejmá. Klasický příklad: 86400 v kódu odpovědném za timeout. Vývojář vidí číslo a musí uhodnout, že se jedná o počet sekund v dni. Pokud udělá chybu a zadá 84600 — chyba bude těžko k odhalení, protože timeout se spustí o 18 minut dříve.

Proč jsou magic numbers nebezpečné: zaprvé naršují čitelnost. Číslo 1024 může znamenat velikost kilobajtu, práh stránkování nebo maximální počet prvků. Bez kontextu — je to jen číslo. Zadruhé vytvářejí duplicitu: pokud je 1024 použito na pěti místech, při změně prahu na 2048 musí vývojář najít všech pět a nahradit je. Pokud je jedno místo vynecháno — systém pracuje nesprávně, ale bez zřejmé chyby.

Příklad magic numbers před a po

kotlin
// před — magie v čisté formě
fun calculateTimeout(base: Int): Int {
    return base * 3 + 5000
}

// po — hodnoty nahrazeny konstantami
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
}

Třetí nebezpečí — nemožnost testování. Pokud je prahová hodnota vložena do kódu jako literál, test ji nemůže přepsat pro kontrolu okrajových podmínek. Konstanta vyjmutá do companion object nebo konfiguračního souboru činí kód testovatelným: test dosadí jinou hodnotu a zkontroluje chování systému na hranici.

Vytvořte si návyk: pokaždé, když napíšete číslo jiné než 0, 1, 100 nebo 2 — zastavte se a přemýšlejte, zda stojí za to ho vyjmout do konstanty. Pokud číslo souvisí s obchodní logikou (limit, práh, timeout, velikost) — vyjměte ho povinně. Pokud je číslo matematickou konstantou (pi, e) — použijte standardní knihovnu (Math.PI, Math.E).

Magické řetězce a cesty

Magic strings — řetězcové literály vložené do kódu bez vyjmutí do konstant nebo zdrojů. Typické příklady: URL endpointů, názvy klíčů SharedPreferences, Intent Actions, bundle keys, názvy souborů a SQL dotazy.

Nebezpečí magických řetězců spočívá v absenci kontroly během kompilace. Překlep v řetězci „user_prefs” nebude odhalen až do runtime. Pokud je řetězec použit na deseti místech a vývojář na jednom místě napsal „user_pref” (bez s) — aplikace nespadne, ale data se neukládají. Taková chyba může žít v produkci měsíce, protože nezpůsobuje pád.

Pro Android projekty musí být magické řetězce vyjmuty do zdrojů (strings.xml, arrays.xml) nebo do konstant v companion object. Pro iOS — do řetězcových zdrojů (Localizable.strings) nebo enum konstant. Pro backend — do konfiguračních souborů (.env, application.properties). Žádný klíč, URL ani cesta by neměly být v kódu přítomny jako řetězcový literál.

swift
// před — magické řetězce napříč třídou
let prefs = UserDefaults.standard
prefs.set(token, forKey: "auth_token")
prefs.set(userId, forKey: "current_user_id")

// po — řetězce vyjmuty do 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)

Věnujte zvláštní pozornost řetězcům, které se opakují. Pokud se stejný klíč „user_settings” vyskytuje ve třech souborech — s pravděpodobností 99 procent dříve nebo později v jednom z nich vznikne překlep. Vyjmutí do enum nebo konstanty zaručuje, že všechny reference používají stejnou hodnotu.

Magic flags a booleovské parametry

Magic flags — booleovské parametry, jejichž hodnota není z kontextu volání zřejmá. Klasický anti-vzor: předávání true nebo false metodě bez vysvětlení, co přesně tento příznak zapíná nebo vypíná.

Příklad: userDao.fetch(includeDeleted = false). Vývojář vidí false a nechápe, zda to znamená „nzahrnout smazané” nebo „nzahrnout aktivní”. Za měsíc se false změní na true a ve výsledcích se začnou objevovat smazané záznamy. Chyba je odhalena až v produkci.

Řešení — nahrazení booleovských příznaků enumem nebo sealed class. Místo parametru Boolean použijte UserFilter.includeDeleted nebo UserFilter.activeOnly. Tak kód sám dokumentuje záměr a IDE nabízí dostupné možnosti při automatickém doplňování.

Pokud je booleovský příznak předáván přes několik vrstev — to je další signál, že abstrakce je chybná. Místo vlečení příznaku přes tři úrovně volání přemýšlejte, zda by výběr filtrování neměl být proveden na horní úrovni a předán jako hotová konfigurace. Čím méně booleovských příznaků v kódu — tím méně magie.

Zaveďte pravidlo: žádný booleovský parametr není předáván metodě bez pojmenovaného argumentu (pokud jazyk podporuje named arguments). V Kotlin a Swift je tento požadavek splněn automaticky. V Java použijte Builder nebo enum konstanty místo true/false.

Nástroje pro detekci magie

Vyhledávání magických hodnot je automatizováno statickými analyzátory, které jsou nakonfigurovány k identifikaci literálů na neočekávaných místech. Každý jazyk nabízí vlastní nástroje s konfigurovatelnými výjimkami.

NástrojJazykyPravidlo
SonarQubeJava, Kotlin, Swift, Python, JSMagicNumber, HardcodedString
ESLintJavaScript, TypeScriptno-magic-numbers, no-hardcoded-strings
DetektKotlinMagicNumber, ComplexCondition
SwiftLintSwiftmagic_number (zapnuto opt-in)
PMDJava, Apex, PLSQLMagicNumber (lze nakonfigurovat seznam povolených)
PhpStorm InspectionsPHPNumericLiteralWithContext (vestavěná inspekce)

Konfigurace výjimek je kriticky důležitá — bez ní bude analyzátor vydávat varování při každé inkrementaci (-1, +1) a matematické nule. Pro SonarQube je seznam povolených čísel: 0, 1, -1, 2 (pro zdvojnásobení), 100 (procenta), 60 a 24 (čas). Pro všechny ostatní hodnoty — vyžadujte pojmenovanou konstantu s modifikátorem public static final (Java) nebo const val (Kotlin).

Pro analýzu na úrovni CI přidejte krok s kontrolou magie jako varování, ale ne blokující sestavení. První spuštění ukáže stovky varování v legacy kódu. Postupně, ticket po ticketu, převádějte kód na konstanty a zvyšujte práh kvality. Když počet magic numbers klesne pod 10 — zapněte pravidlo jako chybu sestavení.

Refaktorování: nahrazujeme magii konstantami

Refaktorování magie — jedna z nejbezpečnějších operací: nahrazení literálu konstantou nemění chování kódu. Nicméně přístup musí být systematický, aby nedošlo k přehlédnutí skrytých závislostí (například pokud je stejné magic number použito v nesouvisejících kontextech, ale náhodou má stejnou hodnotu).

Postup krok za krokem: najděte všechny výskyty magické hodnoty, pochopte kontext každého, rozdělte do různých konstant (i když se hodnoty shodují — kontexty jsou různé a konstanty musí být pojmenovány odlišně), nahraďte literály konstantami, zkontrolujte pomocí testů. Chyba v kroku 2 — nejčastější: dva různé pojmy (timeout v milisekundách a práh v bajtech) mohou číselně souhlasit (například 5000), ale sémanticky jde o různé veličiny a nelze je sloučit do jedné konstanty.

java
// před — stejné číslo v různých kontextech
public class Config {
    public void setupCache() {
        cache.setMaxSize(5000); // 5 MB
    }
    public void setupTimeout() {
        client.setReadTimeout(5000); // 5 sekund
    }
}

// po — různé konstanty pro různé kontexty
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
        );
    }
}

Pro nový kód je pravidlo jednoduché: každý literál, kromě 0, 1, -1, true, false, null a prázdného řetězce, se vyjímá do konstanty. Výjimky: matematické konstanty (vždy přes standardní knihovnu), testovací data (literál může zůstat v testu, ale s vysvětlujícím názvem proměnné) a okrajové hodnoty pro inkrementaci (i + 1 ve smyčce — normální).

Často kladené otázky

Je 100 magic number, pokud představuje 100 procent?

Ano, 100 je také magic number, pokud se používá bez kontextu. Místo 100 napište MAX_PERCENT nebo PROBABILITY_SCALE. Výjimka: když je 100 zřejmým procentem v kontextu (například ve vzorci pro výpočet procenta), ale i v tomto případě konstanta zlepšuje čitelnost.

Jak naložit s čísly v testech?

V testech je také lepší používat pojmenované proměnné. Místo assertEquals(42, result) napište val expected = 42; assertEquals(expected, result). Výjimka: testy na okrajové hodnoty (0, null, prázdný řetězec) — lze je ponechat jako literály, protože jsou čitelné v kontextu testu.

Vyplatí se vyjímat čísla do Android zdrojů?

Ano, čísla související s UI (velikosti, okraje, doba trvání animace) by měla být ve zdrojích (dimens.xml, integers.xml). Obchodní konstanty (timeouty, limity) — v companion object nebo konfiguračním souboru. Hlavní kritérium: pokud se číslo může změnit bez změny logiky — je to zdroj.

Jak najít magic numbers v legacy projektu?

Spusťte SonarQube s pravidlem MagicNumber nebo ESLint s no-magic-numbers. Získejte zprávu, seřaďte podle četnosti použití a začněte s čísly, která se vyskytují na třech nebo více místech. Ty jsou s největší pravděpodobností kandidáty na vyjmutí do konstanty.

Musí být každé číslo v kódu vyjmuto do konstanty?

Ne. Povolené literály: 0, 1, -1 (inkrementace/dekrementace, kontrola prázdnoty), true, false, null, prázdný řetězec. Všechny ostatní vyžadují pojmenování. Pokud je číslo 0 použito ne jako kontrola prázdnoty (například 0 — je ID kořenové kategorie), pak i 0 musí být konstantou: ROOT_CATEGORY_ID = 0.

Shrnutí

  • Magie — literály bez vysvětlení: čísla, řetězce, příznaky, jejichž význam je skryt před čtenářem kódu.
  • Magic numbers — číselné konstanty bez názvu (86400, 1024, 0.85, 5000) vyžadující doménové znalosti k pochopení.
  • Magic strings — hardcode klíčů, URL a cest, neviditelné pro kompilátor a vedoucí k runtime chybám.
  • Magic flags — booleovské parametry, jejichž hodnota není zřejmá (true/false ve volání metody).
  • Nástroje: SonarQube, ESLint, Detekt, SwiftLint, PMD — všechny podporují pravidlo MagicNumber.
  • Řešení: každý literál (kromě 0, ±1, true, false, null, „”) je vyjmut do pojmenované konstanty s vysvětlujícím názvem.
  • Různé kontexty — různé konstanty: 5000 jako timeout a 5000 jako velikost cache — jsou různé entity.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také