Technický dluh a architektura: proč ten nejdražší dluh nevidíte v code review

Většina týmů si pod technickým dluhem představí ošklivý kód. Ten skutečně drahý dluh ale leží o patro výš — v architektuře. A v diffu pull requestu ho nikdy neuvidíte.

Abstraktní vizualizace architektonického technického dluhu: čisté moduly nad popraskanou strukturou závislostí

„Máme technický dluh.“ Tuhle větu slyším skoro v každé firmě, do které přijdu na audit. Skoro vždy jí ale lidé myslí to samé — konkrétní ošklivý kód. A skoro vždy je to ta levnější polovina problému. Ta dražší se schovává jinde a chová se úplně jinak.

01Dva druhy dluhu, které se pletou

Když se řekne „technický dluh“, většina lidí si představí konkrétní kód: dlouhou metodu, chybějící test, zkopírovaný blok, proměnnou pojmenovanou $tmp2. Tomu říkám lokální dluh. Je nepříjemný, ale má jednu zásadní výhodu — je vidět, je ohraničený a jeho oprava je odhadnutelná. Otevřete soubor, opravíte, zavřete.

Pak je tu druhý druh: strukturální dluh. Modul, který sahá přímo do databázové tabulky jiného modulu. Doménová logika rozlitá v kontrolerech. Závislosti, které tvoří kruh. Jedna sdílená databáze pod třemi „mikroslužbami“. Tenhle dluh nebolí na jednom místě — bolí všude trochu. A přesně proto je nebezpečný.

Ta hranice mezi nimi je ale propustnější, než se zdá. Zkopírovaný blok na čtyřiceti místech je formálně lokální dluh — jenže když se změní business pravidlo, platíte ho čtyřicetkrát. Skutečná diagnostická otázka tedy nezní jaký druh dluhu to je, ale kolika míst se jediná smysluplná změna musí dotknout. Tomu se říká blast radius — dosah změny. A je to jediná metrika, která vás drží na pravdě o struktuře systému: lokální dluh je strukturální dluh s dosahem jedna, strukturální dluh je lokální dluh, který už vyrostl.

02Proč architektonický dluh roste rychleji

Lokální dluh se obvykle chová lineárně: deset zanedbaných metod stojí zhruba desetkrát tolik co jedna. Strukturální dluh se ale úročí. Každá nová funkce se totiž staví na stávající architektuře — a tím přebírá její předpoklady.

Příklad z praxe: někdo jednou pod tlakem termínu sáhl z modulu objednávek přímo do tabulky users. Fungovalo to. Za rok je takových míst čtyřicet. „Oddělit uživatele do vlastní služby“ už není refaktoring na odpoledne, ale několikaměsíční projekt s rizikem. Jistina se nezměnila — jen se k ní nabalil úrok.

03Proč ho v code review neuvidíte

Tady je jádro problému. Code review pracuje s diffem. A diff je ze své podstaty lokální — ukáže obsah jednoho souboru, jedné změny. Jenže architektura není obsah souboru. Architektura je vztah mezi soubory — graf závislostí, tok dat, umístění hranic.

Žádný jednotlivý pull request nevypadá špatně. Každý je „jen malá výjimka, ať to stihneme“. Strukturální dluh nevzniká ze špatných rozhodnutí — vzniká ze součtu rozumných lokálních rozhodnutí, z nichž žádné nikdo neposuzoval v kontextu celku. Reviewer schválí strom. Les neposoudí nikdo.

04Diagnostika: kolik míst se dotkne jediná změna?

Strukturální dluh nepoznáte podle pocitu „kód je ošklivý“. Poznáte ho podle toho, kolika míst se musí dotknout jediná smysluplná změna — a co to dělá s kódem a s týmem. Příznaky se rozpadají do dvou skupin.

V kódu (dosah viditelný v repozitáři):

  • „Triviální“ změna se dotkne osmi souborů ve čtyřech modulech.
  • Testy buď neexistují, nebo se musí pouštět „všechny najednou“, protože nejdou izolovat — a změna na jednom místě tak rozbije i test, který s ní zdánlivě nesouvisí.
  • Nikdo si netroufne smazat starý kód, protože není jasné, kdo na něj závisí.

