Decyzje architektoniczne
Dziewięć rekordów ADR — decyzje, których cofnięcie kosztowałoby więcej niż tydzień pracy. Kontekst, decyzja, konsekwencje.
Po co ADR#
Każda decyzja, której cofnięcie kosztowałoby więcej niż tydzień pracy, ma swój rekord. Format jest stały: Kontekst → Decyzja → Konsekwencje → Odrzucone alternatywy. Status przyjęta oznacza, że kod i dokumentacja są z nią zgodne.
Lista decyzji#
| Nr | Decyzja | Status |
|---|---|---|
| 0001 | Izolacja adaptera przez porty | przyjęta |
| 0002 | Wersjonowany format JSON z łańcuchem migracji | przyjęta |
| 0003 | Brak ECS — prototyp oceniony i odrzucony | przyjęta |
| 0004 | WASM opcjonalny, tylko przy mierzalnej przewadze | przyjęta |
| 0005 | Brak SPA fallback — stan w query stringu | przyjęta |
| 0006 | Jedna wersja dla wszystkich pakietów | przyjęta |
| 0007 | Bramy jakości jako blokujące komendy | przyjęta |
| 0008 | Playground jako jeden klasyczny plik HTML | przyjęta |
| 0009 | Dokumentacja jako generowana jedna strona | przyjęta |
0001 — Izolacja adaptera przez porty#
Decyzja: rdzeń nie importuje Phasera; cały runtime idzie przez sześć interfejsów (RenderPort, PhysicsPort, CameraPort, InputPort, AudioPort, AssetBackend).
Konsekwencje: kod gry testowalny w Node, wymienny backend, ale dodatkowa warstwa abstrakcji i konieczność feature-detection dla metod opcjonalnych. Pilnują tego ESLint i test skanujący źródła.
0002 — Wersjonowany format JSON#
Decyzja: projekt ma formatVersion i łańcuch migracji; eksport zawiera sumę FNV-1a.
Konsekwencje: stare projekty otwierają się w nowych wersjach silnika; migracje są addytywne i idempotentne.
0003 — Brak ECS#
Decyzja: prototyp ECS został zbudowany, zmierzony i odrzucony. Zostają komponenty z fazami systemowymi.
Konsekwencje: prostszy model mentalny i przewidywalna kolejność faz przy zachowaniu wydajności (0,72 ms/klatkę dla 20 000 obiektów). Pełny ECS wymagałby przebudowy indeksów i serializacji.
0004 — WASM opcjonalny#
Decyzja: most WASM istnieje, ale moduł dodajemy tylko po benchmarku TS vs WASM.
Konsekwencje: required: false nie wywala gry przy braku pliku; zespół nie utrzymuje natywnego kodu „na wszelki wypadek”.
0005 — Brak SPA fallback#
Decyzja: gra żyje pod stałym adresem katalogu, stan trzyma w query stringu; nieznane ścieżki zwracają 404.html.
Konsekwencje: względne ./assets/… działają w dowolnym podkatalogu; deep-linking po ścieżkach nie istnieje i nie jest potrzebny.
0006 — Jedna wersja dla wszystkich pakietów#
Decyzja: wszystkie pakiety w monorepo mają tę samą wersję (lockstep).
Konsekwencje: zero macierzy kompatybilności wewnętrznej; release jednego pakietu oznacza release wszystkich.
0007 — Bramy jakości jako blokujące komendy#
Decyzja: typecheck, test, bench:check i bundle:check kończą się kodem 1 przy problemie.
Konsekwencje: CI nie potrzebuje parserów wyjścia; regresja wydajności i rozmiaru blokuje merge tak samo jak błąd typów.
0008 — Playground jako jeden plik HTML#
Decyzja: npm run build:single tworzy playground.html działający bez sieci.
Konsekwencje: grę można wysłać mailem i otworzyć z dysku; próg rozmiaru single-file to +5%.
0009 — Dokumentacja jako generowana jedna strona#
Decyzja: kanoniczna dokumentacja to generowany docs/index.html z wyszukiwaniem i PL/EN.
Konsekwencje: dokumentacja działa offline i bez serwera; źródła pozostają w Markdown.
Jak dodać rekord#
- Numer kolejny, czterocyfrowy, plik
NNNN-krotki-opis.md. - Wpis w tabeli indeksu —
scripts/release.mjs --checkzgłasza rekord bez wpisu. - Sekcje: Kontekst, Decyzja, Konsekwencje (także koszty), Odrzucone alternatywy.
- Zmiana decyzji = nowy rekord ze statusem
zastępuje 000N, nie edycja historii.