Reconstruir sem recomeçar: extrair a fundação para um app novo, mais simples e rápido
Um roteiro honesto para quando você quer clonar as boas ideias de um projeto que cresceu demais — sem herdar a bagagem. Separar regras, design system e features; deixar a performance vir da arquitetura (não das telas bonitas); e reimplementar por fatias verticais. Escrito a partir da experiência com este próprio site (Astro + Cloudflare + Supabase, rotas estáticas e dinâmicas).
Todo projeto que dá certo passa por um momento estranho: ele cresce tanto que você olha para a base de código e pensa “eu faria isso melhor hoje”. Não porque estava errado — porque você aprendeu no caminho, e porque features foram sendo pregadas umas nas outras até virar um organismo que ninguém projetou de propósito.
Foi daí que veio a vontade de começar um app novo, parecido com este (mesmo domínio,
com partes estáticas e dinâmicas, praticamente as mesmas rotas), mas mais simples, mais
rápido e mais organizado. Este texto é o roteiro que eu daria a mim mesmo antes de abrir
o git init. Guardo aqui para refletir com calma depois.
O reframe: não é “melhorar”, é “extrair”
A primeira armadilha é pensar “vou melhorar a UI deste app e depois o resto”. Não. Um app que cresceu organicamente carrega complexidade que você não quer levar junto: sistemas com estado over-engineered, abstrações criadas para um caso que nunca veio, features que você nem vai reusar.
E apagar coisa de uma base grande é pior do que parece — sempre sobram fantasmas: um import
solto, um token órfão, um if que ninguém entende mais. Copiar deliberadamente para um
repo novo e limpo é mais honesto do que “forkar e deletar”. Você começa com uma folha em
branco e traz, uma a uma, só as peças que provaram valor.
Três camadas, três durabilidades
O erro clássico é tratar o código como uma coisa só. Ele tem, na verdade, três camadas com “vida útil” bem diferente:
| Camada | Reutilização | Quando mexer |
|---|---|---|
| Regras / convenções (a constituição) | ~100% portável | Primeiro. É barato agora e caríssimo depois. |
| Design system + primitivos (tokens, Button, Input, Card, layout) | Muito portável | Logo em seguida, como base limpa. |
| Features de produto (loja, checkout, IA, orçamentos…) | Reimplementar | Por último, uma fatia vertical de cada vez. |
A intuição de “começar pela UI” está certa — desde que “UI” signifique a fundação de design + os primitivos + as regras, e não “deixar as telas bonitas”. Telas bonitas em cima de uma arquitetura errada, você refaz. A fundação (tokens, contrato de componente, tema claro/escuro, a regra de “nenhuma cor cravada”) é o que realmente se paga com o tempo.
A armadilha da performance
Aqui vai o aviso mais importante: performance não vem de UI mais bonita — vem de arquitetura. Dá para passar semanas polindo componentes e o site continuar pesado, porque o problema real é quanto JavaScript você embarca e o que renderiza no servidor.
Antes de investir na UI, decida a estratégia de renderização. Para uma stack como esta (Astro + Cloudflare + Supabase), com rotas mistas, as alavancas de “simples e rápido” são:
- Menos JS no cliente. Ilhas do Astro: hidrate só o que precisa de interação. A regra nova é HTML/CSS por padrão, JavaScript só numa ilha justificada. Muita coisa que hoje é componente interativo poderia ser HTML estático.
- SSR só onde faz sentido. Renderizar tudo no servidor é confortável, mas caro e lento. Catálogo e páginas de conteúdo podem ser estáticos/ISR; deixe o SSR para o que é genuinamente por-usuário (carrinho, conta, checkout). O mapa de rotas praticamente já te diz o que é estático e o que é dinâmico — use isso como planta.
- Menos camadas de abstração. Comece mínimo e só abstraia quando doer duas vezes (YAGNI). Uma abstração agnóstica de provedores, por exemplo, só se justifica quando existe um segundo provedor de verdade — antes disso é peso morto.
- Token system enxuto. Mantenha as CSS Custom Properties como fonte única da verdade, mas audite e corte o que não é usado. Um núcleo pequeno e bem definido (cor, espaço, tipografia, raio, sombra) vale mais que 16 paletas que ninguém lembra por quê.
- Camada de dados fina. Um cliente, contratos tipados, sem N invólucros em volta.
Um caminho em fases
- Fase 0 — Regras (um doc curto). Um
CONVENTIONS.mdenxuto: estrutura de pastas, naming, contrato de componente (props tipadas, BEM, tokens), quando adicionar JS, acessibilidade, tema, e a disciplina de umSPEC.mdpor pasta. Essa disciplina é ouro — mas com uma regra de higiene que este projeto aprendeu na marra: SPEC desatualizado mente. Ou o SPEC acompanha o código, ou ele vira armadilha. - Fase 1 — Fundação de design. Tokens + reset + primitivos limpos (Button, Input, Card,
Stack/Grid) + tema claro/escuro. Uma página
/_uique mostra tudo de uma vez (um mini-Storybook caseiro) para ver o sistema respirar. - Fase 2 — Shell de layout. Navegação e estruturas de página — mais simples que o necessário hoje. Resista à tentação de recriar a máquina de estados complexa; comece pelo suficiente.
- Fase 3 — Features por fatia vertical. Uma jornada completa de cada vez (ex.: loja → catálogo → produto → carrinho → checkout), trazendo do projeto antigo só o que aquela fatia precisa.
O que herdar e o que largar
Herdar (as boas raízes): a disciplina de SPEC.md por pasta · a estrutura
ui/categoria/Componente/Componente.astro · os tokens --c-* e a regra “sem hex cravado” ·
o hábito de um CLAUDE.md/doc de regras do projeto · o padrão de abstração agnóstica —
quando houver mais de uma implementação real.
Largar ou simplificar: SSR em tudo · sistemas com estado over-engineered · abstrações multi-provedor antes de existir o segundo provedor · o acúmulo de features que o app novo não vai usar · SPECs que descrevem um passado que o código já abandonou.
O fio da meada
Se eu tivesse que resumir numa frase: defina as regras enquanto elas são baratas, construa a fundação antes das telas, deixe a performance nascer da arquitetura, e traga as features por último — uma fatia de cada vez, olhando nos olhos cada linha que você copia.
O objetivo não é um app perfeito. É um app do qual, daqui a um ano, eu não sinta vontade de
fugir. E isso se decide agora, na folha em branco — não depois, no meio de 200 lugares com
#1c1c18 cravado no CSS.