← Notatki

Paweł · 10 września 2026

Silnik i instancja — gdzie postawić granicę

Kolejne serwisy kończyły się tak samo: przy drugim okazywało się, że osiemdziesiąt procent kodu jest wspólne, tylko rozjechane w dwóch repozytoriach. Kolofon zaczął się od próby zrobienia tego porządnie.

Zasada jest jedna: silnik nie wie nic o marce, autorach ani treści, którą renderuje. Wszystko dostaje jako dane, przez sześć wyraźnie nazwanych szwów.

1. site.config.ts     marka, adresy, klucze jawne, identyfikatory baz
2. glob wpisow        content/posts/<seria>/*.json
3. authors.ts         atrybucja i typografia autora
4. redirects.ts       historia adresow (301)
5. pages/* + trasy    strony wlasne instancji
6. public/*           ikony, logo, obrazek OG
Sześć miejsc, w których instancja mówi silnikowi, kim jest

Wszystko poza tą listą należy do silnika i jest wciągane do instancji przez synchronizację. Instancja tych plików nie edytuje — a jeśli zrobi to mimo wszystko, zmiana zniknie przy najbliższym przebiegu.

Dlaczego nie pakiet npm

Naturalny odruch: skoro to biblioteka, opublikuj ją jako pakiet i wciągaj zależnością. Nie zrobiłem tego i zapisałem powód w dokumentacji, żeby za pół roku samemu do niego nie wracać.

Powody są dwa i oba są długiem, nie zaletą. Po pierwsze, moduł czytający wpisy skanuje je globem po ścieżce względnej — w katalogu zależności taki glob wskaże w pustkę. Po drugie, silnik w kilkunastu miejscach importuje treść instancji, więc zależność jest dwukierunkowa: obcy użytkownik nie ma czego zaimportować.

Do czasu spłacenia obu obowiązuje vendoring, czyli kopiowanie plików silnika do instancji. Brzmi prymitywnie i takie jest. Ale jest zapisane, ma mechanizm i wiadomo, kiedy się skończy — a to więcej niż można powiedzieć o większości długu technicznego.

Klucz ponad językiem

Serwis ma wersję polską i angielską. Pierwsza wersja wiązała je mapą adresów: słownik, który dla polskiego adresu podawał angielski. Rozsypało się przy pierwszej zmianie tytułu.

Rozwiązaniem był klucz. Każdy materiał dostaje identyfikator niezależny od języka, a adres pozostaje w języku treści.

{ "key": "dz-042", "slug": "noc-w-schronisku",   "lang": "pl" }
{ "key": "dz-042", "slug": "a-night-in-the-hut", "lang": "en" }
Ten sam materiał w dwóch wersjach

Przejście między wersjami idzie trasą po kluczu, nie po adresie. Zmiana tytułu po jednej stronie nie ma jak zepsuć powiązania, bo powiązanie nie zna tytułów.

Z tego wyszła druga zasada, która okazała się ważniejsza: granica biegnie po tym, czego rzecz dotyczy. Komentarze, oceny i głosy w ankietach dotyczą MATERIAŁU, więc są wspólne dla obu wersji. Odsłony, adres i napisy interfejsu dotyczą STRONY, więc są osobne. Nie da się tego rozstrzygnąć raz na zawsze — trzeba pytać przy każdej nowej funkcji.