Frankenstein v programování je kód sestavený z nekompatibilních částí různých technologií, stylů a architektur. Podle výzkumu ThoughtWorks Technology Radar (2024) vykazuje 28 % velkých projektů známky Frankensteinova syndromu — architektonického eklekticismu vznikajícího při absenci jednotné technické vize. Analogicky k románu Mary Shelleyové takový kód funguje, ale jeho údržba se stává noční můrou.
Hlavní body
Frankenstein (Frankenstein code, Frankenstein pattern) je antipattern, při kterém je softwarový systém sestaven z částí, které nejsou určeny ke spolupráci. Stejně jako Frankensteinovo monstrum může takový kód fungovat, ale je ošklivý, nepředvídatelný a nebezpečný při sebemenších změnách.
Tento termín pochází z literatury: v románu Mary Shelleyové „Frankenstein, neboli moderní Prométheus” (1818) vytvořil vědec živou bytost z fragmentů těl různých zemřelých lidí. V programování je analogie přesná — vývojáři berou kusy různých frameworků, knihoven, jazyků a lepí je dohromady, čímž vzniká fungující, ale příšerný výsledek.
Rozdíl Frankensteina od špagetového kódu spočívá v měřítku a povaze problému. Špagetový kód je zamotaná struktura v rámci jednoho technologického stacku. Frankenstein je eklekticismus na úrovni architektury: různé technologie, nekompatibilní paradigmata, konfliktní přístupy v rámci jednoho systému.
Mikroslužbová architektura umožňuje použití různých technologií pro různé služby, ale za podmínky jasných hranic a standardizovaných komunikačních protokolů. Frankenstein je chaotické míšení bez hranic: REST a GraphQL v jednom kontroleru, dvě ORM v jednom modulu, SQL a NoSQL pro stejnou entitu.
Absence technického lídra nebo architekta je hlavní příčinou. Když v projektu není nikdo odpovědný za integritu architektury, každý vývojář si vybírá nástroje „pro sebe”. Jeden má rád Spring, druhý Guice, třetí vlastní DI. Výsledkem je architektonický mišmaš.
Sloučení projektů je druhou běžnou příčinou. Dva týmy vyvíjely své moduly nezávisle s použitím různých stacků. Když je potřeba moduly sjednotit do jedné aplikace, jednoduše se „slepí” adaptéry a mezivrstvami. Vzniká Frankenstein.
Firemní akvizice jsou třetím scénářem. Společnost A koupila společnost B a chce integrovat její produkt do svého. Místo přepsání — slepení přes API, sdílené databáze a provizorní řešení. Po roce se systém změní v monstrum, kterému nikdo nerozumí.
| Příčina | Popis | Typický výsledek |
|---|---|---|
| Žádný architekt | Každý vývojář si volí svůj stack | 3 různí HTTP klienti v jednom modulu |
| Sloučení projektů | Dva produkty se spojují v jeden | Dvě ORM, dva způsoby logování |
| M&A | Akvizice společnosti s jejím produktem | Hybrid různých architektur a stylů |
| Experimenty | Zavádění nových technologií bez strategie | Java 8 + Java 21 funkce v jednom souboru |
| Politická rozhodnutí | Vnucování technologie shora bez kontextu | Enterprise framework pro jednoduchý skript |
Zkušení vývojáři, kteří chtějí vyzkoušet nové technologie v produkci, se často stávají zdrojem Frankensteina. Místo omezení experimentů na izolovaný modul zavádějí experimentální kód do kritické části systému.
Klasickým příkladem je použití více ORM v jedné aplikaci. Některé moduly používají Hibernate, jiné MyBatis a další přímé JDBC dotazy. Transakce se stávají neovladatelnými, cache je nekonzistentní a nový vývojář neví, který přístup zvolit pro novou funkci.
Druhým příkladem je míšení architektonických stylů. V kontroleru REST API se nacházejí volání SOAP služeb, přímé SQL dotazy, přístup k souborovému systému a generování HTML. Takovou aplikaci nelze testovat, rozšiřovat ani dokumentovat.
Třetím příkladem je technologický stack, kde je Python použit pro backend, Node.js pro mikroslužbu, C# pro desktopového klienta a Java pro Android aplikaci, přičemž veškerá business logika je rozprostřena mezi nimi bez jasného rozdělení odpovědnosti.
// frankenstein — smíšené styly a technologie
// callbacks, Promises a async/await kombinované
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// Promise uvnitř callbacku
fetch("/api/data").then(function(data) {
// async/await uvnitř then
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// čistý kód — jednotný styl async/await
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
Jedna databáze je používána současně jako SQL relační (s normalizací) a jako NoSQL dokumentově orientovaná (s JSON sloupci). Část dotazů jde přes ORM, část přes uložené procedury, část přes přímé SQL z kódu. Schéma databáze není zdokumentováno, migrace kolidují.
Složitost onboardingu je prvním důsledkem. Nový vývojář musí znát 5 jazyků, 3 frameworky, 2 architektonické styly, aby pochopil, jak systém funguje. Onboarding se protahuje z týdnů na měsíce. Podle LinkedIn (2023) ztrácejí projekty s technologickým eklekticismem nové zaměstnance 2krát častěji.
Nepředvídatelnost chování je druhým důsledkem. Změna v Python mikroslužbě může nečekaně rozbít Java modul, protože používají sdílenou databázi bez jasných kontraktů. Ladění takových problémů vyžaduje současnou znalost všech technologií ve stacku.
Bezpečnost je třetím důsledkem. Každá technologie ve stacku vyžaduje svou vlastní konfiguraci zabezpečení, své patche, své monitorování. Udržet bezpečnost na přijatelné úrovni pro 5–6 různorodých technologií je prakticky nemožné. Jedna z nich se nevyhnutelně ukáže jako zranitelná.
SonarQube může měřit technický dluh, ale nemůže měřit „architektonický dluh” — nekompatibilitu komponent. Tento dluh se neprojevuje ve varováních linteru, ale v nemožnosti přidat novou funkci bez změny tří různých modulů napsaných v různých technologiích.
Prvním a nejdůležitějším krokem je jmenovat architekta nebo tech leada odpovědného za integritu technologického stacku. Tato osoba má právo veta na zavádění nových technologií bez architektonického posouzení. Ne demokracie, ale odpovědné individuální rozhodnutí o klíčových technologiích.
Druhým — zavést proces Architecture Decision Record (ADR). Každé významné architektonické rozhodnutí (volba databáze, frameworku, protokolu) je zdokumentováno jako krátký text: kontext, zvažované alternativy, přijaté rozhodnutí, důsledky. ADR jsou uloženy v repozitáři a dostupné celému týmu.
Třetím — stanovit princip „jeden úkol — jeden nástroj”. Pro HTTP požadavky — jeden klient. Pro ORM — jedna knihovna. Pro logování — jeden framework. Výjimky jsou povoleny pouze přes ADR s odůvodněním. Pokud je v projektu již Axios — nepřidávejte fetch, pokud je SLF4J — nepište přes System.out.
Experimenty jsou povoleny, ale v izolovaném prostředí. Vyčleňte modul nebo službu, kterou lze přepsat novou technologií bez vlivu na zbytek systému. Pokud se experiment podaří — standardizujte jej přes ADR. Pokud ne — odstraňte jej bez následků.
Inventarizace je prvním krokem. Vytvořte úplnou mapu technologického stacku: jaké frameworky, knihovny, jazyky, protokoly se používají, ve kterých modulech a pro jaké úkoly. Uvidíte rozsah problému: duplicitní nástroje, konfliktní technologie, nepoužívané závislosti.
Standardizace je druhým krokem. Vyberte jeden nástroj pro každý úkol. Například: pouze Hibernate pro ORM, pouze SLF4J + Logback pro logování, pouze REST pro API. Zdokumentujte standard v ADR. Začněte náhradu v modulech, kde eklekticismus způsobuje nejvíce problémů.
Strategie Parallel Run je třetím krokem. Staré a nové nástroje pracují paralelně, dokud nový neprokáže svou spolehlivost. Například starý HTTP klient a nový pracují současně, ale nový pouze pro část požadavků. Po období stabilizace je starý odstraněn.
// frankenstein — tři HTTP přístupy v jednom projektu
// Modul A: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// Modul B: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// Modul C: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// jednotný přístup: RestTemplate pro sync, WebClient pro reactive
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
Technický lídr je hlavním nástrojem v boji proti Frankensteinovi. Ne manažer, ne architekt ve slonovinové věži, ale praktikující vývojář, který píše kód, reviewuje PR a přijímá architektonická rozhodnutí. Bez takového člověka projekt nevyhnutelně sklouzává k technologickému eklekticismu.
RFC (Request for Comments) je proces převzatý z komunit otevřeného zdroje. Před zavedením jakékoli významné technologie autor napíše RFC: problém, navrhované řešení, alternativy, plán implementace. Tým diskutuje, hlasuje, přijímá nebo odmítá. RFC vytváří transparentnost a zabraňuje „tichým” architektonickým rozhodnutím.
Technologický radar (Technology Radar od ThoughtWorks) je nástroj pro kategorizaci technologií: Adopt, Trial, Assess, Hold. Tým pravidelně přezkoumává radar a aktualizuje statusy. To pomáhá odlišit „modní” od „užitečného” a vyhnout se zavádění nevyzkoušených technologií do kritického kódu.
Nejdůležitější vlastností architektury je konzistence (consistency). I ne nejlepší nástroj používaný v celém projektu je lepší než nejlepší nástroj používaný pouze v jednom modulu. Konzistence snižuje kognitivní zátěž, zjednodušuje onboarding a činí kód předvídatelným.
Často kladené otázky
Polyglot persistence je vědomé používání různých databází pro různé úkoly (PostgreSQL pro transakce, Redis pro cache, Elasticsearch pro vyhledávání). Frankenstein je chaotické míšení bez strategie. Rozdíl spočívá v přítomnosti architektonického rozhodnutí: polyglot je plán, Frankenstein je jeho absence.
Ano, a je to častý problém. Když každá mikroslužba používá svůj vlastní jazyk, databázi, protokol a přístup k nasazení bez centralizovaných standardů — vzniká distribuovaný Frankenstein. Pro mikroslužby jsou důležité společné standardy: jednotný protokol (REST/gRPC), jednotný formát logů, centralizovaná observability.
Nezakazujte — veďte. Požádejte autora RFC: popište, proč stávající řešení není vhodné, jaké alternativy byly zváženy, jak bude migrace provedena. Často během psaní RFC vývojář sám pochopí, že nová technologie není potřeba. Pokud je RFC přesvědčivé — implementujte, ale s plánem a omezeními.
Nejprve inventarizace, poté standardizace. Nesnažte se přepsat vše najednou. Vyberte jednu vrstvu (například HTTP klienty nebo logování), zvolte jednotný nástroj, napište ADR a migrujte postupně. Metoda Strangler Fig — nahrazujte staré komponenty jednu po druhé bez zastavení aplikace.
Čím méně, tím lépe. Ideálně — jeden jazyk, jeden framework, jedna databáze, jeden způsob logování. Realisticky — 2–3 jazyky (s jasným oddělením), 1–2 databáze, 1–2 frameworky. Každá další technologie zvyšuje kognitivní zátěž týmu a náklady na údržbu.
Shrnutí
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í.
Přečtěte si také