Engineering · 7 min čtení

Jak splácet technický dluh, aniž byste zastavili vývoj funkcí

Technický dluh splácíte bez zastavení vývoje funkcí tak, že ho berete jako stálou položku, ne jako projekt. Změřte, kde dluh skutečně bolí, veďte seřazený registr, v každém sprintu vyhraďte pevný podíl kapacity a riskantní části nahrazujte postupně za testy, abstrakcemi a feature flagy. Jestli to funguje, vám řeknou metriky DORA.

Autor BacklooPublikováno

Hlavní body

  • Nejdřív měřte: dluh v kódu, na který skoro nikdo nesahá, je levný; dluh v souborech, které se mění každý týden a způsobují incidenty, je drahý.
  • Veďte registr dluhu s cenou, rizikem a jmenovitým vlastníkem a vyhraďte pro něj pevný díl každého sprintu, místo abyste vyjednávali o každé položce zvlášť.
  • Systémy nahrazujte po částech pomocí vzoru strangler fig, branch by abstraction a feature flagů. Přepis naráz je nejriskantnější možnost.
  • Před refaktoringem napište charakterizační testy a jako výsledkovou tabuli, kterou přečte každý, používejte čtyři klíčové metriky DORA.

Proč je zmrazení vývoje funkcí špatné řešení

Zmrazení vývoje funkcí vyměňuje pomalý, viditelný náklad (dluh) za náhlý, viditelný náklad (žádný posun produktu), takže první zasedání představenstva přežije jen zřídka. Vydrží přístup, který je průběžný: malé, předvídatelné množství práce na dluhu v každém cyklu, mířené na kód, který bolí nejvíc, s výsledky, které byznys vidí.

Ten náklad je skutečný. Dluh se projevuje pomalejšími dodávkami, více regresemi, delším zaškolováním a únavou z pohotovostí. V rozpočtu se jako samostatná položka objeví jen zřídka, a proto ve srovnání s funkcemi pořád prohrává.

10–20 %

technologického rozpočtu na nové produkty se odkloní na řešení technického dluhu; dluh tvoří 20–40 % hodnoty celého technologického majetku firmy. — McKinsey, “Tech debt: Reclaiming tech equity” ↗

Tuhle daň už platíte. Otázkou je, jestli ji platíte jako úroky, tedy pomalými a křehkými dodávkami, nebo jako jistinu, tedy plánovanou prací, která zlevní každou další změnu.

Měřte dluh tam, kde bolí: hotspoty a incidenty

Dluh měříte tak, že zkombinujete, jak často se kód mění, s tím, jak těžké je ho změnit. Složitý soubor, na který nikdo nesahá, je kuriozita. Složitý soubor, který se mění každý týden, je hotspot — a v hotspotech se dluh mění v náklady. Přidejte data o incidentech a máte obhajitelný seznam priorit.

Četnost změn × složitost

Četnost změn (churn) získáte přímo z verzovacího systému. Složitost může být jednoduchá jako počet řádků kódu, nebo přesná jako cyklomatická či kognitivní složitost z linteru. Obě hodnoty vynásobte a seřaďte. Prvních deset souborů obvykle odpovídá za velkou část bolesti, na kterou si váš tým už stěžuje.

bash
# počet commitů na soubor za posledních 6 měsíců (churn)
git log --since="6 months ago" --name-only --pretty=format: \
  | grep -E '\.(ts|tsx|py|go)$' \
  | sort | uniq -c | sort -rn | head -30

# hrubý ukazatel složitosti: počet řádků na soubor
wc -l $(git ls-files 'src/**/*.ts') | sort -rn | head -30

Nekomplikujte to. Tabulka, která oba seznamy spojí, stačí k tomu, abyste začali užitečnou debatu. Specializované nástroje přidají trendy a mapy vlastnictví, až budete vědět, že se to vyplácí.

Propojte dluh s incidenty

