nexus-core-v3 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +134 -0
- package/agents/README.md +133 -0
- package/agents/_protocol.md +107 -0
- package/agents/analyst.md +138 -0
- package/agents/architect.md +146 -0
- package/agents/data-engineer.md +170 -0
- package/agents/dev.md +134 -0
- package/agents/devops.md +141 -0
- package/agents/nexus-master.md +147 -0
- package/agents/pm.md +133 -0
- package/agents/po.md +138 -0
- package/agents/qa.md +192 -0
- package/agents/sm.md +122 -0
- package/agents/squad-creator.md +121 -0
- package/agents/ux-design-expert.md +165 -0
- package/artifact-manifest.json +903 -0
- package/bin/nexus.mjs +37 -0
- package/checklists/README.md +49 -0
- package/checklists/architect-checklist.md +47 -0
- package/checklists/change-checklist.md +61 -0
- package/checklists/db-predeploy-checklist.md +57 -0
- package/checklists/design-quality-checklist.md +57 -0
- package/checklists/discovery-checklist.md +36 -0
- package/checklists/foundation-checklist.md +39 -0
- package/checklists/launch-checklist.md +39 -0
- package/checklists/pm-checklist.md +48 -0
- package/checklists/po-master-checklist.md +64 -0
- package/checklists/reality-check-checklist.md +49 -0
- package/checklists/story-dod-checklist.md +52 -0
- package/checklists/story-draft-checklist.md +36 -0
- package/dist/bin/dashboard.html +279 -0
- package/dist/bin/nexus.mjs +20008 -0
- package/dist/constitution.yaml +76 -0
- package/knowledge/README.md +57 -0
- package/knowledge/architecture/architectural-styles-map.md +182 -0
- package/knowledge/architecture/design-patterns-gof.md +192 -0
- package/knowledge/architecture/distributed-patterns-cheatsheet.md +201 -0
- package/knowledge/architecture/saas-subscription-blueprint.md +355 -0
- package/knowledge/architecture/system-design-tradeoffs.md +231 -0
- package/knowledge/architecture/t3-fullstack-typesafe-stack.md +273 -0
- package/knowledge/copy/landing-copy-that-converts.md +168 -0
- package/knowledge/data/postgres-indexing-and-tuning.md +263 -0
- package/knowledge/data/schema-modeling-decisions.md +273 -0
- package/knowledge/data/supabase-rls-patterns.md +316 -0
- package/knowledge/data/zero-downtime-migrations.md +308 -0
- package/knowledge/devops/cicd-pipeline-best-practices.md +318 -0
- package/knowledge/devops/production-dockerfile.md +283 -0
- package/knowledge/devops/twelve-factor-app.md +398 -0
- package/knowledge/engineering/clean-code-principles.md +429 -0
- package/knowledge/engineering/effective-code-review.md +204 -0
- package/knowledge/engineering/testing-strategy-beyond-unit.md +307 -0
- package/knowledge/governance/risk-matrix.md +56 -0
- package/knowledge/integration/mcp-server-selection-matrix.md +235 -0
- package/knowledge/marketing/copy-que-converte.md +43 -0
- package/knowledge/marketing/funil-e-jornada.md +36 -0
- package/knowledge/negocios/proposta-vencedora.md +38 -0
- package/knowledge/negocios/roi-e-unit-economics.md +46 -0
- package/knowledge/pipeline/1-descobrir.md +26 -0
- package/knowledge/pipeline/2-estrategizar.md +26 -0
- package/knowledge/pipeline/3-estruturar.md +27 -0
- package/knowledge/pipeline/4-construir.md +27 -0
- package/knowledge/pipeline/5-endurecer.md +28 -0
- package/knowledge/pipeline/6-lancar.md +27 -0
- package/knowledge/pipeline/7-operar.md +27 -0
- package/knowledge/security/lgpd-conformidade-basica.md +35 -0
- package/knowledge/security/owasp-secure-coding-gates.md +220 -0
- package/knowledge/security/owasp-top10-threat-assessment.md +287 -0
- package/knowledge/security/threat-modeling-stride.md +34 -0
- package/knowledge/web-craft/a11y-audit-checklist.md +251 -0
- package/knowledge/web-craft/accessible-component-patterns.md +383 -0
- package/knowledge/web-craft/anti-ai-look.md +114 -0
- package/knowledge/web-craft/design-system-from-code.md +195 -0
- package/knowledge/web-craft/intrinsic-css-layout.md +420 -0
- package/knowledge/web-craft/style-cloning.md +185 -0
- package/knowledge/web-craft/visual-polish-review.md +183 -0
- package/package.json +55 -0
- package/runbooks/campanha-de-conteudo.md +36 -0
- package/runbooks/feature-em-projeto-existente.md +37 -0
- package/runbooks/mvp-startup.md +38 -0
- package/runbooks/resposta-a-incidente.md +37 -0
- package/squads/exemplo-conteudo/agents/editor-chefe.md +48 -0
- package/squads/exemplo-conteudo/agents/pesquisador.md +44 -0
- package/squads/exemplo-conteudo/agents/redator.md +45 -0
- package/squads/exemplo-conteudo/knowledge/estilo-editorial.md +21 -0
- package/squads/exemplo-conteudo/squad.yaml +19 -0
- package/squads/exemplo-conteudo/tasks/pesquisar-fontes.md +26 -0
- package/squads/exemplo-conteudo/tasks/planejar-pauta.md +27 -0
- package/squads/exemplo-conteudo/tasks/redigir-artigo.md +26 -0
- package/squads/exemplo-conteudo/tasks/revisar-artigo.md +27 -0
- package/squads/marketing/agents/analista.md +56 -0
- package/squads/marketing/agents/chefe-marketing.md +65 -0
- package/squads/marketing/agents/conteudo.md +55 -0
- package/squads/marketing/agents/copy.md +55 -0
- package/squads/marketing/agents/growth.md +56 -0
- package/squads/marketing/agents/social.md +55 -0
- package/squads/marketing/squad.yaml +17 -0
- package/squads/marketing/tasks/aprovar-campanha.md +43 -0
- package/squads/negocios/agents/chefe-negocios.md +65 -0
- package/squads/negocios/agents/financas-roi.md +55 -0
- package/squads/negocios/agents/suporte.md +55 -0
- package/squads/negocios/agents/vendas-proposta.md +56 -0
- package/squads/negocios/squad.yaml +17 -0
- package/squads/negocios/tasks/aprovar-proposta.md +40 -0
- package/squads/security/agents/appsec-reviewer.md +59 -0
- package/squads/security/agents/chefe-seguranca.md +65 -0
- package/squads/security/agents/compliance-auditor.md +60 -0
- package/squads/security/agents/threat-modeler.md +60 -0
- package/squads/security/squad.yaml +20 -0
- package/squads/security/tasks/aprovar-gate-seguranca.md +42 -0
- package/squads/security/tasks/emitir-parecer-conformidade.md +42 -0
- package/tasks/README.md +72 -0
- package/tasks/accessibility-wcag-checklist.md +69 -0
- package/tasks/advanced-elicitation.md +42 -0
- package/tasks/analyze-performance.md +54 -0
- package/tasks/analyze-project-structure.md +59 -0
- package/tasks/apply-qa-fixes.md +57 -0
- package/tasks/architect-analyze-impact.md +62 -0
- package/tasks/archive-squad.md +52 -0
- package/tasks/audit-codebase.md +53 -0
- package/tasks/build-component.md +61 -0
- package/tasks/calculate-roi.md +63 -0
- package/tasks/ci-cd-configuration.md +51 -0
- package/tasks/collect-visual-evidence.md +62 -0
- package/tasks/compose-molecule.md +57 -0
- package/tasks/consolidate-patterns.md +54 -0
- package/tasks/create-brownfield-prd.md +54 -0
- package/tasks/create-competitor-analysis.md +42 -0
- package/tasks/create-deep-research-prompt.md +62 -0
- package/tasks/create-doc.md +62 -0
- package/tasks/create-epic.md +49 -0
- package/tasks/create-front-end-spec.md +56 -0
- package/tasks/create-migration-plan.md +57 -0
- package/tasks/create-next-story.md +66 -0
- package/tasks/create-prd.md +53 -0
- package/tasks/create-project-brief.md +47 -0
- package/tasks/create-rls-policies.md +59 -0
- package/tasks/create-schema.md +57 -0
- package/tasks/create-service.md +55 -0
- package/tasks/create-squad.md +100 -0
- package/tasks/create-suite.md +62 -0
- package/tasks/db-apply-migration.md +56 -0
- package/tasks/db-domain-modeling.md +57 -0
- package/tasks/db-dry-run.md +50 -0
- package/tasks/db-env-check.md +57 -0
- package/tasks/db-load-csv.md +54 -0
- package/tasks/db-policy-apply.md +58 -0
- package/tasks/db-rollback.md +51 -0
- package/tasks/db-run-sql.md +61 -0
- package/tasks/db-seed.md +52 -0
- package/tasks/db-smoke-test.md +51 -0
- package/tasks/db-snapshot.md +48 -0
- package/tasks/db-verify-order.md +49 -0
- package/tasks/deliberate.md +46 -0
- package/tasks/design-indexes.md +59 -0
- package/tasks/dev-develop-story.md +61 -0
- package/tasks/document-project.md +59 -0
- package/tasks/execute-checklist.md +57 -0
- package/tasks/execute-epic-plan.md +52 -0
- package/tasks/execute-subtask.md +51 -0
- package/tasks/extend-pattern.md +63 -0
- package/tasks/extend-squad.md +60 -0
- package/tasks/extract-patterns.md +64 -0
- package/tasks/extract-tokens.md +59 -0
- package/tasks/facilitate-brainstorming-session.md +42 -0
- package/tasks/generate-ai-frontend-prompt.md +57 -0
- package/tasks/generate-documentation.md +60 -0
- package/tasks/generate-migration-strategy.md +57 -0
- package/tasks/generate-shock-report.md +56 -0
- package/tasks/mcp-management.md +66 -0
- package/tasks/orchestrate.md +50 -0
- package/tasks/perform-market-research.md +42 -0
- package/tasks/plan-create-context.md +57 -0
- package/tasks/plan-create-implementation.md +58 -0
- package/tasks/po-close-story.md +60 -0
- package/tasks/po-manage-story-backlog.md +59 -0
- package/tasks/po-pull-story.md +60 -0
- package/tasks/po-sync-story.md +59 -0
- package/tasks/pr-automation.md +50 -0
- package/tasks/pre-push-quality-gate.md +54 -0
- package/tasks/push.md +53 -0
- package/tasks/qa-browser-console-check.md +52 -0
- package/tasks/qa-create-fix-request.md +58 -0
- package/tasks/qa-evidence-requirements.md +55 -0
- package/tasks/qa-false-positive-detection.md +55 -0
- package/tasks/qa-fix-issues.md +55 -0
- package/tasks/qa-gate.md +53 -0
- package/tasks/qa-migration-validation.md +58 -0
- package/tasks/qa-nfr-assess.md +45 -0
- package/tasks/qa-review-story.md +56 -0
- package/tasks/qa-risk-profile.md +45 -0
- package/tasks/qa-security-checklist.md +64 -0
- package/tasks/qa-test-design.md +47 -0
- package/tasks/qa-trace-requirements.md +48 -0
- package/tasks/release-management.md +53 -0
- package/tasks/repository-cleanup.md +61 -0
- package/tasks/route.md +44 -0
- package/tasks/run-tests.md +50 -0
- package/tasks/security-audit.md +54 -0
- package/tasks/setup-database.md +60 -0
- package/tasks/setup-design-system.md +60 -0
- package/tasks/shard-doc.md +60 -0
- package/tasks/spec-assess-complexity.md +55 -0
- package/tasks/spec-critique.md +64 -0
- package/tasks/spec-gather-requirements.md +48 -0
- package/tasks/spec-research-dependencies.md +42 -0
- package/tasks/spec-write-spec.md +50 -0
- package/tasks/test-as-user.md +52 -0
- package/tasks/ux-create-wireframe.md +54 -0
- package/tasks/ux-user-research.md +55 -0
- package/tasks/validate-next-story.md +61 -0
- package/tasks/validate-squad.md +55 -0
- package/tasks/verify-subtask.md +52 -0
- package/tasks/version-management.md +45 -0
- package/templates/README.md +47 -0
- package/templates/architecture-tmpl.md +115 -0
- package/templates/competitor-analysis-tmpl.md +87 -0
- package/templates/epic-tmpl.md +83 -0
- package/templates/front-end-spec-tmpl.md +110 -0
- package/templates/market-research-tmpl.md +98 -0
- package/templates/migration-plan-tmpl.md +92 -0
- package/templates/prd-tmpl.md +95 -0
- package/templates/project-brief-tmpl.md +100 -0
- package/templates/qa-verdict-tmpl.md +73 -0
- package/templates/rls-policies-tmpl.md +93 -0
- package/templates/schema-design-tmpl.md +107 -0
- package/templates/spec-tmpl.md +88 -0
- package/templates/squad/agent-dna-tmpl.md +72 -0
- package/templates/squad/chief-dna-tmpl.md +98 -0
- package/templates/squad/squad-task-tmpl.md +50 -0
- package/templates/squad/squad-yaml-tmpl.md +47 -0
- package/templates/story-tmpl.md +63 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code-principles
|
|
3
|
+
domain: engineering
|
|
4
|
+
agents: [dev]
|
|
5
|
+
when: "ao escrever ou refatorar qualquer código, para garantir legibilidade e manutenibilidade"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Clean Code — heurísticas de legibilidade e manutenção
|
|
9
|
+
|
|
10
|
+
Código se lê muito mais vezes do que se escreve. A régua aqui é a do `clean-code-javascript`
|
|
11
|
+
de Ryan McDermott (adaptação do _Clean Code_ de Robert C. Martin para JS) — não um style guide,
|
|
12
|
+
mas um guia para produzir software **legível, reutilizável e refatorável**. Os exemplos abaixo são
|
|
13
|
+
os pares reais do repositório-fonte (JavaScript). A regra-mãe: **toda decisão de código tem que se
|
|
14
|
+
justificar** — se um nome, um argumento ou uma condicional só existe porque "saiu assim", é dívida.
|
|
15
|
+
|
|
16
|
+
> Aviso do próprio autor: nem todo princípio precisa ser seguido à risca, e poucos são unânimes. São
|
|
17
|
+
> diretrizes. Mas elas vêm de anos de experiência coletiva — use-as como pedra-de-toque ao avaliar a
|
|
18
|
+
> qualidade do código que você produz.
|
|
19
|
+
|
|
20
|
+
## O problema / os tells
|
|
21
|
+
|
|
22
|
+
Se o diff tem 3+ destes, ele cheira a código apressado, não a craft:
|
|
23
|
+
|
|
24
|
+
1. **Nomes não-pesquisáveis e mágicos** — `setTimeout(blastOff, 86400000)`. Ninguém sabe o que é
|
|
25
|
+
`86400000`, e você não consegue dar `grep` num número solto no meio do código.
|
|
26
|
+
2. **Nomes não-pronunciáveis / abreviados** — `yyyymmdstr`, `l`, `d1`. Se você não consegue falar o
|
|
27
|
+
nome em voz alta numa code review, ele está errado.
|
|
28
|
+
3. **Vocabulário inconsistente pro mesmo conceito** — `getUserInfo()`, `getClientData()`,
|
|
29
|
+
`getCustomerRecord()` espalhados, todos buscando a mesma coisa.
|
|
30
|
+
4. **Funções com 4+ argumentos posicionais** — `createMenu("Foo", "Bar", "Baz", true)`. Na chamada,
|
|
31
|
+
ninguém sabe o que cada posição significa, e o `true` no fim é um enigma.
|
|
32
|
+
5. **Argumento-flag booleano** — `createFile(name, temp)`. A flag denuncia que a função tem dois
|
|
33
|
+
caminhos, logo faz mais de uma coisa.
|
|
34
|
+
6. **Função que faz várias coisas** — filtra, transforma e dispara no mesmo corpo; impossível de
|
|
35
|
+
testar ou reusar em pedaços.
|
|
36
|
+
7. **Side effects escondidos** — função que muta uma variável global ou o objeto recebido por
|
|
37
|
+
parâmetro, em vez de receber e retornar.
|
|
38
|
+
8. **Condicionais negativas e cruas** — `if (!isDOMNodeNotPresent(node))`: dupla negação que trava o
|
|
39
|
+
leitor; `if (fsm.state === "fetching" && isEmpty(listNode))` sem nome que explique a intenção.
|
|
40
|
+
9. **Herança por preguiça** — `EmployeeTaxData extends Employee` quando a relação é "tem-um", não "é-um".
|
|
41
|
+
10. **`catch (error) { console.log(error) }`** — engole o erro sem plano de reação.
|
|
42
|
+
11. **Código morto** — `oldRequestModule` que ninguém chama, mantido "por via das dúvidas". O histórico
|
|
43
|
+
do git já guarda isso.
|
|
44
|
+
|
|
45
|
+
## Os princípios (com pares bad→good reais)
|
|
46
|
+
|
|
47
|
+
### 1. Nomes pesquisáveis (sem números mágicos)
|
|
48
|
+
|
|
49
|
+
Constantes nomeadas em vez de literais soltos — para o leitor entender e para o `grep` achar.
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// Bad — o que diabos é 86400000?
|
|
53
|
+
setTimeout(blastOff, 86400000);
|
|
54
|
+
|
|
55
|
+
// Good — constante nomeada e maiúscula
|
|
56
|
+
const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; // 86400000
|
|
57
|
+
|
|
58
|
+
setTimeout(blastOff, MILLISECONDS_PER_DAY);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Nomes pronunciáveis e significativos
|
|
62
|
+
|
|
63
|
+
Você lê mais código do que escreve; abreviação economiza segundos na escrita e custa minutos na leitura.
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
// Bad
|
|
67
|
+
const yyyymmdstr = moment().format("YYYY/MM/DD");
|
|
68
|
+
|
|
69
|
+
// Good
|
|
70
|
+
const currentDate = moment().format("YYYY/MM/DD");
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
E sem mapeamento mental: nomeie a variável do loop pelo que ela é, não `l`.
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
// Bad — "espera, o que é `l` mesmo?"
|
|
77
|
+
locations.forEach(l => { /* ...muitas linhas... */ dispatch(l); });
|
|
78
|
+
|
|
79
|
+
// Good
|
|
80
|
+
locations.forEach(location => { /* ... */ dispatch(location); });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 3. Mesmo vocabulário pro mesmo tipo
|
|
84
|
+
|
|
85
|
+
Um conceito, um nome. Escolha um e use em todo lugar.
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
// Bad
|
|
89
|
+
getUserInfo();
|
|
90
|
+
getClientData();
|
|
91
|
+
getCustomerRecord();
|
|
92
|
+
|
|
93
|
+
// Good
|
|
94
|
+
getUser();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 4. ≤2 argumentos — objeto quando precisar de mais
|
|
98
|
+
|
|
99
|
+
Mais de 2-3 parâmetros leva à explosão combinatória de casos de teste e some com a clareza na chamada.
|
|
100
|
+
Quando precisar de muitos, passe **um objeto** e desestruture — a assinatura passa a documentar quais
|
|
101
|
+
campos a função usa, e simula parâmetros nomeados.
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// Bad — o que é `true`? e a ordem?
|
|
105
|
+
function createMenu(title, body, buttonText, cancellable) { /* ... */ }
|
|
106
|
+
createMenu("Foo", "Bar", "Baz", true);
|
|
107
|
+
|
|
108
|
+
// Good — campos nomeados, ordem irrelevante
|
|
109
|
+
function createMenu({ title, body, buttonText, cancellable }) { /* ... */ }
|
|
110
|
+
createMenu({ title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 5. Função faz UMA coisa
|
|
114
|
+
|
|
115
|
+
A regra mais importante. Quando a função faz mais de uma coisa, é difícil compor, testar e raciocinar.
|
|
116
|
+
Isole cada ação.
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// Bad — itera, busca no banco, checa estado e envia, tudo junto
|
|
120
|
+
function emailClients(clients) {
|
|
121
|
+
clients.forEach(client => {
|
|
122
|
+
const clientRecord = database.lookup(client);
|
|
123
|
+
if (clientRecord.isActive()) {
|
|
124
|
+
email(client);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Good — cada função tem um trabalho
|
|
130
|
+
function emailActiveClients(clients) {
|
|
131
|
+
clients.filter(isActiveClient).forEach(email);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isActiveClient(client) {
|
|
135
|
+
const clientRecord = database.lookup(client);
|
|
136
|
+
return clientRecord.isActive();
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 6. Sem flag booleana como argumento
|
|
141
|
+
|
|
142
|
+
A flag avisa que a função tem caminhos diferentes — ou seja, faz mais de uma coisa. Separe.
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// Bad
|
|
146
|
+
function createFile(name, temp) {
|
|
147
|
+
if (temp) {
|
|
148
|
+
fs.create(`./temp/${name}`);
|
|
149
|
+
} else {
|
|
150
|
+
fs.create(name);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Good
|
|
155
|
+
function createFile(name) {
|
|
156
|
+
fs.create(name);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function createTempFile(name) {
|
|
160
|
+
createFile(`./temp/${name}`);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 7. Evite side effects
|
|
165
|
+
|
|
166
|
+
Uma função idealmente recebe valores e retorna valores — não muta estado global nem o objeto/array
|
|
167
|
+
recebido. Mutar dado compartilhado gera bugs em lugares distantes. Centralize os efeitos que forem
|
|
168
|
+
inevitáveis (ex.: escrever em arquivo) em um único serviço.
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
// Bad — muta uma global; outra função que use `name` quebra
|
|
172
|
+
let name = "Ryan McDermott";
|
|
173
|
+
function splitIntoFirstAndLastName() {
|
|
174
|
+
name = name.split(" ");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Good — recebe e retorna, sem tocar no de fora
|
|
178
|
+
function splitIntoFirstAndLastName(name) {
|
|
179
|
+
return name.split(" ");
|
|
180
|
+
}
|
|
181
|
+
const newName = splitIntoFirstAndLastName(name);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
O mesmo vale para arrays/objetos passados por parâmetro: clone em vez de mutar.
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
// Bad — muta o cart de quem chamou
|
|
188
|
+
const addItemToCart = (cart, item) => {
|
|
189
|
+
cart.push({ item, date: Date.now() });
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Good — retorna um novo cart
|
|
193
|
+
const addItemToCart = (cart, item) => {
|
|
194
|
+
return [...cart, { item, date: Date.now() }];
|
|
195
|
+
};
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 8. Evite condicionais negativas
|
|
199
|
+
|
|
200
|
+
Negativa (ainda mais dupla) força o leitor a inverter a lógica na cabeça. Nomeie no positivo.
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
// Bad — dupla negação
|
|
204
|
+
function isDOMNodeNotPresent(node) { /* ... */ }
|
|
205
|
+
if (!isDOMNodeNotPresent(node)) { /* ... */ }
|
|
206
|
+
|
|
207
|
+
// Good
|
|
208
|
+
function isDOMNodePresent(node) { /* ... */ }
|
|
209
|
+
if (isDOMNodePresent(node)) { /* ... */ }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 9. Encapsule condicionais
|
|
213
|
+
|
|
214
|
+
Uma expressão booleana composta vira uma função com nome que diz a intenção.
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
// Bad
|
|
218
|
+
if (fsm.state === "fetching" && isEmpty(listNode)) { /* ... */ }
|
|
219
|
+
|
|
220
|
+
// Good
|
|
221
|
+
function shouldShowSpinner(fsm, listNode) {
|
|
222
|
+
return fsm.state === "fetching" && isEmpty(listNode);
|
|
223
|
+
}
|
|
224
|
+
if (shouldShowSpinner(fsmInstance, listNodeInstance)) { /* ... */ }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 10. Composição > herança
|
|
228
|
+
|
|
229
|
+
Se sua cabeça já foi pra `extends`, pare e pergunte se é "é-um" (herança) ou "tem-um" (composição).
|
|
230
|
+
`EmployeeTaxData` não é um tipo de `Employee` — um empregado **tem** dados fiscais.
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
// Bad — herança forçada numa relação "tem-um"
|
|
234
|
+
class EmployeeTaxData extends Employee {
|
|
235
|
+
constructor(ssn, salary) {
|
|
236
|
+
super();
|
|
237
|
+
this.ssn = ssn;
|
|
238
|
+
this.salary = salary;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Good — composição
|
|
243
|
+
class Employee {
|
|
244
|
+
constructor(name, email) {
|
|
245
|
+
this.name = name;
|
|
246
|
+
this.email = email;
|
|
247
|
+
}
|
|
248
|
+
setTaxData(ssn, salary) {
|
|
249
|
+
this.taxData = new EmployeeTaxData(ssn, salary);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 11. SOLID em JS — os cinco
|
|
255
|
+
|
|
256
|
+
**S — Single Responsibility.** Uma classe, uma razão para mudar. Separe autenticação de configuração.
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
// Bad — UserSettings também verifica credenciais
|
|
260
|
+
class UserSettings {
|
|
261
|
+
changeSettings(settings) {
|
|
262
|
+
if (this.verifyCredentials()) { /* ... */ }
|
|
263
|
+
}
|
|
264
|
+
verifyCredentials() { /* ... */ }
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Good — auth virou colaboradora
|
|
268
|
+
class UserAuth {
|
|
269
|
+
constructor(user) { this.user = user; }
|
|
270
|
+
verifyCredentials() { /* ... */ }
|
|
271
|
+
}
|
|
272
|
+
class UserSettings {
|
|
273
|
+
constructor(user) {
|
|
274
|
+
this.user = user;
|
|
275
|
+
this.auth = new UserAuth(user);
|
|
276
|
+
}
|
|
277
|
+
changeSettings(settings) {
|
|
278
|
+
if (this.auth.verifyCredentials()) { /* ... */ }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**O — Open/Closed.** Aberto para extensão, fechado para modificação. Em vez de `if adapter.name === ...`,
|
|
284
|
+
deixe cada adapter implementar o contrato.
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
// Bad — fetch precisa mudar a cada novo adapter
|
|
288
|
+
fetch(url) {
|
|
289
|
+
if (this.adapter.name === "ajaxAdapter") { return makeAjaxCall(url).then(/*...*/); }
|
|
290
|
+
else if (this.adapter.name === "nodeAdapter") { return makeHttpCall(url).then(/*...*/); }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Good — cada adapter tem request(); HttpRequester não muda
|
|
294
|
+
fetch(url) {
|
|
295
|
+
return this.adapter.request(url).then(response => { /* transform */ });
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**L — Liskov Substitution.** Subtipo tem que substituir o tipo base sem quebrar resultados. O clássico
|
|
300
|
+
Square/Rectangle: forçar `Square extends Rectangle` faz `getArea()` mentir. Modele ambos sobre `Shape`.
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
// Good — sem herança que viola contrato
|
|
304
|
+
class Shape { render(area) { /* ... */ } }
|
|
305
|
+
class Rectangle extends Shape {
|
|
306
|
+
constructor(width, height) { super(); this.width = width; this.height = height; }
|
|
307
|
+
getArea() { return this.width * this.height; }
|
|
308
|
+
}
|
|
309
|
+
class Square extends Shape {
|
|
310
|
+
constructor(length) { super(); this.length = length; }
|
|
311
|
+
getArea() { return this.length * this.length; }
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**I — Interface Segregation.** Não force o cliente a depender do que não usa. Settings opcionais em vez
|
|
316
|
+
de "fat interface".
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
// Good — animationModule é opcional, dentro de options
|
|
320
|
+
const $ = new DOMTraverser({
|
|
321
|
+
rootNode: document.getElementsByTagName("body"),
|
|
322
|
+
options: { animationModule() {} }
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**D — Dependency Inversion.** Módulo de alto nível não depende do de baixo nível — ambos dependem de
|
|
327
|
+
abstração. Injete a dependência em vez de instanciá-la dentro.
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
// Bad — InventoryTracker cria a dependência concreta
|
|
331
|
+
class InventoryTracker {
|
|
332
|
+
constructor(items) {
|
|
333
|
+
this.items = items;
|
|
334
|
+
this.requester = new InventoryRequester(); // acoplado
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Good — requester é injetado (qualquer um com requestItem serve)
|
|
339
|
+
class InventoryTracker {
|
|
340
|
+
constructor(items, requester) {
|
|
341
|
+
this.items = items;
|
|
342
|
+
this.requester = requester;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 12. Lance objetos Error, não strings; e nunca ignore o erro capturado
|
|
348
|
+
|
|
349
|
+
Erros lançados são bons: o runtime te avisa que algo deu errado, com stack trace. Lance um `Error` de
|
|
350
|
+
verdade (carrega mensagem **e** stack), e dê um plano para o `catch` — não engula.
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
// Tell — string crua não tem stack trace
|
|
354
|
+
throw "Must be of type String or Number";
|
|
355
|
+
|
|
356
|
+
// Good — Error object, com stack
|
|
357
|
+
throw new Error("Must be of type String or Number");
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
// Bad — engole o erro
|
|
362
|
+
try {
|
|
363
|
+
functionThatMightThrow();
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.log(error);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Good — reaja: log de erro, notifique, ou reporte
|
|
369
|
+
try {
|
|
370
|
+
functionThatMightThrow();
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.error(error);
|
|
373
|
+
notifyUserOfError(error);
|
|
374
|
+
reportErrorToService(error);
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
O mesmo vale para promises rejeitadas: trate no `.catch`, não só `console.log`.
|
|
379
|
+
|
|
380
|
+
### 13. Remova código morto
|
|
381
|
+
|
|
382
|
+
Se ninguém chama, apague. O histórico do git guarda. `oldRequestModule` parado ao lado do `new` só
|
|
383
|
+
confunde quem lê.
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
// Bad — função antiga nunca chamada, mantida "por garantia"
|
|
387
|
+
function oldRequestModule(url) { /* ... */ }
|
|
388
|
+
function newRequestModule(url) { /* ... */ }
|
|
389
|
+
const req = newRequestModule;
|
|
390
|
+
|
|
391
|
+
// Good — só o que está em uso
|
|
392
|
+
function newRequestModule(url) { /* ... */ }
|
|
393
|
+
const req = newRequestModule;
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Checklist
|
|
397
|
+
|
|
398
|
+
Antes de marcar a task como pronta, responda — qualquer "sim" é dívida a corrigir:
|
|
399
|
+
|
|
400
|
+
- [ ] Tem número/string mágico que deveria ser constante nomeada e pesquisável?
|
|
401
|
+
- [ ] Algum nome é abreviado, não-pronunciável ou exige mapeamento mental (`l`, `d1`, `yyyymmdstr`)?
|
|
402
|
+
- [ ] O mesmo conceito aparece com nomes diferentes (`getUserInfo`/`getClientData`/...)?
|
|
403
|
+
- [ ] Alguma função tem mais de 2-3 argumentos posicionais sem virar objeto?
|
|
404
|
+
- [ ] Há argumento booleano (flag) que denuncia dois caminhos na mesma função?
|
|
405
|
+
- [ ] Alguma função faz mais de uma coisa (mistura busca, transformação e efeito)?
|
|
406
|
+
- [ ] Alguma função muta estado global ou o objeto/array recebido por parâmetro?
|
|
407
|
+
- [ ] Há condicional negativa (ou dupla negação) que poderia ser positiva?
|
|
408
|
+
- [ ] Há booleano composto cru no `if` que mereceria uma função nomeada?
|
|
409
|
+
- [ ] Usei `extends` numa relação "tem-um" em vez de composição?
|
|
410
|
+
- [ ] Lancei string em vez de `new Error(...)`? Engoli algum erro com `console.log` sem reação?
|
|
411
|
+
- [ ] Sobrou código morto (função/branch que ninguém chama)?
|
|
412
|
+
|
|
413
|
+
## Tabela de decisão
|
|
414
|
+
|
|
415
|
+
| Use isto | Quando |
|
|
416
|
+
|---|---|
|
|
417
|
+
| Constante nomeada (`MILLISECONDS_PER_DAY`) | houver qualquer literal numérico/string com significado no código |
|
|
418
|
+
| Argumento objeto + desestruturação | a função precisar de mais de 2-3 parâmetros |
|
|
419
|
+
| Duas funções separadas | você fosse passar uma flag booleana para escolher o caminho |
|
|
420
|
+
| Receber + retornar (sem mutar) | a função tocaria estado global ou o objeto/array recebido |
|
|
421
|
+
| Clonar (`[...cart, item]`) | precisar "alterar" um array/objeto vindo por parâmetro |
|
|
422
|
+
| Função nomeada (`shouldShowSpinner`) | um `if` tiver booleano composto ou intenção não-óbvia |
|
|
423
|
+
| Condicional no positivo | o nome/teste estiver no negativo (ou em dupla negação) |
|
|
424
|
+
| Composição (`has-a`) | a relação for "tem-um" (`Employee` tem `TaxData`) |
|
|
425
|
+
| Herança (`is-a`) | for genuinamente "é-um", houver reuso da base e mudança global desejada |
|
|
426
|
+
| Injeção de dependência (DIP) | um módulo de alto nível instanciaria diretamente um concreto de baixo nível |
|
|
427
|
+
| Polimorfismo / contrato comum (OCP, LSP) | um `if/switch` ramificar por `type`/`name` e tender a crescer |
|
|
428
|
+
| `throw new Error(...)` + reação no `catch` | algo puder dar errado e você precisar de stack trace e plano |
|
|
429
|
+
| Apagar (confiar no git) | o código não for chamado por ninguém |
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: effective-code-review
|
|
3
|
+
domain: engineering
|
|
4
|
+
agents: [dev, qa]
|
|
5
|
+
when: "ao revisar um pull/merge request ou preparar o próprio CL para review"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Code review eficaz — o padrão do Google
|
|
9
|
+
|
|
10
|
+
A maioria das discussões de code review trava por falta de um critério compartilhado. Sem ele, o
|
|
11
|
+
review vira gosto pessoal: o revisor segura o CL até ele ficar "do jeito dele", o autor responde na
|
|
12
|
+
defensiva, e o que era pra melhorar o código vira queda de braço. Este pack destila o padrão do Google
|
|
13
|
+
(`google/eng-practices`: *How to do a code review* + *The CL author guide*), porque ele resolve isso com
|
|
14
|
+
**um único critério-mestre** do qual todo o resto deriva.
|
|
15
|
+
|
|
16
|
+
> A fonte chama o pull request de **CL** (changelist). Aqui usamos "CL" e "PR/MR" como sinônimos.
|
|
17
|
+
|
|
18
|
+
## O problema / os tells
|
|
19
|
+
|
|
20
|
+
Você está num review medíocre quando vê:
|
|
21
|
+
|
|
22
|
+
1. **Review como busca pela perfeição.** O revisor segura o CL porque "dá pra ficar melhor" — sem que o
|
|
23
|
+
estado atual piore o código. A fonte é direta: *"there is no such thing as 'perfect' code—there is
|
|
24
|
+
only better code."* Perfeição não é o critério; melhoria do code health é.
|
|
25
|
+
2. **CLs gigantes.** Um PR de 800 linhas espalhado por 40 arquivos. Ninguém revisa de verdade: *"important
|
|
26
|
+
points get missed or dropped."*
|
|
27
|
+
3. **Feedback sem severidade.** Tudo no mesmo tom. O autor não sabe o que é bloqueante e o que é gosto, e
|
|
28
|
+
trata um typo de comentário com o mesmo peso de um bug de concorrência.
|
|
29
|
+
4. **Feedback como ordem, nunca como ensino.** O revisor manda "faça X" sem dizer por quê. O autor obedece
|
|
30
|
+
sem aprender; o próximo CL repete o erro.
|
|
31
|
+
5. **Descrição de CL inútil.** Título "Fix bug", "Phase 1", "Add patch". Daqui a um ano, o `git log` não
|
|
32
|
+
diz nada a ninguém.
|
|
33
|
+
6. **Review parado por dias.** O CL fica encalhado porque autor e revisor não chegam a acordo, ou porque
|
|
34
|
+
o revisor "depois olha". A velocidade do time inteiro cai.
|
|
35
|
+
7. **Autor na defensiva.** Resposta no calor, tratando crítica ao código como ataque pessoal — *"never
|
|
36
|
+
respond in anger to code review comments."*
|
|
37
|
+
|
|
38
|
+
## Os princípios
|
|
39
|
+
|
|
40
|
+
### 1. O critério-mestre: aprove quando o CL melhora a saúde do código
|
|
41
|
+
|
|
42
|
+
O propósito do review não é provar que o código é perfeito, é garantir que *"the overall code health of
|
|
43
|
+
the codebase is improving over time."* Daí a regra de aprovação:
|
|
44
|
+
|
|
45
|
+
> *"In general, reviewers should favor approving a CL once it is in a state where it definitely improves
|
|
46
|
+
> the overall code health of the system being worked on, even if the CL isn't perfect."*
|
|
47
|
+
|
|
48
|
+
Isso não é desculpa pra deixar passar lixo — a contrapartida é igualmente firme: *"Don't accept CLs that
|
|
49
|
+
degrade the code health of the system."* O CL não precisa ser perfeito; precisa ser **melhor**, e não pode
|
|
50
|
+
piorar. Quando ele claramente melhora e só restam refinamentos opcionais, aprove com comentários (o
|
|
51
|
+
"LGTM with comments"): você libera o autor e confia que ele endereça os nits.
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
# ❌ revisor segurando por perfeição
|
|
55
|
+
"Funciona e está mais limpo que o anterior, mas não vou aprovar até você
|
|
56
|
+
extrair essas 3 funções, renomear o módulo e adicionar 4 testes a mais."
|
|
57
|
+
|
|
58
|
+
# ✅ aprovar a melhoria, marcar o resto como opcional
|
|
59
|
+
"LGTM. Melhora clara sobre o que existia. Nit: dá pra extrair `parseHeader`
|
|
60
|
+
numa função à parte depois — opcional, não bloqueia o merge."
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. O que o revisor procura (nesta ordem de importância)
|
|
64
|
+
|
|
65
|
+
A fonte lista explicitamente o que olhar — **design vem primeiro**, não estilo:
|
|
66
|
+
|
|
67
|
+
- **Design.** A interação das peças faz sentido? A mudança pertence a este codebase ou a uma lib? É o
|
|
68
|
+
ponto mais importante do review.
|
|
69
|
+
- **Funcionalidade.** *"Does this CL do what the developer intended?"* Pensa em edge cases, concorrência,
|
|
70
|
+
bugs. Mudança de UI muitas vezes pede um demo pra entender o impacto real no usuário.
|
|
71
|
+
- **Complexidade.** Está *"more complex than it should be"*? O teste prático: se *"can't be understood
|
|
72
|
+
quickly by code readers"*, é complexo demais. Cuidado com over-engineering — resolva o problema que
|
|
73
|
+
você sabe que precisa ser resolvido **agora**, não o especulado.
|
|
74
|
+
- **Testes.** Há testes unit/integration/e2e adequados? Eles **falham quando o código quebra** e fazem
|
|
75
|
+
asserções úteis, sem complexidade desnecessária.
|
|
76
|
+
- **Nomes.** *"long enough to fully communicate what the item is or does, without being so long that it
|
|
77
|
+
becomes hard to read."*
|
|
78
|
+
- **Comentários.** Bons comentários *"explain why"* o código existe — a razão que o código não mostra
|
|
79
|
+
sozinho —, não parafraseiam o que ele faz.
|
|
80
|
+
- **Estilo / consistência.** Style guide é autoridade. Divergência de gosto pessoal vira `Nit:`, não
|
|
81
|
+
bloqueio.
|
|
82
|
+
- **Documentação.** README, docs e referências acompanham a mudança quando relevante.
|
|
83
|
+
- **Cada linha.** Revise todo o código designado — entender cada peça importa pro próximo dev.
|
|
84
|
+
- **Contexto.** Olhe o impacto sistêmico, não só o diff. E **elogie o que está bom**: reconheça boas
|
|
85
|
+
soluções, não só aponte problemas.
|
|
86
|
+
|
|
87
|
+
### 3. CLs pequenos: o multiplicador de qualidade
|
|
88
|
+
|
|
89
|
+
Tamanho não é detalhe — é o fator que mais muda a qualidade do review. A régua da fonte:
|
|
90
|
+
|
|
91
|
+
> *"100 lines is usually a reasonable size for a CL, and 1000 lines is usually too large."*
|
|
92
|
+
|
|
93
|
+
E o tamanho é sobre **mudança lógica autocontida**, não só contagem bruta: *"A 200-line change in one file
|
|
94
|
+
might be okay, but spread across 50 files it would usually be too large."* O CL certo faz **uma coisa**.
|
|
95
|
+
Na dúvida, *"write CLs that are smaller than you think you need to write."*
|
|
96
|
+
|
|
97
|
+
Por que pequeno ganha: é revisado mais rápido (cinco minutos várias vezes), revisado a fundo (em CL
|
|
98
|
+
grande *"important points get missed or dropped"*), introduz menos bugs, desperdiça menos trabalho se a
|
|
99
|
+
direção estiver errada, dá menos conflito de merge, é mais fácil de desenhar bem e de reverter.
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
# ❌ um CL: "Add user profiles"
|
|
103
|
+
migration + model + 3 endpoints + UI + refactor do auth + rename de 12 arquivos
|
|
104
|
+
→ 900 linhas, 40 arquivos, ninguém revisa de verdade
|
|
105
|
+
|
|
106
|
+
# ✅ sequência de CLs autocontidos
|
|
107
|
+
CL1: migration + model (~80 linhas)
|
|
108
|
+
CL2: endpoints de leitura + testes (~120 linhas)
|
|
109
|
+
CL3: UI de profile (~150 linhas)
|
|
110
|
+
→ cada um revisável em minutos, mergeável e reversível sozinho
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 4. Dar feedback: severidade explícita, ensinar não impor
|
|
114
|
+
|
|
115
|
+
**Marque a severidade.** O autor precisa distinguir bloqueante de sugestão. Prefixos da fonte:
|
|
116
|
+
|
|
117
|
+
- `Nit:` — *"a minor thing. Technically you should do it, but it won't hugely impact things."*
|
|
118
|
+
- `Optional (ou Consider):` — *"I think this may be a good idea, but it's not strictly required."*
|
|
119
|
+
- `FYI:` — *"I don't expect you to do this in this CL, but you may find this interesting."*
|
|
120
|
+
|
|
121
|
+
**Ensine, não mande.** *"Pointing out problems and letting the developer make a decision often helps the
|
|
122
|
+
developer learn."* Explique o **porquê**. E quando o código está complexo demais, *"encourage developers
|
|
123
|
+
to simplify code or add code comments instead of just explaining the complexity to you"* — o ganho fica
|
|
124
|
+
no código, não na conversa do review. Sempre: *"courteous and respectful while also being very clear and
|
|
125
|
+
helpful."*
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
# ❌ ordem sem razão, severidade ambígua
|
|
129
|
+
"Use um map aqui."
|
|
130
|
+
|
|
131
|
+
# ✅ aponta o problema, ensina, marca severidade
|
|
132
|
+
"Este loop aninhado é O(n²); com a lista de pedidos crescendo isso vira gargalo.
|
|
133
|
+
Um map de id→pedido resolve em O(n). Required."
|
|
134
|
+
|
|
135
|
+
# nit de verdade, marcado como tal:
|
|
136
|
+
"Nit: `d` poderia ser `daysUntilDue` pra ficar autoexplicativo. Opcional."
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 5. O guia do AUTOR
|
|
140
|
+
|
|
141
|
+
- **Descrição do CL.** Primeira linha = resumo curto, no **imperativo** ("Delete the FizzBuzz RPC and
|
|
142
|
+
replace it with the new system"), dizendo **o que** muda. Corpo = **o quê e por quê**, com números de
|
|
143
|
+
bug, benchmarks e links de design. Ruins (da fonte): "Fix bug", "Fix build", "Add patch", "Phase 1",
|
|
144
|
+
"kill weird URLs" — *"do not provide enough useful information."* Bom: *"RPC: Remove size limit on RPC
|
|
145
|
+
server message freelist. Servers like FizzBuzz have very large messages and would benefit from reuse."*
|
|
146
|
+
- **Responder a reviews.** *"Don't take it personally"* — a crítica é ao código, não a você. Nunca
|
|
147
|
+
responda com raiva. Se o revisor não entendeu, **conserte o código** primeiro; se não dá pra clarear,
|
|
148
|
+
adicione um comentário no código explicando o porquê; explicar só no review tool é último recurso (o
|
|
149
|
+
próximo leitor não vê a thread do PR).
|
|
150
|
+
- **Discordar bem.** Pense em colaboração, não defesa: *"I went with X because of [these pros/cons]... Are
|
|
151
|
+
you suggesting that Y better serves the original tradeoffs?"*
|
|
152
|
+
|
|
153
|
+
### 6. Resolver conflitos e velocidade
|
|
154
|
+
|
|
155
|
+
Conflito entre autor e revisor se resolve por **fatos, não preferências**: *"Technical facts and data
|
|
156
|
+
overrule opinions and personal preferences."* Style guide é autoridade no estilo. Busquem consenso; se
|
|
157
|
+
não houver, apliquem os princípios deste padrão e, persistindo, escalem pra liderança técnica. Acima de
|
|
158
|
+
tudo: *"Don't let a CL sit around because the author and the reviewer can't come to an agreement."*
|
|
159
|
+
|
|
160
|
+
**Velocidade:** o que importa é o **tempo de resposta**, não o tempo total do CL. A régua: *"One business
|
|
161
|
+
day is the maximum time it should take to respond to a code review request."* Se você não está no meio de
|
|
162
|
+
uma tarefa focada, revise logo que o CL chega; se está codando concentrado, *"don't interrupt yourself"*
|
|
163
|
+
— responda num ponto natural de pausa. Review lento derruba a velocidade do time inteiro.
|
|
164
|
+
|
|
165
|
+
## Checklist
|
|
166
|
+
|
|
167
|
+
Antes de **aprovar** um CL:
|
|
168
|
+
|
|
169
|
+
- [ ] O CL **melhora** a saúde do código e **não a piora**? (critério-mestre — não exija perfeição)
|
|
170
|
+
- [ ] O **design** faz sentido e a mudança pertence a este codebase?
|
|
171
|
+
- [ ] Faz o que o autor pretendeu, incluindo edge cases e concorrência?
|
|
172
|
+
- [ ] Não está mais complexo que o necessário, sem over-engineering pra o futuro?
|
|
173
|
+
- [ ] Tem testes que **falham quando o código quebra**, com asserções úteis?
|
|
174
|
+
- [ ] Nomes claros, comentários que explicam o **porquê**, docs atualizadas?
|
|
175
|
+
- [ ] Revisei **cada linha** designada e elogiei o que está bom?
|
|
176
|
+
- [ ] Marquei a **severidade** (`Nit:`/`Optional:`/`FYI:`) e expliquei o **porquê** de cada comentário?
|
|
177
|
+
- [ ] Respondi em até **um dia útil**?
|
|
178
|
+
|
|
179
|
+
Antes de **enviar** o próprio CL:
|
|
180
|
+
|
|
181
|
+
- [ ] É **uma mudança autocontida** (~100 linhas; 1000 é grande demais; cuidado com o espalhamento)?
|
|
182
|
+
- [ ] A descrição tem primeira linha no imperativo + corpo com **o quê e por quê** (não "Fix bug")?
|
|
183
|
+
- [ ] Vou responder ao review sobre o **código**, sem levar pro pessoal?
|
|
184
|
+
|
|
185
|
+
## Tabela de decisão
|
|
186
|
+
|
|
187
|
+
| Situação | O que fazer |
|
|
188
|
+
|---|---|
|
|
189
|
+
| CL melhora o código mas não está perfeito | **Aprove** (LGTM with comments); marque refinamentos como `Nit:`/`Optional:` |
|
|
190
|
+
| CL piora a saúde do código | **Não aprove**; aponte o problema com o porquê |
|
|
191
|
+
| Comentário é gosto pessoal / estilo | `Nit:`; não bloqueie o merge por isso |
|
|
192
|
+
| Comentário é design/funcionalidade/segurança | Required; bloqueie e explique o porquê |
|
|
193
|
+
| CL > ~1000 linhas ou espalhado por dezenas de arquivos | Peça pra **quebrar** em CLs autocontidos |
|
|
194
|
+
| Código complexo demais de entender | Peça **simplificar ou comentar no código** — não aceite explicação só no PR |
|
|
195
|
+
| Quer que o dev aprenda | Aponte o **problema** e deixe ele decidir, em vez de dar a ordem pronta |
|
|
196
|
+
| Autor e revisor não chegam a acordo | Decida por **fatos/dados** e pelo style guide; persistindo, **escale** — não deixe o CL parado |
|
|
197
|
+
| Chegou um review e você não está focado em outra coisa | Revise **logo** (alvo: resposta em ≤ 1 dia útil) |
|
|
198
|
+
| Chegou um review e você está codando concentrado | Não se interrompa; responda numa **pausa natural** |
|
|
199
|
+
| Revisor não entendeu seu código | **Conserte o código** ou comente nele o porquê; explicar só no PR é último recurso |
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
**Fonte:** Google Engineering Practices — `google.github.io/eng-practices`
|
|
204
|
+
(*How to do a code review* e *The CL author guide*).
|