Zanim przejdziesz do improve-codebase-architecture, potrzebujesz jego słownika — sam skill wymaga, żeby używać tych terminów dokładnie, bez zamiany na "komponent" czy "serwis". Cel: moduły głębokie — dużo zachowania za małym interfejsem, przy czystym seamie, testowalne przez ten interfejs.
Polecane źródło
Lokalny plik .agents/skills/codebase-design/SKILL.md. Pełny glosariusz z tej lekcji: Glosariusz: codebase-design — wróć do niego, gdy zapomnisz definicji.
Głęboki kontra płytki moduł
Głęboki = mały interfejs + dużo implementacji:
┌─────────────────────┐
│ Small Interface │
├─────────────────────┤
│ Deep Implementation │
└─────────────────────┘
Płytki = duży interfejs + mało implementacji (unikaj):
┌─────────────────────────────────┐
│ Large Interface │
├─────────────────────────────────┤
│ Thin Implementation │
└─────────────────────────────────┘
Moduł jest głęboki, gdy duża ilość zachowania siedzi za małym interfejsem. Jest płytki, gdy interfejs jest niemal tak skomplikowany jak sama implementacja — czyli w praktyce niewiele Ci oszczędza.
Seam: to samo słowo, które już znasz z Lekcji 17
Seam to lokalizacja, w której żyje interfejs modułu — miejsce, gdzie można zmienić zachowanie bez edytowania właśnie tam. tdd kazał Ci uzgadniać seamy przed napisaniem testu; codebase-design odpowiada na pytanie, skąd ten seam się bierze i jak zdecydować, gdzie go postawić.
Kluczowy wniosek: "jeden adapter to hipotetyczny seam, dwa adaptery to prawdziwy". Nie wprowadzaj seamu (interfejsu z możliwością podmiany implementacji) tylko dlatego, że "może się kiedyś przyda" — dopóki nie masz dwóch realnych rzeczy, które faktycznie się różnią przy tym samym interfejsie, seam jest spekulacją, nie potrzebą.
Test usunięcia (deletion test)
Szybki test na to, czy moduł zarabia na swoje utrzymanie: wyobraź sobie, że go usuwasz. Jeśli złożoność znika — to był zwykły przepust (shallow, do usunięcia). Jeśli złożoność pojawia się z powrotem u wszystkich, którzy go wywoływali — moduł faktycznie coś skupiał w jednym miejscu (deep, wart zachowania).
Zadanie praktyczne — zastosuj test usunięcia do jednego modułu
W swoim prawdziwym projekcie, bez uruchamiania żadnego skilla — czysto myślowo:
Wybierz jeden moduł/klasę/funkcję, co do której masz wątpliwości, czy jest potrzebna w obecnym kształcie.
Zastosuj test usunięcia: czy złożoność by zniknęła, czy pojawiłaby się z powrotem u wywołujących?
Sprawdź "jeden adapter kontra dwa": czy ten moduł ma realnie więcej niż jedną implementację/adapter przy tym samym interfejsie? Jeśli nie — czy seam faktycznie jest potrzebny już teraz?
Sprawdź się
1. Moduł ma interfejs niemal tak skomplikowany jak jego implementacja. Jak się to nazywa w tym słowniku?
To definicja płytkiego modułu: interfejs niemal tak złożony jak implementacja, więc moduł niewiele oszczędza wywołującym.
2. Zastosowałeś test usunięcia do modułu i złożoność, którą realizował, pojawiła się z powrotem u wszystkich wywołujących. Co to oznacza?
Test usunięcia: jeśli złożoność wraca u wywołujących po usunięciu modułu, znaczy że moduł faktycznie ją skupiał w jednym miejscu, zamiast być zwykłym przepustem.
3. Masz dokładnie jedną implementację interfejsu (jeden adapter). Czy warto już teraz utrzymywać osobny seam pod przyszłe alternatywy?
Zasada mówi wprost: jeden adapter to hipotetyczny seam, dopiero dwa adaptery czynią go prawdziwym. Nie wprowadzaj seamu, dopóki coś naprawdę się przy nim nie różni.
4. Dlaczego skill każe mówić "interface" i "seam" zamiast "API" i "boundary"?
"API"/"signature" są zbyt wąskie (tylko poziom typów), a "boundary" jest przeciążone znaczeniem z bounded context w DDD. Spójność języka jest tu celem samym w sobie.
5. Czym różni się seam wewnętrzny od seamu zewnętrznego, według zasady "głębokość jest cechą interfejsu"?
Głęboki moduł może mieć wewnętrzne seamy używane tylko przez własne testy, niezależnie od zewnętrznego seamu przy jego publicznym interfejsie — mockowanie wewnątrz nie psuje głębokości na zewnątrz.
Coś niejasne? Zapytaj mnie wprost — mogę pomóc rozstrzygnąć, czy konkretny moduł z Twojego projektu jest głęboki czy płytki.