Každý postmortem by měl odpovědět na jednu otázku navíc: která část kódu to zhoršila nebo ztížila opravu? Incident označte příslušným modulem. Po čtvrtletí jsou moduly s nejvíce incidenty a nejvyšší četností změn vašimi prvními cíli — a máte to čím doložit.

Veďte registr dluhu, ne hřbitov v backlogu

Registr dluhu je krátký, seřazený seznam známého dluhu s odhadovanou cenou, mírou rizika a vlastníkem. Od backlogu plného ticketů „refaktorovat X“ se liší tím, že každá položka uvádí, kolik dluh stojí dnes a co jeho splacení odemkne, takže ji lze prioritizovat proti funkcím stejným jazykem.

Minimální položka registru dluhu
PolePříkladProč na tom záleží
PoložkaLogika cen objednávek duplikovaná v API a v administraciPojmenovává problém, ne řešení
DůkazyMezi 3 největšími hotspoty; 2 incidenty minulé čtvrtletíVáže ji na měřitelnou bolest
ÚrokKaždá změna cen zasahuje do 2 kódových bází, ~1 den navícPrůběžná cena za to, že se nic neudělá
RizikoVysoké: k zákazníkům se dostanou špatné cenyDopad na byznys, když to selže
Navržený krokVyčlenit modul cen za jedno rozhraníNejmenší změna, která pomůže
VlastníkJmenovitý inženýrNěkdo za to odpovídá
StavPříští sprintViditelný pokrok

Řaďte podle úroku × rizika, ne podle toho, jak moc vás kód uráží. Registr jednou měsíčně projděte, vyřaďte položky, na kterých už nezáleží, a držte ho zhruba do dvaceti záznamů. Registr, který nikdo nečte, je jen druhý backlog.

V každém sprintu vyhraďte pevnou kapacitu

Nejjednodušší pravidlo, které přežije střet s termíny, je pevný podíl kapacity vyhrazený na dluh v každém sprintu, jednou dohodnutý s produktem a znovu nevyjednávaný položku po položce. Zvolte číslo, které dokážete udržet, například jeden den z deseti, a chraňte ho jako každý jiný závazek.

  • Pevně, ne ze zbytku. Práce na dluhu „až bude čas“ se nikdy neudělá. Naplánujte ji jako první.
  • Brané z registru. Tým si bere položky shora, takže se nevede debata o tom, co se počítá.
  • Navíc pravidlo skauta. Drobné úklidy v kódu, který už stejně měníte, jsou součástí funkce, ne rozpočtu na dluh.
  • Pružné v rámci čtvrtletí. Kvůli spuštění můžete sprint vynechat a pak to dohnat. Zůstatek sledujte otevřeně.

Nahrazujte, nepřepisujte: strangler fig, branch by abstraction, flagy

Velký dluh se splácí tak, že systém nahrazujete po částech, zatímco dál běží — nikdy přepisem naráz. Většinu práce odvedou tři techniky: strangler fig pro celé subsystémy, branch by abstraction pro kód uvnitř jedné kódové báze a feature flagy pro bezpečné přepínání provozu. Pokud stejně zvažujete přepis, přečtěte si nejdřív záchrana, refaktoring, nebo přepis.

Vzor strangler fig

Martin Fowler pojmenoval tento vzor podle škrticího fíkovníku, který obrůstá strom, dokud ho nenahradí. Před starý systém postavte směrovací vrstvu, novou implementaci stavějte postupně po jedné routě nebo schopnosti a provoz přesouvejte, jakmile je každá část hotová. Starý kód se zmenšuje, dokud ho nejde smazat. V žádném okamžiku vás nečeká riskantní víkend s přepnutím.

Branch by abstraction

U kódu v jednom repozitáři vložte před část, kterou chcete nahradit, rozhraní, převeďte na něj všechna volání, za ním postavte novou implementaci, pak přepněte a starou smažte. Všechno se průběžně dodává do mainu; na konci nečeká žádná dlouho žijící větev k mergi.

Feature flagy jako přepínač

