Az architektúrádnak nincs memóriája

Az architektúrádnak nincs memóriája

Közzétéve: 2026. október 30.

Nézd meg videón

Ugyanez a tartalom YouTube-on is elérhető angolul, ha inkább videóban hallanád.

Megnézem YouTube-on

Szerda reggel, stand-up. Anna harmadik napja dolgozik backendfejlesztőként egy jegyértékesítő platformon.

Rendesen megcsinálta a házi feladatot. Az első napon megtalálta az architektúra-diagramot. A másodikon átolvasta a kódot. Közben pedig feltűnt neki valami: a nagy jegyárusítások alatt lassú a helyfoglalás. Fájdalmasan lassú. A megoldás meg szinte kínálja magát.

Úgyhogy amikor sorra kerül, ki is mondja: „Miért nem tartjuk a foglalásokat Redisben, rövid lejárattal? Sokkal gyorsabb lenne.”

És akkor... csend lesz.

Valaki hirtelen nagyon érdekesnek találja a kávéját. Valaki más Péterre pillant, az egyetlen emberre a csapatban, aki ott volt, amikor megtörtént.

Két évvel korábban ugyanis a csapat pontosan ezt csinálta. És működött is. Több mint egy évig szépen működött. Egészen a szezon legnagyobb jegyárusításáig, amikor a csúcs kellős közepén failover történt a Redisben. Egy adag foglalás egyszerűen eltűnt, és néhány száz helyet kétszer adtak el. Valódi embereknek, akik aztán ugyanarra a helyre szóló jeggyel álltak a kapuban.

Ami ezután jött, az egy hétnyi visszatérítés, bocsánatkérés és nagyon hosszú este volt. Utána a foglalások csendben visszakerültek az adatbázisba.

Anna ebből semmit sem tudott. Honnan is tudhatta volna? Az ábra, amit napokig nézett, helyes volt. Pontosan úgy mutatta a rendszert, ahogy ma kinéz, és Redis persze nem volt rajta. Azt viszont nem tudta megmutatni, hogy a Redis volt már ott, és azt sem, miért kellett mennie. A két ember közül, akik az egész történetet ismerték, az egyik tavasszal kilépett.

A csapat így a következő negyven percben egy olyan döntésről vitatkozott, amit egyszer már meghozott, drágán megfizette az árát, aztán visszacsinálta.

Ez nem Anna hibája. A rendszernek egyszerűen nincs memóriája.

Az ábra helyes volt, csak nem volt mögötte történet

És itt jön a furcsa rész: dokumentációban nem volt hiány. Volt diagram, és még naprakész is volt, ami ritkább, mint kellene. A másik fele viszont hiányzott.

Aki naponta használ Gitet, ismeri ezt a kettősséget. Egy checkout pillanatképet ad: a fájlokat, ahogy most állnak. Ez elég ahhoz, hogy futtassuk a kódot, ahhoz viszont nem, hogy megértsük. Ahhoz a history kell, a commitok, amelyek elmondják, mi változott, és ha valaki véletlenül rendes commit message-et írt, azt is, miért.

Az architektúra ugyanígy működik. Egy C4 diagram a pillanatkép: így néz ki a rendszer ma. Az architektúra-döntési rekordok (ADR-ek) a diffek: mindegyik elmondja, mi változott az architektúrában, és miért ezt választotta a csapat a többi lehetőség helyett.

A C4 diagram mint pillanatkép, az ADR-napló mint diffek sorozata

A pillanatkép megmutatja, mi van, a diffek elmagyarázzák, miért.

Szóval mindkettőre szükség van. A history nélküli pillanatkép elárulja, mi van, de azt soha, hogy miért. Anna pontosan itt tartott a harmadik napján: egy tökéletesen pontos ábrát nézett, ami semmivel sem tudta figyelmeztetni. A pillanatkép nélküli history viszont ugyanennyire használhatatlan: senki sem olvas végig negyven ADR-t egymás után, hogy fejben visszajátszva kitalálja, hogyan néz ki most a rendszer.

A pillanatkép: általában két C4 ábra elég

Arról, hogyan rajzoljunk olyan diagramot, amit tényleg el lehet olvasni, már írtam korábban, úgyhogy itt csak a rövid változat jön. A Simon Brown által kidolgozott C4 négy nagyítási szintet ad: System Context, Container, Component és Code. A pillanatkép szerepét nagyrészt az első kettő viszi.

