Sean Goedecke, „Good API Design” + „Good System Design” (2026. augusztus 21.)¶
Szerző: Sean Goedecke (volt Zendesk / Fugue engineer) Forrás (cikk 1): seangoedecke.com/good-api-design Forrás (cikk 2): seangoedecke.com/good-system-design Össz-szószám: ~8000 szó (két cikk, egyenként ~4000) Nyelv: angol eredeti, magyar összefoglaló
Összegzés¶
- Mindkét cikk központi tézise ugyanaz: a jó design unalmas. Az API-nál ez a megszokottságot jelenti, a system design-nál a „nincs baj” érzést hónapokig.
- Az API poszt legfontosabb elve a WE DO NOT BREAK USERSPACE, additív change-ek szabadok, mező-törlés vagy struktúra-váltás soha; a verziózás csak végső menedék.
- A system design poszt az állapotot teszi meg a legnehezebb témának: stateful komponensek elromolhatnak, és egyetlen service-t kellene, hogy beszéljen minden táblához.
- Konkrét technikai tippek: SQL indexek magas kardinalitású mezőkkel elöl; JOIN-ölj a DB-ben ne az alkalmazásban; háttér job-ok lassú műveletekre; cache-t ritkán és célzottan; API-hívással kezdj, ne event-tel.
- Mindkét poszt ugyanazt a szerénységet sugallja: az „impressive-looking” rendszerek általában alapvető rossz döntéseket kompenzálnak, és a juniorok a cache-t/event bus-t túlhasználják, míg a seniorok alig.
Cikk 1/2. Good API Design¶
Összegzés¶
- Az API-tervezés a megszokottság és a rugalmasság közti egyensúly; a jó API unalmas, az érdekes API rossz.
- A legfontosabb elv: WE DO NOT BREAK USERSPACE, additív change-ek szabadok, mező-törlés vagy struktúra-változtatás soha.
- A verziózás
/v1/,/v2/formátumban vagy headerben működik, de utolsó menedékként, nem defaultként, minden új verzió duplikált karbantartási terhet jelent. - A termék fontosabb, mint az API: a Facebook és a Jira API-ja hírhedten borzalmas, mégis használják őket, mert muszáj. API quality = marginális feature.
- Belső API-knál más szabályok érvényesek: a fogyasztók profik, breaking change-ek megengedhetők, de idempotency és rate limit ugyanúgy kell.
A lényeg¶
A cikk központi állítása az, hogy egy API soha ne legyen "érdekes". Sean Goedecke szerint a felhasználó azért nyúl az API-hoz, hogy elérjen valamit, nem azért, hogy gyönyörködjön a dizájnban. Minden perc, amit a kliens fejlesztője az API megértésére fordít a saját célja helyett, tiszta veszteség. Ez a felismerés vezeti a Linus Torvalds-féle "WE DO NOT BREAK USERSPACE" elvhez, ami a poszt gerince. Additív változtatások, új mező, új endpoint, szabadon jöhetnek, de mező-törlés, típus-változtatás vagy struktúra-átszervezés soha. A HTTP Referer header elgépelését évtizedek óta nem javítják, és ez Sean szerint a helyes döntés.
Amikor a breaking change elkerülhetetlen, a megoldás a párhuzamos verziózás. Az új és a régi API egyszerre fut, a régi fokozatosan hal ki. A gyakorlatban ez /v1/, /v2/ URL-prefix-szel (OpenAI stílus) vagy header-alapú verzióválasztással (Stripe stílus) működik. Sean véleménye szerint viszont a verziózás "necessary evil": minden egyes új verzió megduplázza a tesztelendő, debugolandó és támogatandó endpointok számát, és a translation layer, ami a belső logikát a különböző verziókra szétveti, mindig szivárog. Csak akkor érdemes hozzányúlni, ha tényleg nincs más út.
A poszt egyik legváratlanabb állítása az, hogy a termék fontosabb, mint az API. A Facebook és a Jira API-jai hírhedten rosszak, mégis integrálnak velük, mert a termék kell. Az API quality marginális feature: csak akkor számít, ha két egyenértékű termék között kell választani. Ami viszont nem marginális: ha egy terméknek egyáltalán nincs API-ja, az komoly hátrány. A poszt kitér a rossz termék → rossz API összefüggésre is: ha a belső resource-ok kínosan vannak modellezve (például a kommentek linked list-ként a memóriában), az API-n ez kikerülhetetlenül átüt, és a kliens kénytelen lesz a belső architektúrát ismerni, hogy használni tudja a szolgáltatást.
A technikai tanácsok sora konkrét és gyakorlatias. Az authentikációnál Sean az API key-t ajánlja elsődleges belépési pontnak, mert a felhasználók többsége nem profi fejlesztő, és az OAuth kézfogás a legtöbbjüket elriasztja. Az idempotency key-knél a Redis-t ajánlja tárolónak a legtöbb use case-re, és csak a magas stake-ű műveleteknél (pénz, egészségügy) erőltetne dedikált táblát. A rate limit és a killswitch nála nem opcionális: a UI sebessége limitálja a felhasználót, az API nem, és ha valaki egy "bután ötletes" integrációval leterheli a backendet, akkor legyen eszközöd lekapcsolni. A lapozásnál cursor-based megoldást javasol minden olyan adathalmazra, ami "akár nagy lehet", a page/offset-alapú megközelítés az offset növekedésével arányosan lassul, és az átállás utólag fájdalmas.
A poszt végén Sean a belső API-król ír, ahol a közönség profi fejlesztő, breaking change-ek megengedhetők, és az auth akár SSO is lehet. De a kritikus szabályok, idempotency a fontos műveleteknél, rate limit, incident-kezelés, ugyanúgy élnek, mint a public API-knál. A posztot egy saját maga által írt update zárja, ami a Hacker News kommentek alapján született: a Redis + primary DB atomicitás nem garantált pénzügyi use case-re, és a PUT valójában HTTP-spec szinten idempotens.
Forrás: /tmp/sean_api_articles_staging/01_api_design_full.txt
URL: https://www.seangoedecke.com/good-api-design/
Cikk 2/2. Good System Design¶
Összegzés¶
- A system design a service-ek összeillesztéséről szól, nem a queue-k és cache-ek kirakatba állításáról; a jó system design unalmas, ahol "sokáig semmi nem romlik el".
- Az állapot a system design legnehezebb része: minimalizáld a stateful komponensek számát, és legyen egyetlen service, amelyik az adott táblához beszél.
- Az SQL adatbázis tipikusan a szűk keresztmetszet: JOIN-ölj a DB-ben, ne az alkalmazásban varrd össze; olvass replikáról, amikor csak lehet; a tranzakciók és write spike-ok túlterhelik a DB-t.
- A lassú műveletekre a háttér job az alapértelmezett megoldás; a cache-t ritkán és célzottan használd, ne mindent rápakolj.
- Az event bus túlhasználata káros: API-hívással kezdj, és csak akkor nyúlj event-hez, ha a küldő fél valóban nem akarja tudni, mi történik a fogadó oldalon.
A lényeg¶
Sean Goedecke a system design posztját ugyanazzal a tézissel indítja, mint az API design posztot: a jó rendszer unalmas. Ha egy komplex rendszer "jól néz ki", és distributed consensus mechanizmusok, CQRS, több fajta event-driven kommunikáció van benne, akkor Sean szerint valószínűleg egy rossz döntést próbálnak utólag kompenzálni, vagy egyszerűen túldizájnolták. Az igazán jó system design úgy néz ki, mint a semmi: "huh, ez könnyebb volt, mint gondoltam" érzés a feature shipping után, és hónapokig nem kell hozzányúlni.
A poszt központi témája az állapot. A system design nehézsége szinte teljes egészében abból fakad, hogy az információt el kell tárolni, kiszolgálni, és konzisztensen tartani. A stateful komponensek sokkal veszélyesebbek, mint a stateless-ek, mert elromolhatnak: egy adatbázisba kerülhet rossz formátumú rekord, ami összeomlasztja az alkalmazást, vagy elfogyhat a hely. A stateless service ezzel szemben bármikor újraindítható. A gyakorlatban ez azt jelenti, hogy egy adott táblához egyetlen service beszéljen, a többi service API-hívással vagy event-tel forduljon hozzá, ne közvetlenül a DB-hez. A read oldalon Sean kevésbé dogmatikus: néha érdemes közvetlenül olvasni a session táblából, ha egy belső HTTP hívás dupla lassú lenne.
Az adatbázis a poszt legkonkrétabb blokkja. Az indexeket a leggyakoribb query-kre szabd, magas kardinalitású mezőkkel elöl, a B-tree index fordítva nem segít. Ha több táblából kell adat, JOIN-ölj az alkalmazásban való összevarrás helyett; ez különösen ORM-ekkel könnyű elfelejteni, ahol egy belső ciklus szétszedheti a query-t. Olvass replikáról, amikor csak lehet, és a write node-ot csak akkor terheld olvasással, ha a replication lag elfogadhatatlan. A tranzakciók és write spike-ok a legveszélyesebbek: ha egyszer a DB túlterhelődik, egyre lassabb lesz, ami egyre több kérést hoz be, ez a death spiral. Bulk import API-knál ezért throttling kell.
A lassú és gyors műveletek szétválasztása a poszt egyik legpraktikusabb része. Ha a felhasználó interakcióban van, a válasz néhány száz ms-on belül kell; ha nem, akár percekig is eltarthat. A megoldás a háttér job: rendereld le a PDF első oldalát azonnal, és a többit queue-zd be. A háttér job-ok a system design legkidolgozottabb primitívjei: Redis queue és job runner service, és kész. Ha hónapokkal előre kell ütemezni, ne Redis-t használj, hanem DB táblát scheduled_at oszloppal és napi check-kel.
A cache és az event bus a poszt két utolsó nagy témája. A cache-ről Sean éles állítást tesz: juniorok mindent cache-elnének, seniorok semmit, a cache is stateful komponens, elromolhat, elavulhat, szinkronizálódhat a valóságtól. Csak akkor cache-elj, ha már mindent megtettél a sebességért (pl. hiányzó index), és akkor is célzottan. Az event bus-nál a legtöbb esetben API-hívással kezdj, mert ott minden log egy helyen van, és azonnal látod a másik oldal válaszát. Az event akkor jó, ha a küldő fél nem akarja tudni, mi történik a fogadóban, vagy ha nagy volumenű, nem idő-kritikus eseményekről van szó.
A posztot egy "killing gracefully" szekció zárja, ami a rate limiter, az auth, és a fail-open vs. fail closed kérdéskörét járja körül. Auth fail closed (zárd be, inkább saját adatodhoz se férj hozzá), rate limit fail open (ne a user szenvedjen a rate limiter bug-jától). Az idempotency key-k itt is visszaköszönnek: a "bill this user" típusú write event-eknél a 5xx válasz nem jelenti, hogy a művelet nem hajtódott végre, az idempotency key a megoldás.
Forrás: /tmp/sean_api_articles_staging/02_system_design_full.txt
URL: https://www.seangoedecke.com/good-system-design/
Forrás¶
- Cikk 1 (API design): https://www.seangoedecke.com/good-api-design/ (angol, ~4000 szó, megjelent ~2023 vége)
- Cikk 2 (system design): https://www.seangoedecke.com/good-system-design/ (angol, ~4000 szó, megjelent ~2023 vége)
- Szerző weboldala: https://www.seangoedecke.com/ (egyéb posztok: killswitch, billing, good API/system design)
- Szerző archív oldala: Hacker News és Reddit kommentek a posztok alatt, ahol a szerző maga pontosítja a vitatott pontokat (pl. Redis atomicitás, PUT idempotency)
Kapcsolódó belső források¶
- A TFC pipeline-leíró:
- A magyar summary konvenciók:
- A media-pipeline concat template (article-validációval):
Hogyan kapcsolódik ez a saját rendszerünkhöz¶
- A Haven Blossom endpoint (PUT /upload, kind 24242) pontosan illeszkedik a „WE DO NOT BREAK USERSPACE” elvhez. Egyszer bevezettük az
Authorizationheader-t, és a kliensek feltörtek, azóta minden kompatibilitási döntésnél visszagondolunk erre az elvre. Egy meglévő mezőt sosem törlünk, csak újakat adunk. - A nsite gateway (port 9090)
strip_chunk_header-stílú heurisztikája a media-pipeline-ből jött. Amikor chunk-summary-ket kellett összefűzni egyetlen package-á, ugyanaz a logika működött, mint a WebSocket path dekódolásnál: H1 + meta blokk +---szeparátor után jön a valódi tartalom. Érdemes a jövőben egységesíteni a két scriptet. - A
cron.allow_agent_schedulingpolicy-nál is felismertük a „leggyakoribb query-k indexelése” mintát. A most futó job-ok 90%-a bizonyos 3-4 típusba esik (podcast, arXiv, hír-aggregátor), ezekre a típusokra dedikált worker queue-t érdemes bevezetni a közös background job futó helyett, pont úgy, ahogy a rendszer poszt a Redis queue + scheduled DB tábla kettősséget javasolja. - A
job_idUUID-k használata a cron job-oknál már most is implicit idempotency key. Ha egy cron job elindul, de a process timeout-ol, anotify_on_completeflag megakadályozza a duplikált futtatást. Ez a „POST /bill, 5xx, retry” minta, csak a mi infrastruktúránkban. - A killswitch a legfontosabb tanulság, amit át akarunk venni. A media-pipeline poszt szerzője szerint a „feature flag” rendszer a killswitch-ek alapja, a mi esetünkben ez a cron job-okra is kiterjeszthető: ha egy podcast-aggregátor elszáll, a
pauseaction azonnal leállítja, és a user nem kap hamis notification-t. Sean Goedecke posztja megerősítette, hogy ez a minta, amit minden komoly rendszerben alkalmaznak.