V týmu (dosah viditelný v lidech):

  • Nový vývojář se v kódu orientuje měsíce, ne týdny.
  • Odhady jsou systematicky 2–3× mimo a nikdo neumí říct proč.

Žádný z těchto bodů není o „špatných programátorech“. Jsou to věcné příznaky toho, že hranice v systému jsou na špatných místech — nebo nejsou vůbec. A umístění hranic není čistě technické rozhodnutí: kopíruje tvar komunikace v týmu. Tým rozdělený podle technických vrstev (frontend, backend, databáze) vyrobí architekturu rozdělenou podle vrstev; tým rozdělený podle domén vyrobí architekturu podle domén. Proč tahle gravitace vzniká a jak proti ní jít, rozebírá článek Architektura je tvar týmu.

// Praktický pohled

Při auditu se neptám nejdřív na kód. Ptám se: jak dlouho trvá, než nový člověk nasadí svou první změnu do produkce? Tahle jediná odpověď řekne o zdraví vývoje víc než tisíc řádků. Neměří to čistě architekturu — měří to i CI/CD a kulturu revizí. Ale to je rys, ne chyba: když je číslo špatné, něco drhne, a tohle je dobré místo, kde začít hledat.

05Úrok, jistina a účet, který nikdy nepřijde

Sekce 02 popsala, že strukturální dluh se úročí. Metafora ale má další patro, které většina týmů nedotáhne — a tam se rozhoduje, jestli dluh splatíte, nebo jen platíte úrok do nekonečna.

Většina firem roky splácí jen úrok a jistiny se nikdy nedotkne. A na rozdíl od banky vám tenhle účet nikdy nepřijde obálkou. Jen se vám pomalu a nenápadně prodlužují všechny odhady — až je „rychlá featura“ otázka kvartálu a nikdo neví, kdy se to stalo.

I metafora má svou mez. Finanční jistina je přesná částka, kterou vrátíte; architekturu ale nevrátíte — přestavíte ji a nová struktura si nese vlastní dluh. „Splatit“ tady neznamená uzavřít půjčku, ale snížit cenu příští změny. Analogie přesto drží v tom podstatném: technický dluh je rozhodnutí o penězích, ne o vkusu.

06Dluh není nepřítel. Neviditelný dluh ano.

Tady pozor na zkratku „technický dluh = zlo“. Vědomě přijatý, zapsaný a ohraničený dluh je naprosto legitimní nástroj. Potřebujete ověřit hypotézu? Stihnout trh? Zkratka je správné rozhodnutí — pokud o ní víte.

Nebezpečný je dluh nevědomý a neviditelný. Rozdíl mezi tím dobrým a špatným je jediná otázka: bylo to rozhodnutí, nebo se to prostě stalo?

Konkrétní příklad za všechny: před třemi lety jsme s týmem před uzávěrkou kola vědomě odložili multi-tenancy. Místo abychom ji stavěli „pro jistotu“, napsali jsme ADR o jednu stranu — co odkládáme, proč, a za jakých okolností se k tomu vrátíme (první enterprise zákazník, který si o ni řekne). Vrátili jsme se k tomu po patnácti měsících, splatili to za šest týdnů a nikoho to nestálo víc nervů než plánovaná featura. To je vědomý dluh.

Protipříklad je ten, který popsala sekce 02: někdo sáhl z modulu objednávek do tabulky users a ostatní to po něm udělali ještě čtyřicetkrát. Žádné rozhodnutí. Žádný záznam. Žádný plán návratu. To je dluh, který se prostě stal — a ten je vždycky dražší než ten, který jste si vědomě půjčili.

Tahle otázka — vědomý dluh versus nevědomý — má svůj vlastní rozhodovací rámec. Kdy je zkratka půjčka, kdy procesní problém a kdy jen mezera v dovednostech, rozebírám v článku Technický dluh není bordel v kódu.

07Co s tím — prakticky

Udělejte dluh viditelným