A System Context ábrán a rendszerünk egyetlen doboz, körülötte a felhasználók és azok a külső rendszerek, amelyektől függ. Anna platformján ez a vásárló és a szervező, maga a jegyértékesítő platform, egy fizetési szolgáltató, egy e-mail-szolgáltató és a helyszíni beléptető szkennerek.

A Container ábra ebbe a dobozba nagyít bele, és megmutatja, miből áll: a vásárlói webapp, a szervezői portál, a fő API (egy moduláris monolit), a PostgreSQL, egy queue egy notification workerrel, és egy külön beléptető service a saját kis adatbázisával. A C4-ben a container persze nem Docker konténert jelent, hanem bármit, ami önállóan fut vagy adatot tárol.

Component diagramot csak ott érdemes rajzolni, ahol az emberek tényleg eltévednek, a Code szintet pedig nyugodtan rábízhatjuk az IDE-re. Végül is minden további szint egy újabb dolog, ami elavulhat.

A diff: mit rögzít egy ADR

Mi spórolta volna meg azt a negyven percet? Egy rövid dokumentum egyetlen architekturális döntésről. Ennyi az ADR. A legtöbb template Michael Nygard 2011-es írására vezethető vissza, és a kulcsszó itt tényleg a rövid: egy-két oldal. Én ezt a szerkezetet használom:

  • Cím: mit döntöttünk el, nem azt, miről beszélgettünk. „Helyfoglalások PostgreSQL-ben”, nem „Adatbázis-egyeztetés”.
  • Státusz: Proposed, Accepted, Rejected, vagy Superseded egy későbbi ADR által.
  • Kontextus: a helyzet, és azok a kényszerek, amelyek most hatnak rá.
  • Megfontolt opciók: legalább kettő, valódi. A „nem csinálunk semmit” is opció.
  • Döntés: egy-két mondat.
  • Következmények: a jók, és a rosszak is, amelyeket tudatosan vállalunk. A későbbi olvasóknak erre van a legnagyobb szükségük, a csapatok mégis ezt hagyják ki a leggyakrabban.
  • Érintett containerek: mely dobozokat ad hozzá, veszi el vagy alakítja át a diagramon.
  • Újragondolás, ha: egy konkrét trigger, amikor újra elő kell venni: csapatméret, forgalmi szám vagy dátum.

Az utolsó kettő nincs benne Nygard eredeti template-jében. Pedig pont ezek kötik a döntést a pillanatképhez, és ezek akadályozzák meg, hogy csendben elavuljon.

Egyetlen szabály teszi az ADR-eket commitszerűvé: amit elfogadtunk, azt nem szerkesztjük. Ha a csapat meggondolja magát, új ADR-t ír, amely felváltja a régit, a régin pedig egyetlen dolog változik: a státusza „Superseded by” lesz. Ahogy a main-re már kipusholt commitokat sem írja át senki: új commitot adunk hozzá, ami revertálja a régit, és a history őszinte marad.

És íme a rekord, amit Anna sosem olvashatott el. A fájdalmas márciusi döntés, rövidítve:

# ADR-0006: Helyfoglalások PostgreSQL-ben

Státusz: Accepted (2026-03-24) · Felváltja: ADR-0004

## Kontextus
A márciusi jegyárusítás alatt failover történt a Redis primaryn. Az utolsó
másodpercekben írt foglalások nem jutottak át a replikára; ~300 hely felszabadult,
és kétszer eladtuk. A helyfoglalás a rendelés helyességének része, nem cache.

## Megfontolt opciók
1. Redis megerősítése (szigorúbb perzisztencia, szinkron replikáció): gyors, de két source of truth
2. Foglalások PostgreSQL-ben: expires_at oszlop, row lock SKIP LOCKED-dal, sweeper job
3. Nem csinálunk semmit: ritka dupla eladások, kézi visszatérítés

## Döntés
A 2. opció. A helyek állapotának egyetlen source of truth-ja legyen.

## Következmények
+ Failovernél nem vesznek el foglalások; a foglalás és a rendelés egy tranzakcióban commitol
+ Eggyel kevesebb rendszert kell üzemeltetni
- Nagyobb írási terhelés a PostgreSQL-en a csúcsokon (a márciusi csúcs 3×-ára load-teszteltük)
- A sweeper job új mozgó alkatrész, riasztás kell rá

