Instynkt przy złożonych funkcjach to "spróbuję coś" — ale decyzje architektoniczne chowają się w trzecim modelu, piątym edge case. Prawdziwa wartość plan mode to przeniesienie rozmowy architektonicznej do tekstu przed kodem. Realny przypadek: system ławy przysięgłych Pickful — 3032 linie, 119 speców na zielono, jeden commit, zero architektonicznych przeróbek potem.
W obliczu złożonej funkcji instynkt większości ludzi to „spróbujmy coś napisać".
Problem: złożone systemy mają pewną cechę — decyzje architektoniczne ukrywają się w 3. modelu, w 5. edge case, w 8. regule punktów. Zanurkowanie w kod i uderzenie o te decyzje w połowie drogi, a potem cofanie się, by je zmienić, kosztuje 10× więcej niż przegadanie ich w tekście od samego początku.
Użyłem plan mode Claude Code, żeby zbudować TopicReview — system ławy przysięgłych społeczności w Pickful — i zobaczyłem skrajną wersję tej nierówności: jeden commit, 3032 linie, 119 speców na zielono, dostarczone za jednym razem. Żaden z kilkunastu kolejnych commitów nie był przeróbką architektoniczną — wszystkie to tuning parametrów, polish UI, łatki edge case'ów. System działa stabilnie od tamtej pory i jest dziś centralnym elementem tego, jak społeczność moderuje samą siebie.
Ten wpis dotyczy tego, dlaczego złożone funkcje wymagają najpierw plan mode, co tak naprawdę robi faza plan i kiedy rozmowa jest na tyle dojrzała, by zacząć pisać kod.
TopicReview to głosowanie społeczności decydujące, czy post niskiej jakości zostanie usunięty. Jedno zdanie do opisania — ale specyfikacja rozwija się warstwami:
Istota złożoności nie tkwi w żadnej pojedynczej regule — tkwi w tym, jak reguły oddziałują między sobą. Każda dodana reguła może wyzwolić rollback gdzieś indziej.
Kiedy piszesz ciągiem, najtrudniejsze problemy to nie widoczne fakty — tylko pytania, których nie pomyślałeś zadać. Czytając kod TopicReview od tyłu, jest co najmniej cztery ściany, w które nieuchronnie walniesz, pomijając plan:
Reguły kwalifikowalności przysięgłych. Wygląda tylko na User.jurors_and_judges.sample(12). Ale rzeczywiste reguły to: wykluczyć autora posta, wykluczyć osobę, która go zgłosiła, wykluczyć każdego, kto już głosował w pierwszej rundzie (żeby ten sam człowiek nie głosował też w apelacji). Trzy warstwy wykluczeń. Pisząc model jednym ciągiem, pominiesz jedną lub dwie.
Odroczona wypłata punktów. Werdykt remove normalnie wyzwala wypłatę przysięgłym. Ale apelacja może odwrócić remove — a gdy to zrobi, przysięgli głosujący wedle starego werdyktu lądują po złej stronie, więc wypłaty trzeba przeliczyć wedle nowego werdyktu. Dlatego werdykt remove musi poczekać na zamknięcie 24-godzinnego okna apelacji, zanim wypłaci przysięgłym. Pominiesz tę regułę, zapłacisz wcześniej — będziesz potem odbierał punkty, 10× bardziej uciążliwe niż wypłacenie z opóźnieniem.
Projekt interfejsu zaplanowanego joba. CloseTopicReviewJob z wyglądu „zamyka review". W praktyce obsługuje trzy sytuacje:
# Wygaśnięcie okna głosowania wstępnego
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Odroczona wypłata przysięgłym po werdykcie remove
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# Wygaśnięcie okna apelacji
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)
Bez wcześniejszego planowania napiszesz pierwszą sygnaturę, a w drugim przypadku zorientujesz się, że interfejs musi się zmienić.
Najdroższa ściana: czy można apelować podczas tymczasowego usunięcia? Gdy głosy remove przekraczają próg, post jest natychmiast ukrywany (tymczasowo), ale cały review pozostaje w stanie voting — nie decided. Czy użytkownik może już apelować?
decided i appealedTa jedna decyzja rozchodzi się wstecz i zmienia sprawdzenia parametrów w open_appeal! oraz logikę maszyny stanów. Podejmowanie jej w połowie = przepisywanie połowy systemu.
Plan mode Claude Code to tryb, w którym pisanie kodu jest zabronione — Claude może czytać repo, przemyśleć podejścia, dyskutować z tobą, ale każda modyfikacja pliku jest hard-blokowana, dopóki nie zatwierdzisz planu.
To mechaniczne ograniczenie jest sednem: wymusza, by rozmowa na poziomie architektury odbywała się w tekście.
Kilka rzeczy, które faza plan robi w praktyce:
1. Rysowanie maszyny stanów i ról. 5 stanów, 4 role (przysięgły / sędzia / autor posta / zgłaszający), co każda rola może i czego nie może w każdym stanie — wszystko w kilku linijkach markdown. Kilka linii vs. dziesiątki plików. Koszt zmiany różni się o dwa rzędy wielkości.
2. Przejście przez przepływ każdej roli:
Gdzie marsz się zacina, wyskakuje ukryte pytanie: „czy przysięgli widzą głosy innych przysięgłych?", „co autor może zrobić podczas tymczasowego usunięcia?"
3. Przesłuchiwanie edge case'ów. Faza plan nie projektuje „ścieżki normalnej" — celowo zadaje pytania, które zwykle się nie pojawiają:
finalize — czy race zdubluje wypłatę? (Dodać pole juror_points_awarded dla idempotencji.)95% tych pytań nie wyłania się naturalnie przy pisaniu kodu. Faza plan zmusza cię do przejścia przez nie po kolei.
4. Księga punktów. System punktów jest wystarczająco złożony, by dyskusja nie wystarczyła — trzeba faktycznie narysować tabelę: każdy przepływ punktów z wyzwalaczem, kwotą i ścieżką rollback. Gdy księga się bilansuje, wszystkie edge case'y (zwrot tymczasowy, zwrot apelacji, bonusy) rozliczają się.
Twardy próg:
closed (keep / remove / warn × z apelacją / bez × tymczasowa / nietymczasowa) — opowiadasz od początku do końcaGdy osiągniesz ten poziom, pisanie kodu staje się tłumaczeniem planu na Ruby.
Pierwsze wdrożenie tego systemu:
d162f1e Add community moderation system with jury/judge review and appeals
63 files changed, 3032 insertions(+)
119 specs, 0 failures
63 pliki, 3032 linie, 119 speców na zielono. Dostarczone za jednym razem.
Kilkanaście kolejnych commitów potwierdza, że architektura się utrzymała:
Apply legacy penalty (1pt) for posts created before 2026-03-26
Fix topic review appeal bugs: window mismatch and verdict not updated
Add topic_removed status for posts removed by community review
Default to keep verdict when review expires with zero votes
Reduce provisional removal penalty to 1pt during trial period
Allow topic creator to withdraw active reviews
Add handled tab to jury dashboard, fix tabs styling
Każdy to tuning / fix / polish / mała funkcja. Żaden nie jest „wróćmy i przeprojektujmy maszynę stanów" albo „model punktów trzeba zmienić". Szkielet był w całości trafiony.
To prawdziwa premia planu: realizacja pozostaje nieprzerwana. Nie ma „poczekaj, jak działa ta ścieżka" — plan to pokrył. Nie ma „nie pomyślałem o tym edge case" — faza plan zapytała. Nie ma „ten interfejs trzeba zaprojektować od nowa" — plan to już poukładał.
Godziny pisania kodu, robiąc tylko jedno: przekład jasnego projektu na klawiaturę.
Nie każde zadanie zasługuje na plan:
Zysk z plan mode płynie z obniżenia kosztu przepisywania. Jeśli w zadaniu nie ma ryzyka przepisywania, plan to tylko narzut.
„Najpierw pomyśl, potem rób" brzmi jak rada dotycząca charakteru. Plan mode nie o tym.
Plan mode polega na tym, by rozmowa na poziomie architektury działa się tam, gdzie 10 słów może ją zmienić — a nie tam, gdzie trzeba zmieniać 30 plików.
W warunkach złożoności trzeba odwrócić stare branżowe „words are cheap, code is expensive" — nie oznacza to „pisz kod najpierw, zobaczymy" (to działa tylko, gdy różnica kosztów jest mała), oznacza wykorzystanie tej różnicy: przenieść drogą rozmowę do przodu, do taniego medium.
3000 linii w jednym commicie to świetne uczucie. Nie dlatego, że szybko piszę — dlatego, że plan zamienił „pisanie" w czysto mechaniczny akt.