Flag za běhu rozhoduje, která implementace obslouží požadavek. Nasaďte nejdřív interním uživatelům, pak malému procentu a pak všem — a vracejte se přepnutím flagu, ne novým nasazením.

ts
// Jedno rozhraní, dvě implementace, jeden přepínač.
interface PriceCalculator {
  quote(order: Order): Money;
}

const calculator: PriceCalculator = flags.isOn("pricing-v2", { userId })
  ? new PricingModule()      // nová, otestovaná, s vlastníkem
  : new LegacyPricing();     // stará cesta, smažeme ji, až flag dosáhne 100 %

I flagy jsou dluh. Každému flagu přiřaďte vlastníka a datum odstranění a smažte ho do jednoho až dvou sprintů po plném nasazení.

Než začnete refaktorovat, natáhněte záchrannou síť

Refaktoring bez testů je jen měnění kódu a doufání. Než sáhnete na hotspot, zafixujte jeho současné chování testy, i když je to chování zvláštní. Tyto charakterizační testy vám v tu ránu řeknou, že vaše změna mění něco, na čem uživatelé závisí.

  • Charakterizační testy pokrývají hlavní vstupy a výstupy modulu, který budete měnit
  • Alespoň jeden end-to-end test pokrývá kritickou uživatelskou cestu, která přes něj vede (registrace, pokladna, rezervace)
  • CI spouští testy u každého pull requestu a při selhání blokuje merge
  • Sledování chyb a základní metriky běží, takže regrese v produkci je vidět během několika minut
  • Existuje cesta zpět: flag, revert nebo předchozí nasazení, které můžete povýšit

Pokud kód vznikl rychle s AI nástroji a nemá téměř žádné testy, začněte tam. Minimální záchrannou síť popisuje náš produkční checklist pro aplikace z vibecodingu.

Čtyři klíčové metriky DORA jako výsledková tabule

Čtyři klíčové metriky DORA ukazují, jestli se práce na dluhu vyplácí, protože sledují rychlost a stabilitu dodávek zároveň: frekvenci nasazení, dobu realizace změn, podíl neúspěšných změn a dobu obnovy služby. Pokud splácení dluhu funguje, první dvě se zlepšují a poslední dvě klesají.

Čtyři klíčové metriky DORA a jak se v nich projevuje dluh
MetrikaCo měříJak jí dluh škodíKde ji získat
Frekvence nasazeníJak často dodáváte do produkceKvůli křehkému kódu týmy změny shromažďují do dávekLogy nasazení z CI/CD
Doba realizace změnOd commitu po běh v produkciPomalé code review, nestabilní testy, ruční krokyGit + časy nasazení
Podíl neúspěšných změnPodíl nasazení, která způsobí incident nebo rollbackProvázaný kód se rozbíjí na nečekaných místechEvidence incidentů + nasazení
Doba obnovy službyJak dlouho trvá zotaveníSlabá observabilita, riskantní rollbackyČasy incidentů

Než začnete, zaznamenejte výchozí stav, čtyři čísla procházejte každý měsíc a nepodlehněte pokušení dělat z nich individuální cíle. Popisují systém, ne lidi.

Jak vysvětlit dluh netechnickým stakeholderům

Vysvětlujte dluh v měně, kterou stakeholdeři už používají: čas uvedení na trh, riziko a peníze. Nikdo mimo engineering nepotřebuje slyšet o provázanosti nebo pokrytí testy. Potřebují slyšet, že změna cen trvá týden místo dne a že poslední dva výpadky vzešly ze stejného modulu.

  1. Pojmenujte byznysový symptom. „Každá změna cen trvá pět dní a tohle čtvrtletí dvakrát rozbila pokladnu.“
  2. Vyčíslete úrok. „Stojí nás to zhruba jeden inženýrský den na každou změnu plus čas na incidenty.“
  3. Navrhněte ohraničený krok. „Dva sprinty v rámci našeho běžného rozpočtu na dluh, abychom vyčlenili modul cen.“
  4. Slibte měřitelný výsledek. „Doba realizace změn cen pod dva dny, sledovaná na dashboardu DORA.“
  5. Podejte zprávu. Ukažte stav před a po. Důvěra, kterou tím získáte, zafinancuje další položku.

