README que sobe o projeto no primeiro dia, e continua certo um ano depois
A estrutura de README que leva quem nunca viu o repositório até a página funcionando, e o truque para ele não envelhecer: o mesmo comando roda no CI.
Segunda, 9h, primeiro dia da Júlia. O README do projeto agenda-clinica manda instalar o Node 14, rodar npm start e abrir a porta 8080. O Node 14 nem instala direito, o script se chama dev há dois anos e a porta mudou para 3000. Às 15h ela ainda não viu a tela de login e acha que o problema é ela. O problema é um documento que ninguém executou desde que foi escrito.
A resposta curta: um bom README tem três blocos curtos no topo (o que é, o que instalar, como subir e ver uma página), com comandos copiáveis e a URL local no fim. E para ele não mentir de novo, os mesmos comandos rodam no CI: se o README quebrar, o pipeline quebra junto.
Por que o README envelhece
Código tem compilador e teste. README não tem nada que reclame quando fica errado. Cada mudança de porta, de versão de runtime, de nome de script ou de variável de ambiente é feita por alguém que já tem o projeto rodando e nunca mais segue o passo a passo do zero. O documento só é testado de verdade quando chega uma pessoa nova, e aí já está desatualizado em três lugares.
Há um segundo problema: README que começa pela arquitetura. Diagrama, histórico das decisões, explicação das camadas. Tudo isso tem valor, mas antes de ver funcionar a pessoa não tem onde pendurar a informação. Primeiro ela precisa ver a página. Depois a arquitetura faz sentido.
A estrutura que funciona
- O que é, em uma ou duas frases. "Agenda de consultas para clínicas pequenas. API em Node, banco PostgreSQL, front em React."
- Pré-requisitos com versão. Runtime, gerenciador de pacotes, Docker se precisar. Versão exata ou mínima, e de onde ela vem (arquivo
.nvmrc, campoengines). - Como subir, em comandos copiáveis. Um comando por linha, na ordem, sem "configure o banco" vago no meio.
- Como saber que funcionou. A URL local e o que deve aparecer nela. Usuário de teste, se a tela pede login.
- Problemas comuns. Porta ocupada, Docker parado, variável faltando. Duas ou três linhas cada.
- Para onde ir depois. Link para a documentação de arquitetura, as decisões registradas e o guia de contribuição.
O README do exemplo, reescrito
Para o agenda-clinica, o topo do novo README ficou assim:
# agenda-clinica
Agenda de consultas para clínicas pequenas. API em Node.js, banco PostgreSQL.
## Pré-requisitos
- Node.js na versão do arquivo .nvmrc (hoje, 22)
- Docker com Compose, para o banco local
## Como subir
```bash
cp .env.example .env
npm ci
docker compose up -d db
npm run db:migrate
npm run db:seed
npm run dev
```
Abra http://localhost:3000 e entre com recepcao@exemplo.test / senha-local-123.
Esse usuário só existe no banco local criado pelo seed.
## Problemas comuns
- Porta 3000 ocupada: defina PORT=3001 no .env.
- "connection refused" no migrate: o container do banco ainda está subindo.
Rode docker compose ps e espere o estado healthy.
## Próximos passos
- docs/arquitetura.md
- docs/adr/ (decisões registradas)
- CONTRIBUTING.md
Repare no que não está ali: nenhuma senha real, nenhum segredo de produção. O .env.example vai para o Git com valores de desenvolvimento; o .env fica no .gitignore. Se algum segredo já escapou para o repositório, siga trocar o segredo antes de limpar o histórico.
No Windows, quem usa PowerShell troca o cp por Copy-Item .env.example .env. Vale uma linha no README em vez de deixar a pessoa descobrir sozinha.
Como impedir que ele minta de novo
A ideia central é simples: o README não pode descrever um caminho que ninguém executa. Então faça o CI executar o mesmo caminho.
- Coloque os comandos de subida num script versionado, por exemplo
scripts/subir-local.sh. - No README, mostre os comandos e diga que o script faz exatamente isso.
- Crie um job de CI que roda o script numa máquina limpa e confere se a página responde.
- Quem mudar porta, runtime ou nome de script muda o README no mesmo pull request. A revisão cobra isso, como cobra teste.
O teste de fumaça no CI pode ser bem curto:
#!/usr/bin/env bash
set -euo pipefail
cp .env.example .env
npm ci
docker compose up -d --wait db
npm run db:migrate
npm run db:seed
npm run dev > dev.log 2>&1 &
for i in $(seq 1 30); do
if curl -fsS http://localhost:3000/ > /dev/null; then
echo "app respondeu"
exit 0
fi
sleep 2
done
echo "app não respondeu em 60 s"
cat dev.log
exit 1
O --wait do docker compose up espera os serviços ficarem saudáveis, então o serviço db precisa de um healthcheck no compose.yaml (e um healthcheck honesto, como explica healthcheck que mente). Se o seu Compose for antigo e não tiver essa opção, use um laço com docker compose ps no lugar.
Com esse job, a próxima pessoa que trocar a porta para 4000 sem atualizar o README vê o pipeline vermelho antes do merge. O primeiro dia da próxima Júlia deixa de ser arqueologia.
O teste humano, uma vez por trimestre
O CI prova que os comandos funcionam numa máquina limpa de Linux. Ele não prova que o texto é claro. Uma vez por trimestre, ou a cada pessoa nova, peça para alguém seguir o README sem ajuda e anotar cada ponto em que travou. Cada trava é um parágrafo que falta. Corrija na hora, no mesmo dia, enquanto a dúvida está fresca.
Quem acabou de chegar é a única pessoa que enxerga o que está faltando. Depois de uma semana no projeto, ela também passa a "simplesmente saber" o que o documento não diz.
Erros comuns
- Versão sem fonte. "Use Node 18" no texto e 22 no
.nvmrc: a pessoa instala a errada e perde uma tarde com erro de dependência. - Passo vago no meio. "Configure o banco" sem comando faz cada pessoa configurar de um jeito, e os bugs locais deixam de ser reproduzíveis.
- Arquitetura antes do primeiro comando. A pessoa lê três telas de diagrama antes de saber se o projeto sobe, e desiste de ler.
- Credencial real no exemplo. A senha de homologação no README vira senha pública no dia em que o repositório é aberto ou clonado por terceiros.
- Sem a URL final. O comando roda, nada dá erro, e a pessoa não sabe onde olhar para confirmar que funcionou.
- Atualizar o README "depois". Depois nunca chega, e a diferença entre documento e código cresce a cada sprint.
Checklist
- O topo explica o que é o projeto em até duas frases.
- Cada pré-requisito tem versão, e ela bate com
.nvmrc,enginesou equivalente. - Todos os comandos de subida são copiáveis, na ordem, sem passo descrito só em palavras.
- O README diz a URL local e o que deve aparecer nela.
- O
.env.exampleexiste e não tem nenhum segredo real. - Um job de CI executa os mesmos comandos e confere se a página responde.
- Pull requests que mudam porta, runtime ou script também mudam o README.
Pegue uma máquina limpa (ou peça a alguém que nunca abriu o repositório) e siga só o README: em quanto tempo a home aparece, e em qual linha a pessoa precisou perguntar algo?