## Érintett containerek
Ticketing API, Main DB · megszűnik: Seat Hold Cache (Redis)

## Újragondolás, ha
A jegyárusítási csúcs meghaladja a 2026. márciusi csúcs háromszorosát, vagy a p95 foglalási idő 300 ms fölé megy

Nézzük meg egy pillanatra azt a kontextus részt. Három mondat, és benne van az egész hétnyi visszatérítés. Pont az a történet, amit Péternek fejből kellett volna elmesélnie.

Egy korábbi írásomban szereplő megkötés itt is érvényes: az utólag, csak a dokumentum kedvéért megírt ADR nyugta, nem döntési rekord. Az értéke abból jön, ha a döntés előtt születik meg, mert így a csapat kénytelen tényleg végigbeszélni a döntést. Az alábbiak mind azt feltételezik, hogy a csapat így dolgozik.

A history olvasása, mintha commit log lenne

Ha a kettőt egymás mellé tesszük, a platform architektúrája gyakorlatilag egy rövid commit logként olvasható. Minden sor egy kis történet:

  • ADR-0001: moduláris monolittal indulunk. Három fejlesztő, egyelőre nincs ok microservice-ekért fizetni. Újra kell gondolni, ha háromnál több csapat dolgozik a kódbázisban.
  • ADR-0002: a PostgreSQL az egyetlen fő adattár.
  • ADR-0003: a vásárlók a fizetési szolgáltató hosted oldalán fizetnek, így kártyaadathoz sosem nyúlunk, és a kártyás compliance munka nagy része kimarad.
  • ADR-0004: a helyfoglalások Redisbe kerülnek tízperces lejárattal, mert a jegyárusítások túlterhelték az adatbázist. Megjelenik egy új doboz.
  • ADR-0005: az e-mailek egy queue-n és egy workeren keresztül mennek, miután egy lassú e-mail-szolgáltató miatt várakoztak a fizetések. Két újabb doboz.
  • ADR-0006: a helyfoglalások visszakerülnek PostgreSQL-be. Felváltja az ADR-0004-et, a Redis doboz pedig eltűnik.
  • ADR-0007: a beléptetés saját service-t kap, mert a helyszíneken gyenge a hálózat, a szkennereknek offline is működniük kell, és később szinkronizálnak.

Látod az ADR-0004-et és az ADR-0006-ot? Ez Anna ötlete, a történet végével együtt, két sorban.

A leghasznosabb kép akkor születik meg, ha a tavalyi container diagramot a mai mellé tesszük, és minden változás mellé odaírjuk az ADR-t, ami okozta:

A container diagram egy évvel ezelőtt és ma, minden változás mellett az azt indokló ADR-rel

Zöld, ami bekerült, piros, ami kikerült, és minden változás mellett ott az ADR száma.

Most tekerjük vissza azt a stand-upot. Ugyanaz a szerda, ugyanaz az ötlet, csak ezúttal létezik a napló.

Anna kimondja, hogy „Redis”. Senki sem bámul a kávéjába. Péter csak annyit mond: „Jó az ösztönöd. Nézd meg előtte az ADR-0006-ot, egyszer már kipróbáltuk.”

Két perccel később Anna tudja, miért szedték ki a Redist. Lehet, hogy továbbra is a Redist tartja jó megoldásnak, és ez teljesen rendben van. Csakhogy most a javaslatának a failover problémájára is választ kell adnia, a beszélgetés pedig onnan indul, ahol a csapat már tart, nem a nulláról.

A negyven percből kettő lett. És senkinek sem kellett újraélnie az év legrosszabb hetét.

Hogyan kapcsoljuk össze a két felet

Van azért egy csapda. Mindez nem működik, ha a diagram az egyik eszközben él, az ADR-ek egy másikban, és semmi sem mutat egyikből a másikba. Szerencsére ezt három apró szokás megoldja.

Mindkettő a repositoryban van. Egy docs/architecture/ mappa a szövegként leírt diagrammal (Structurizr, Mermaid vagy PlantUML), és egy decisions/ mappa, ADR-enként egy számozott Markdown fájllal. Pull requestben review-zzuk őket, és ugyanaz a keresés hozza fel őket, mint a kódot, és ez már több, mint amit a legtöbb wiki tud.

A linkek mindkét irányba mutatnak. Minden ADR felsorolja, mely containereket érinti, és minden container felsorolja a mögötte álló ADR-eket. Structurizr DSL-ben ez egy property az elemen:

api = container "Ticketing API" "Modular monolith" "Kotlin, Spring Boot" {
    properties {
        "adrs" "0001, 0003, 0006"
    }
}

Így bármelyik dobozra rá lehet kérdezni, hogy miért van ott, és egy kattintással megvan a válasz. Lényegében egy git blame az architektúrához.

Ugyanabban a pull requestben változnak. Ha egy elfogadott döntés hozzáad, elvesz vagy átköt egy dobozt, a diagram frissítése ugyanabba a PR-ba kerül, mint az ADR. Nem később, és nem egy külön ticketben. Szöveges diagramnál a reviewer a kép diffjét közvetlenül az azt okozó döntés mellett látja. Ez az egy szabály őszintén szólva jobban naprakészen tartja a pillanatképet, mint bármilyen negyedéves dokumentációs sprint.

Onboarding: előbb a pillanatkép, aztán a fontos diffek

Adjuk meg Annának azt az első hetet, ami járt volna neki. Ha mindkét fél megvan, négy lépésben vezetném be:

Négylépéses onboarding: context, container, a releváns ADR-ek, végül component és kód

Előbb a pillanatkép, aztán csak azok a diffek, amelyek a munkájához kellenek.

A System Context öt perc. A Container diagram tizenöt, lehetőleg úgy, hogy egy kolléga végigvezeti rajta: itt jön be a rendelés, itt foglaljuk a helyet, ott megy ki az e-mail. Utána jönnek azok az ADR-ek, amelyek a ténylegesen érintett dobozok mögött állnak. Anna a checkouton fog dolgozni, ezért a helyfoglalásról és a fizetésről szóló döntéseket olvassa el, nagyjából öt dokumentumot, fél óra alatt. Csak ezután jön a saját containerének component nézete, és végül a kód.

Érdemes ezt összevetni a megszokott „itt a repo, itt a wiki, kérdezz, ha valami nem világos” megoldással. A kérdések bizony jönnek is. Egyesével, hónapokig, és mindegyik válasz azon múlik, hogy éppen ki emlékszik rá. A pillanatkép alapján egy új ember már az első órában tudja, mi hol van. A diffekből pedig azt is tudja, mi szándékos, mi egy régi incidens öröksége, és mit nem választott igazán senki.

Ez az utolsó kategória amúgy nagyon hasznos. Ha egy doboz mögött nincs ADR, valószínűleg döntés nélkül nőtt oda, és nyugodtan meg lehet kérdőjelezni.

Van egy ráadás is: az új emberek kiváló reviewerei a dokumentációnak. Ha nem tudják követni a diagramot, akkor a diagram rossz, a legolcsóbb dokumentáció-frissítés pedig az, ha ők javítják ki, ami összezavarta őket.

Döntés: a következő diff megírása

Ugorjunk egy évet. Anna már nem új.

A cégnél már négy csapat dolgozik, és a payments csapat önálló service-be szeretné kiszervezni a fizetést, mert a monolitban folyton egymás lábára lépnek. A meeting be van rakva a naptárba. Mindenki hosszúra számít.

Ugyanez a struktúra itt is segít, csak a másik irányban: most a csapat nem olvassa, hanem bővíti a historyt. Én ezt egy körként vezetném végig:

Döntési kör: indulás a pillanatképből, a kapcsolódó ADR-ek elolvasása, javaslat és az „utána” ábra, döntés, az ADR és a diagram együttes merge-e

Minden elfogadott döntés egy diffel viszi előrébb a pillanatképet.

Indulj a pillanatképből. Kerüljön mindenki elé az aktuális container diagram. Meglepően sok architektúra-vita valójában arról szól, hogy két embernek két különböző kép van a fejében.

Olvasd el az érintett diffeket. Ezúttal Anna az, aki megnyitja az ADR-0001-et. Eszerint a monolitot újra kell gondolni, ha háromnál több csapat dolgozik a kódbázisban. Most négy van, a trigger tehát teljesült. És ettől egy csapásra megváltozik a meeting hangulata: senki sem a korábbi architekt ellen érvel, hiszen a korábbi döntés maga kérte, hogy nyissák újra. Az ADR-0003 is releváns. Bármit csinál az új service, nem húzhatja vissza a céget a kártyaadat-kezelésbe, és ezt a megkötést jobb a tervezés előtt ismerni, mint utána.