Práce na dluhu, kterou nejde vysvětlit jako rychlejší nebo bezpečnější produkt, obvykle není ten dluh, který splácet jako první.

Jak vám Backloo může pomoct

Pokud je váš tým přetížený, externí inženýr může provést měření, sestavit první registr a udělat nejriskantnější refaktoringy, zatímco váš tým dál dodává. To je jádro našich plánů údržby a SLA: pevný měsíční rozpočet na aktualizace, monitoring a plánovanou práci na dluhu.

U větších strukturálních problémů, jako je backend, který přerostl svůj první návrh, plánujeme migraci podle vzoru strangler fig v rámci backendových systémů. Nevíte, kde začít? Rescue Audit vám dá seřazený písemný přehled dluhu — a vždycky se nám můžete nejdřív ozvat.

Otázky

Kolik kapacity sprintu by mělo jít na technický dluh?

Univerzální číslo neexistuje. Zvolte pevný podíl, který dokážete udržet v každém sprintu, třeba jeden den z deseti, chraňte ho a po čtvrtletí ho upravte podle metrik DORA a vývoje incidentů.

Je úplný přepis někdy správná volba?

Někdy ano, když platforma přestala být podporovaná nebo je datový model zásadně špatně. I tehdy je ale postupná náhrada podle vzoru strangler fig obvykle bezpečnější než přepnutí naráz. Než se zavážete, sepište argumenty i s důkazy.

Jaký je rozdíl mezi registrem dluhu a backlogem?

Backlog vypisuje práci. Registr dluhu vypisuje známý dluh s důkazy, průběžnou cenou, rizikem a vlastníkem, takže každou položku lze seřadit proti funkcím v byznysových pojmech. Zůstává krátký a prochází se jednou měsíčně.

Jaké nástroje potřebuji k měření technického dluhu?

Na začátek jen historii gitu, linter a evidenci incidentů. K nalezení prvních hotspotů stačí spojit četnost změn, složitost a označení incidentů v tabulce. Specializované nástroje přidejte, až se z toho stane zvyk.

Čtěte dál

  • 01 — Záchrana · 9 min čtení

    Aplikace z Lovable nebo Bolt funguje v náhledu, ale v produkci se rozbije: příčiny a řešení

    Většina aplikací postavených s AI, které fungují v náhledu a v produkci selžou, padá ze stejné hrstky důvodů: proměnné prostředí zapečené při buildu, přesměrování přihlášení stále mířící na náhled, chybějící autorizace v databázi, webhooky, které nejsou idempotentní, CORS a žádný monitoring chyb. Každý z nich má konkrétní a ověřitelné řešení.

  • 02 — Záchrana · 9 min čtení

    Checklist Supabase Row Level Security pro aplikace postavené s AI (s SQL)

    Pokud vaše aplikace komunikuje se Supabase přímo z prohlížeče, je Row Level Security vaším řízením přístupu. Zapněte RLS na každé vystavené tabulce, pro každou operaci napište jednu policy s auth.uid(), klíč service_role držte na serveru, zabezpečte storage buckety a testujte jako anonymní uživatel i jako druhý účet. SQL ke zkopírování najdete níže.

  • 03 — Byznys · 7 min čtení

    Záchrana, refaktoring, nebo přepis? Jak se rozhodnout, co s kódem postaveným s AI

    Zachraňujte, když produkt funguje a problémy jsou v zabezpečení, konfiguraci a chybějících pojistkách. Refaktorujte, když funguje, ale každá změna je pomalá a riskantní. Přepisujte, jen když je zásadně špatně datový model nebo platforma — a i pak po částech. Rozhoduje datový model, ne to, jak neuspořádaně kód vypadá.

100 — INSIGHTS

Zaseknutí mezi demem a spuštěním?

Pošlete nám kontext. Do 24 hodin dostanete odpověď s plánem — nebo upřímné ne.