L'istinto davanti alle feature complesse è «provo qualcosa» — ma le decisioni architetturali si nascondono nel 3° modello, nel 5° edge case. Il vero valore del plan mode è spostare la conversazione architetturale nel testo prima del codice. Caso reale: il sistema di giuria comunitaria di Pickful — 3.032 righe, 119 spec verdi, un solo commit, zero rilavorazioni architetturali dopo.
Di fronte a una feature complessa, l'istinto della maggior parte delle persone è «provo qualcosa».
Il problema: i sistemi complessi hanno una caratteristica — le decisioni architetturali si nascondono nel 3° modello, nel 5° edge case, nell'8ª regola di punti. Tuffarsi nel codice e scontrarsi con quelle decisioni a metà strada, per poi tornare indietro a cambiarle, costa 10× in più rispetto a discuterle a parole fin dall'inizio.
Ho usato il plan mode di Claude Code per costruire TopicReview, il sistema di giuria comunitaria di Pickful, e ho visto la versione estrema di questa disuguaglianza: un solo commit, 3.032 righe, 119 spec in verde, consegnato in un'unica volta. Nessuno dei dieci e passa commit che sono seguiti è un rifacimento architetturale — sono tutti regolazioni di parametri, rifiniture UI, patch di edge case. Il sistema gira stabile da allora ed è oggi centrale nel modo in cui la comunità si auto-modera.
Questo post tratta del perché le feature complesse richiedono prima il plan mode, di cosa sta facendo davvero la fase di plan, e di quando la conversazione è abbastanza matura per cominciare a scrivere codice.
TopicReview è un voto comunitario che decide se un post di bassa qualità debba essere rimosso. Una frase per riassumerlo — ma la spec si dispiega a strati:
Il nucleo della complessità non sta in alcuna regola singola — sta in come le regole interagiscono tra loro. Ogni regola aggiunta può innescare un rollback altrove.
Quando scrivi di getto, i problemi più duri non sono i fatti visibili — sono le domande che non hai pensato di fare. Leggendo il codice di TopicReview all'inverso, ci sono almeno quattro muri che ti colpirebbero inevitabilmente se saltassi il plan:
Regole di idoneità dei giurati. Sembra solo User.jurors_and_judges.sample(12). Ma le regole effettive sono: escludere l'autore del post, escludere chi l'ha segnalato, escludere chi ha già votato al primo turno (così non vota di nuovo in appello). Tre esclusioni impilate. Scrivendo il model di un fiato, ne perdi una o due.
Pagamento differito dei punti. Un verdetto remove di norma scatena il pagamento ai giurati. Ma un appello può ribaltare un remove — e quando lo fa, i giurati che avevano votato col vecchio verdetto si ritrovano sul lato sbagliato, quindi i pagamenti vanno ricalcolati contro il nuovo verdetto. Perciò il verdetto remove deve aspettare la chiusura della finestra d'appello di 24h prima di pagare i giurati. Salta la scrittura di questa regola, paga prima, e finisci a recuperare punti — 10× più scomodo del pagare in ritardo.
Design dell'interfaccia del job schedulato. CloseTopicReviewJob sembra «chiudere una review». In pratica gestisce tre situazioni:
# Scadenza della finestra di voto iniziale
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Pagamento ai giurati differito dopo un verdetto remove
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# Scadenza della finestra d'appello
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)
Senza pianificazione preventiva, scrivi la prima signature, e al secondo caso ti accorgi che l'interfaccia deve cambiare.
Il muro più caro: si può fare appello durante la rimozione provvisoria? Quando i voti remove superano la soglia, il post viene nascosto subito (provvisorio), ma la review resta in stato voting — non decided. L'utente può già fare appello?
decided e appealedQuesta singola decisione si propaga all'indietro e cambia i controlli dei parametri in open_appeal! e la logica della macchina a stati. Decidere a metà strada = riscrivere metà del sistema.
Il plan mode di Claude Code è una modalità in cui scrivere codice è vietato — Claude può leggere il repo, pensare agli approcci, discutere con te, ma qualsiasi modifica ai file è hard-bloccata finché non approvi un plan.
Quel vincolo meccanico è il punto: costringe la conversazione a livello d'architettura ad avvenire in testo.
Alcune cose che la fase di plan fa in pratica:
1. Disegnare la macchina a stati e i ruoli. 5 stati, 4 ruoli (giurato / giudice / autore / segnalatore), cosa ogni ruolo può e non può fare in ogni stato — tutto in poche righe di markdown. Poche righe vs. decine di file. Il costo del cambiamento è di due ordini di grandezza diverso.
2. Attraversare il flusso di ogni ruolo:
Dove il cammino si inceppa, spunta una domanda nascosta: «i giurati vedono i voti degli altri giurati?», «cosa può fare l'autore durante la rimozione provvisoria?»
3. Interrogare gli edge case. La fase di plan non disegna il «percorso normale» — fa apposta le domande che di solito non affiorano:
finalize contemporaneamente — la race raddoppia il pagamento? (Aggiungere un campo juror_points_awarded per l'idempotenza.)Il 95% di queste domande non emerge naturalmente mentre scrivi codice. La fase di plan ti costringe a rispondere una per una.
4. Il libro mastro dei punti. Il sistema di punti è abbastanza complesso da non bastare discuterlo — bisogna disegnare la tabella: ogni flusso di punti con il suo trigger, l'importo e il percorso di rollback. Quando il libro torna, tutti gli edge case (rimborso provvisorio, rimborso d'appello, bonus) si riconciliano.
Un criterio duro:
closed (keep / remove / warn × con/senza appello × provvisorio/non) — la racconti da capo a fondoRaggiunto quel livello, scrivere codice diventa tradurre il plan in Ruby.
Il primo rilascio del sistema:
d162f1e Add community moderation system with jury/judge review and appeals
63 files changed, 3032 insertions(+)
119 specs, 0 failures
63 file, 3.032 righe, 119 spec in verde. Rilasciato in un'unica volta.
I dieci e passa commit successivi confermano che l'architettura ha tenuto:
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
Ognuno è tuning / fix / rifinitura / piccola feature. Nessuno è «tornare indietro e ridisegnare la macchina a stati» o «il modello di punti va cambiato». Lo scheletro era del tutto giusto.
Questo è il vero dividendo del plan: l'esecuzione resta ininterrotta. Non c'è «aspetta, come funziona questo cammino» — il plan lo ha coperto. Non c'è «non ho pensato a questo edge case» — la fase di plan l'ha chiesto. Non c'è «questa interfaccia va riprogettata» — il plan l'ha già sistemata.
Ore a scrivere codice, facendo una sola cosa: tradurre un design chiaro sulla tastiera.
Non tutti i compiti meritano un plan:
Il guadagno del plan mode viene dall'abbassare il costo di riscrittura. Se il task non ha rischio di riscrittura, il plan è solo overhead.
«Pensare prima di agire» suona come un consiglio di carattere. Il plan mode non è quello.
Il plan mode è far sì che la conversazione a livello architetturale avvenga dove 10 parole la cambiano — non dove 30 file devono cambiare.
Sotto complessità, va invertito quel vecchio detto del settore «words are cheap, code is expensive» — non significa «scrivi codice prima e poi si vede» (vale solo quando il gap di costo è piccolo), significa sfruttare il gap di costo: portare la conversazione costosa in anticipo, nel medium economico.
3.000 righe in un singolo commit è una sensazione splendida. Non perché scrivo veloce — perché il plan ha trasformato «scrivere» in un atto puramente meccanico.