Írd meg az új ADR-t Proposed státusszal, és rajzold meg az „utána” ábrát. Hogyan néz ki a container diagram, ha elfogadjuk? Egy új payments service, talán saját adatbázissal, új, feliratozott nyilakkal. A lerajzolás jó próbája a javaslatnak. Ha a csapat nem tudja lerajzolni, még nem érti a javaslatot. Ha pedig az ábrán hirtelen tizenegy új nyíl jelenik meg, na, azt a beszélgetést most érdemes lefolytatni.

Dönts. Accepted vagy Rejected, és az elutasított ADR is a naplóban marad. Jövőre, amikor valakinek ugyanez az ötlete támad, megtalálja, az indokokkal együtt.

Az ADR és a frissített diagram együtt kerül be. A pillanatkép egy diffel előrébb lép, és innen indul újra a kör.

Az a meeting, amit mindenki hosszúra várt? Korábban véget ér.

Hol szokott elcsúszni

Szívesen mondanám, hogy minden csapat, amelyik belevág, boldogan él, míg meg nem hal. Nem így van. Ezek mindegyikét láttam már, nem is egyszer:

  • ADR mindenről. A logging library és a dátumformátum nem igényel döntési rekordot. Az ADR-eket a nehezen visszafordítható döntéseknek érdemes fenntartani: adattárak, határok, integrációs minták, biztonság és pénz. Különben a fontosak elvesznek a zajban.
  • Diagram minden szinten. A csapat fellelkesül a C4-től, minden containerhez component diagramot rajzol, és fél év múlva mind rossz. A Context és a Container szintet érdemes karbantartani, componentet csak oda rajzolni, ahol tényleg eltévednek az emberek.
  • Utólag írt ADR-ek. Amikor egy csapat most kezd, néhány visszamenőleges ADR jó gyakorlás. Ha viszont minden ADR azután születik, hogy egy Slack thread már döntött, a csapatnak lesz historyja, de jobb döntései nem.
  • Régi ADR-ek szerkesztése. Valaki „kijavítja” az ADR-0004-et, hogy megfeleljen a rendszer mai működésének, és máris elveszett a history. Anna Redis-ötletének megint nincs vége. Felváltani kell, nem szerkeszteni.
  • Nincs gazdája. A diagram elsodródik a valóságtól, és egy év után senki sem bízik benne. Ennek nagy részét megoldja, ha az ADR és a diagram ugyanabban a PR-ban változik, a maradékot pedig elkapja egy negyedévente tartott, tizenötperces átnézés a csapattal.

Ha a nulláról indulsz

Ha a csapatodban ebből még semmi sincs, nem kell nagyban kezdeni, az első változat lehet egészen kicsi. Rajzold meg a rendszer System Context és Container diagramját úgy, ahogy van, nem úgy, ahogy szeretnéd, és tedd be szövegként a repositoryba. Válaszd ki azt a három döntést, amire az újonnan érkezők a leggyakrabban rákérdeznek, azokat, amelyeknél mindig elhangzik, hogy „várj, ezt miért így csináljuk?”, és írj mindegyikhez egy rövid ADR-t, belinkelve azokhoz a dobozokhoz, amelyeket megmagyaráznak. Állapodjatok meg abban, hogy ha egy döntés megváltoztatja a diagramot, akkor ugyanabban a pull requestben változtatja meg. A következő nehezen visszafordítható döntésnél pedig a meeting előtt írd meg az ADR-t.

Ez nagyjából két napnyi munka.

És valahol már ott van a következő Annád. Az első napon megtalálja a diagramot, a másodikon átolvassa a kódot, a harmadikon pedig egy ötlettel jön a stand-upra. Lehet, hogy megint csend lesz.

De ezúttal azért, mert mindenki olvas.

Ha ebben segítség kell

Ha nálatok az új emberek hónapokig keresik a helyüket, vagy ugyanazok az architektúra-döntések néhány sprintenként újra előkerülnek, pont ebben segítek csapatoknak. Gyakorlatias architektúra-workshopokon a saját rendszeretekből indulunk ki, közösen megrajzoljuk a pillanatképet, és megírjuk az első ADR-eket a valóban fontos döntésekhez.

Ha inkább egy konkrét problémára keresel megoldást, konzultáció keretében átnézem a jelenlegi architektúrát és dokumentációt, és együtt végiggondoljuk, hogyan lehet a következő döntéseket könnyebben meghozni, és később könnyebben megérteni.