Krátký architektonický záznam (ADR — Architecture Decision Record): rozhodli jsme se X, protože Y, vědomě jsme odložili Z. Tři odstavce. Dluh, který je zapsaný, přestává být tikající bombou a stává se položkou v backlogu. Co je rozhodnutí hodné ADR a jak ho napsat krátce, rozebírá samostatný článek ADR: architektonická paměť týmu.

Recenzujte hranice, ne řádky

Do code review patří otázka „kdo teď na koho závisí?“ víc než debata o formátování. Závislost mezi moduly je architektonické rozhodnutí — zaslouží si stejnou pozornost jako změna chování. Proč běžné code review tuhle vrstvu strukturálně míjí a jak doplnit architektonické review, rozebírá samostatný článek Proč code review nezachrání architekturu.

Vynuťte hranice automaticky

Recenze hranic spoléhá na pozornost člověka — a tu deadline spolehlivě vypne. ADR rozhodnutí zaznamená, ale nevynutí — a v pět odpoledne před nasazením ho stejně nikdo nečte. Pravidlo, které nepustí pull request s cyklickou závislostí, ano. Nástroje jako dependency-cruiser (JavaScript) nebo ArchUnit (Java) umí hranice zapsat jako test: tahle vrstva nesmí volat tamtu, žádné cykly, doménová logika nezná web. Obecnější formou jsou fitness funkce — automatické kontroly architektonických vlastností běžící v CI vedle běžných testů. Hranici, kterou hlídá stroj, deadline nezruší; hranici, kterou hlídá jen dobrý zvyk, ano.

Malá vratná rozhodnutí před velkými nevratnými

Když nevíte, kde hranici vést, veďte ji tak, aby šla později posunout. Levný omyl je ten, který jde vzít zpět.

Refaktorujte po trase

Velké „refaktoringové sprinty“ management dřív nebo později zařízne. Místo toho: kdykoli se nová featura dotkne nějaké oblasti, narovnejte ji při té příležitosti. Dluh se splácí průběžně, ne kampaňovitě.

Měřte zdraví, ne jen rychlost

Lead time změny, počet dotčených modulů na featuru, doba onboardingu. Žádné z těch čísel neměří architekturu napřímo — ale když se všechna zhoršují naráz, bývá za tím právě ona. V auditech vidím konzistentní práh: jakmile lead time běžné featury překročí pět pracovních dní a onboarding nového člověka šest týdnů, najdeme s téměř jistotou cyklickou závislost mezi třemi a více moduly. Není to důkaz kauzality, ale je to dost dobrý důvod začít kreslit graf závislostí.

Mluvte o dluhu jazykem peněz, ne kódu

Architektonický dluh se stane položkou v rozpočtu teprve tehdy, když přestane být inženýrským vkusem. Přeložte ho na konkrétní cenu: „každá změna v této oblasti dnes stojí třikrát tolik co před rokem; tu daň platíme každý sprint“. CFO nezajímá cyklická závislost — zajímá ho, proč odhad utekl o kvartál. Bez toho překladu architektonický dluh nikdy nedostane vlastní řádek v účtu a nikdy se nesplácí; jen se na něj naříká.

08Závěr: dluh je finanční rozhodnutí převlečené za technický detail

Technický dluh není selhání. Je to nástroj — a jako každý nástroj může pomáhat i škodit. Klíč je zacházet s ním jako s financemi: vědomě, zapsaně, s plánem splácení.

Nejhorší pozice není být zadlužený. Nejhorší je nevědět, kolik dlužíte.

Reference

Článek vychází především z autorovy auditní praxe na zakázkách. Koncept fitness funkcí pro architekturu rozpracovali Neal Ford a Rebecca Parsons.

Související a kontext
  1. Technický dluh není bordel v kódublog mesour.com
  2. ADR: architektonická paměť týmublog mesour.com
Matouš Němec
Matouš Němec (mesour)

Softwarový konzultant a AI-first developer. 15+ let praxe v PHP, Javě a Kotlinu — audit architektury, detekce technického dluhu a vývoj na míru.

Zpět na blog