O instinto diante de features complexas é "deixa eu testar algo" — mas as decisões arquiteturais se escondem no terceiro modelo, no quinto edge case. O verdadeiro valor do plan mode é mover a conversa em nível de arquitetura para o texto antes do código. Caso real: o sistema de júri comunitário do Pickful — 3.032 linhas, 119 specs no verde, um único commit, zero retrabalho arquitetural depois.
Diante de uma feature complexa, o instinto da maioria é "deixa eu testar alguma coisa".
O problema: sistemas complexos têm uma característica — as decisões arquiteturais se escondem no 3º modelo, no 5º edge case, na 8ª regra de pontos. Mergulhar de cabeça no código e esbarrar nessas decisões no meio do caminho, voltando para mudá-las, custa 10× mais do que ter discutido tudo em texto desde o início.
Usei o plan mode do Claude Code para construir o TopicReview, o sistema de júri comunitário do Pickful, e vi a versão extrema dessa desigualdade: um único commit, 3.032 linhas, 119 specs no verde, entregue de uma vez só. Nenhum dos dez e tantos commits que vieram depois foi um retrabalho arquitetural — todos são ajustes de parâmetros, polimento de UI, correção de edge cases. O sistema está rodando estável desde então e hoje é central para como a comunidade se automodera.
Este post é sobre por que features complexas exigem plan mode primeiro, o que a fase de plan realmente está fazendo, e quando a conversa está madura o suficiente para começar a escrever código.
TopicReview é uma votação comunitária para decidir se um post de baixa qualidade é removido. Dá para resumir em uma frase — mas a especificação se desdobra em camadas:
A complexidade não está em nenhuma regra isolada — está em como as regras interagem. Cada regra nova pode disparar um rollback em outra.
Quando você escreve direto, os problemas mais difíceis não são os fatos visíveis — são as perguntas que você nunca pensou em fazer. Lendo o código do TopicReview de trás para frente, há pelo menos quatro paredes que inevitavelmente baterão em você se pular o plan:
Regras de elegibilidade de jurados. Parece ser apenas User.jurors_and_judges.sample(12). Mas as regras reais são: excluir o autor do post, excluir quem denunciou o post, excluir quem já votou na rodada inicial (para não votar também na apelação). Três exclusões empilhadas. Escrevendo o model de uma vez só, você vai esquecer uma ou duas.
Pagamento diferido de pontos. Um veredicto remove normalmente dispara o pagamento aos jurados. Mas uma apelação pode reverter um remove — e quando reverte, os jurados que votaram com o veredicto antigo ficam do lado errado, então os pagamentos precisam ser recalculados contra o novo veredicto. Por isso o veredicto remove deve esperar a janela de apelação de 24h fechar antes de pagar os jurados. Pule essa regra, pague primeiro, e você acaba tentando reaver pontos — 10× mais complicado do que pagar tarde.
Design da interface do job agendado. CloseTopicReviewJob parece "finalizar uma review". Na prática ele lida com três situações:
# Expiração da janela de votação inicial
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Pagamento diferido aos jurados após um veredicto remove
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# Expiração da janela de apelação
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)
Sem planejamento antes, você escreve a primeira assinatura e no segundo caso descobre que a interface precisa mudar.
A parede mais cara: dá para apelar durante a remoção provisória? Quando os votos remove cruzam o limiar, o post é escondido (provisório), mas a review continua no estado voting — não decided. O usuário já pode apelar?
decided e appealedEssa única decisão volta e muda os checks de parâmetros dentro de open_appeal! e a lógica da máquina de estados. Decidir no meio do caminho = reescrever metade do sistema.
O plan mode do Claude Code é um modo onde escrever código é proibido — Claude pode ler o repo, pensar em abordagens, discutir com você, mas qualquer modificação de arquivo é bloqueada via hard-block até você aprovar um plano.
Essa restrição mecânica é o ponto: ela força a conversa em nível de arquitetura a acontecer em texto.
Algumas coisas que a fase de plan está fazendo na prática:
1. Desenhar a máquina de estados e os papéis. 5 estados, 4 papéis (jurado / juiz / autor / denunciante), o que cada papel pode e não pode fazer em cada estado — tudo em algumas linhas de markdown. Algumas linhas vs. dezenas de arquivos. O custo de mudança está a duas ordens de grandeza de distância.
2. Percorrer o fluxo de cada papel:
Onde o percurso trava, uma pergunta oculta salta: "os jurados veem os votos uns dos outros?", "o que o autor pode fazer durante a remoção provisória?"
3. Interrogar edge cases. A fase de plan não desenha o "caminho normal" — ela faz de propósito as perguntas que normalmente não aparecem:
finalize ao mesmo tempo — a race dobra o pagamento? (Adicionar um campo juror_points_awarded para idempotência.)95% dessas perguntas nunca aparecem naturalmente enquanto você escreve código. A fase de plan força você a responder uma a uma.
4. O livro-razão de pontos. O sistema de pontos é complexo o suficiente para que discutir não baste — é preciso desenhar a tabela de verdade: cada fluxo de pontos com seu disparador, valor e caminho de rollback. Quando o livro fecha, todos os edge cases (reembolso provisório, reembolso de apelação, bônus) se reconciliam.
Um critério duro:
closed (keep / remove / warn × com / sem apelação × provisório / não) — você consegue contar de ponta a pontaQuando atinge esse patamar, escrever código é traduzir o plano para Ruby.
A primeira entrega desse sistema:
d162f1e Add community moderation system with jury/judge review and appeals
63 files changed, 3032 insertions(+)
119 specs, 0 failures
63 arquivos, 3.032 linhas, 119 specs no verde. Entregue de uma vez só.
Os dez e tantos commits seguintes confirmam que a arquitetura segurou:
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
Cada um é ajuste / fix / polish / pequena feature. Nenhum é "voltar e redesenhar a máquina de estados" ou "o modelo de pontos precisa mudar". O esqueleto estava certo.
Essa é a verdadeira recompensa do plan: a execução não é interrompida. Não tem "espera, como esse caminho funciona" — o plano já cobriu. Não tem "não pensei nesse edge case" — a fase de plan perguntou. Não tem "essa interface precisa ser redesenhada" — o plano já resolveu.
Horas escrevendo código, fazendo uma única coisa: traduzir um design claro para o teclado.
Nem toda tarefa merece plan:
O benefício do plan mode vem de baixar o custo de reescrita. Se a tarefa não tem risco de reescrita, plan é só overhead.
"Pense antes de agir" soa como conselho de personalidade. Plan mode não é isso.
Plan mode é fazer a conversa em nível arquitetural acontecer onde 10 palavras podem mudá-la — não onde 30 arquivos precisam mudar.
Sob complexidade, aquele velho ditado da indústria "words are cheap, code is expensive" precisa ser invertido — não significa "escreve código primeiro e vê" (isso só vale quando a diferença de custo é pequena), significa usar essa diferença: colocar a conversa cara na frente, no meio barato.
3.000 linhas em um único commit é uma sensação incrível. Não porque eu escrevo rápido — porque o plano transformou "escrever" em um ato puramente mecânico.