@luanpdd/kit-mcp 1.34.0 → 1.36.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.
Files changed (118) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +2 -2
  3. package/bin/mcp.js +6 -6
  4. package/bin/ui.js +74 -74
  5. package/gates/ai-prompt-stability.md +120 -120
  6. package/gates/budget-description.md +68 -68
  7. package/gates/confidence.md +29 -29
  8. package/gates/dependency-check.md +33 -33
  9. package/gates/dept-cycle-prevention.md +179 -179
  10. package/gates/golden-signals-coverage.md +133 -133
  11. package/gates/legacy-refactor-safety.md +178 -178
  12. package/gates/multi-tenant-rls-coverage.md +102 -102
  13. package/gates/no-personal-uuid.md +72 -72
  14. package/gates/obs-agents-mcp-supabase.md +86 -86
  15. package/gates/obs-skills-frontmatter.md +76 -76
  16. package/gates/observability-coverage.md +151 -151
  17. package/gates/omm-no-regression.md +83 -83
  18. package/gates/postmortem-template-required.md +127 -127
  19. package/gates/prr-checklist-coverage.md +128 -128
  20. package/gates/regression.md +32 -32
  21. package/gates/release-pipeline-policy.md +132 -132
  22. package/gates/secrets-scan.md +33 -33
  23. package/gates/service-role-not-in-user-facing.md +113 -113
  24. package/gates/skill-must-include.md +71 -71
  25. package/gates/sync-idempotent.md +62 -62
  26. package/gates/verify-phase-goal.md +34 -34
  27. package/kit/agents/designer-ui.md +216 -216
  28. package/kit/agents/workflow-generator.md +537 -0
  29. package/kit/commands/adicionar-backlog.md +1 -1
  30. package/kit/commands/adicionar-fase.md +1 -1
  31. package/kit/commands/adicionar-tarefa.md +1 -1
  32. package/kit/commands/auditar-observabilidade.md +103 -103
  33. package/kit/commands/auditar-toil.md +129 -129
  34. package/kit/commands/caracterizar-prompt.md +195 -195
  35. package/kit/commands/criar-workflow.md +158 -0
  36. package/kit/commands/definir-perfil.md +1 -1
  37. package/kit/commands/definir-slo.md +108 -108
  38. package/kit/commands/fio.md +1 -1
  39. package/kit/commands/golden-signals.md +142 -142
  40. package/kit/commands/instrumentar-fase.md +200 -200
  41. package/kit/commands/investigar-producao.md +162 -162
  42. package/kit/commands/observabilidade.md +118 -118
  43. package/kit/commands/postmortem.md +179 -179
  44. package/kit/commands/prr.md +205 -205
  45. package/kit/commands/publicar-rapido.md +207 -207
  46. package/kit/commands/risk-budget.md +220 -220
  47. package/kit/commands/sre.md +230 -230
  48. package/kit/file-manifest.json +5 -2
  49. package/kit/framework/references/output-style.md +22 -22
  50. package/kit/hooks/post-apply-migration.js +199 -199
  51. package/kit/hooks/sidecar-tool-publisher.js +210 -210
  52. package/kit/skills/_shared-dados-distribuidos/glossary.md +224 -224
  53. package/kit/skills/_shared-legacy/glossary.md +389 -389
  54. package/kit/skills/_shared-multi-tenant/glossary.md +186 -186
  55. package/kit/skills/_shared-observability/glossary.md +396 -396
  56. package/kit/skills/_shared-sre/glossary.md +712 -712
  57. package/kit/skills/_shared-supabase/glossary.md +234 -234
  58. package/kit/skills/blameless-postmortems/SKILL.md +340 -340
  59. package/kit/skills/burn-rate-alerting/SKILL.md +258 -258
  60. package/kit/skills/cascading-failures/SKILL.md +311 -311
  61. package/kit/skills/core-analysis-loop/SKILL.md +352 -352
  62. package/kit/skills/distributed-tracing/SKILL.md +362 -362
  63. package/kit/skills/dynamic-workflow-authoring/SKILL.md +327 -0
  64. package/kit/skills/eliminating-toil/SKILL.md +243 -243
  65. package/kit/skills/event-based-slos/SKILL.md +296 -296
  66. package/kit/skills/four-golden-signals/SKILL.md +314 -314
  67. package/kit/skills/hermetic-builds/SKILL.md +323 -323
  68. package/kit/skills/legacy-monster-methods/SKILL.md +444 -444
  69. package/kit/skills/llm-as-dependency/SKILL.md +436 -436
  70. package/kit/skills/load-shedding-graceful-degradation/SKILL.md +396 -396
  71. package/kit/skills/observability-driven-development/SKILL.md +315 -315
  72. package/kit/skills/observability-maturity-model/SKILL.md +222 -222
  73. package/kit/skills/opentelemetry-standard/SKILL.md +351 -351
  74. package/kit/skills/production-readiness-review/SKILL.md +305 -305
  75. package/kit/skills/release-engineering/SKILL.md +367 -367
  76. package/kit/skills/retry-strategies/SKILL.md +372 -372
  77. package/kit/skills/sre-risk-management/SKILL.md +221 -221
  78. package/kit/skills/structured-events/SKILL.md +265 -265
  79. package/kit/skills/supabase-cron-queues/SKILL.md +275 -275
  80. package/kit/skills/supabase-database-functions/SKILL.md +332 -332
  81. package/kit/skills/supabase-declarative-schema/SKILL.md +183 -183
  82. package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -253
  83. package/kit/skills/supabase-postgres-style/SKILL.md +138 -138
  84. package/kit/skills/supabase-storage/SKILL.md +234 -234
  85. package/kit/skills/telemetry-pipelines/SKILL.md +259 -259
  86. package/kit/skills/telemetry-sampling/SKILL.md +256 -256
  87. package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
  88. package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
  89. package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
  90. package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
  91. package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
  92. package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
  93. package/kit/skills/ui-tipografia/SKILL.md +211 -211
  94. package/package.json +1 -1
  95. package/src/cli/index.js +1114 -1114
  96. package/src/cli/render.js +194 -194
  97. package/src/cli/upgrade-check.js +135 -135
  98. package/src/core/error-redaction.js +76 -76
  99. package/src/core/failures.js +153 -153
  100. package/src/core/gate-runner.js +205 -205
  101. package/src/core/gates.js +82 -82
  102. package/src/core/logger.js +170 -170
  103. package/src/core/manifest-verify.js +174 -174
  104. package/src/core/metrics.js +268 -268
  105. package/src/core/notify.js +60 -60
  106. package/src/core/path-safety.js +141 -141
  107. package/src/core/replays.js +120 -120
  108. package/src/core/ui.js +185 -185
  109. package/src/mcp-server/install.js +149 -149
  110. package/src/mcp-server/roots.js +124 -124
  111. package/src/ui/auto-spawn.js +113 -113
  112. package/src/ui/browser.js +78 -78
  113. package/src/ui/client.js +130 -130
  114. package/src/ui/events.js +65 -65
  115. package/src/ui/lockfile.js +191 -191
  116. package/src/ui/port.js +67 -67
  117. package/src/ui/server.js +547 -547
  118. package/src/ui/wrapper.js +129 -129
@@ -1,444 +1,444 @@
1
- ---
2
- name: legacy-monster-methods
3
- description: Use ao refatorar método > 100 linhas sem testes — scratch refactoring, single-goal editing, safe extraction (cap 22 Feathers). Padrões para domesticar bulleted vs snarled methods.
4
- ---
5
-
6
- # Legacy — Monster Methods
7
-
8
- ## Quando usar
9
-
10
- LLM carrega esta skill quando o user encontra método absurdamente longo (> 100 linhas) que precisa ser modificado. Trigger phrases:
11
-
12
- - "esse método tem [N] linhas, preciso mudar"
13
- - "monster method", "método monstro", "método gigante"
14
- - "scratch refactoring", "refactor de rascunho"
15
- - "single-goal editing", "edição com objetivo único"
16
- - "extract method em método sem testes"
17
- - "cap 22 Feathers"
18
- - "bulleted method", "snarled method"
19
-
20
- Carrega quando `legacy-characterization-tests` é insuficiente isoladamente — método é grande demais para enumerar inputs, mas precisa ser refatorado para ficar testável.
21
-
22
- ## Regras absolutas
23
-
24
- - **Monster method = > 100 linhas OU > 5 níveis de aninhamento.** Pelo menos 1 dos dois. Heurística empírica do livro.
25
- - **Distinguir bulleted vs snarled.** Bulleted = linhas longas mas planas (mais fácil). Snarled = nesting profundo, control flow complexo (mais difícil). Estratégias diferentes.
26
- - **Scratch refactoring é DESCARTÁVEL.** Branch lixo, refactor estético para entender, depois `git checkout main` e descarte tudo. Só conhecimento adquirido viaja para a refatoração real.
27
- - **Single-goal editing.** UMA mudança por commit/PR. Renomear OR extrair OR mover, NUNCA os 3 juntos. Cada commit é mecânico, isolado, revisável.
28
- - **Extract method em monster sem teste = SAFE EXTRACTION.** Apenas levantar bloco contíguo + capturar variáveis usadas como parâmetros. SEM mover lógica entre escopos. SEM mudar comportamento. Lê → executa → escreve idênticamente antes/depois.
29
- - **Compilação verde após CADA commit.** Passo grande demais = você não está fazendo single-goal. Quebre menor.
30
- - **Não introduza tests "no meio" do refactor.** Refactor preserva comportamento → mesmo set de tests roda verde antes/durante/depois. Test novo significa novo comportamento (PR diferente).
31
- - **Pequenos testes em método extraído saem GRÁTIS.** Após extract method, o método extraído é menor, tipicamente puro. Test acumulado durante refactor incremental.
32
-
33
- ## Patterns canônicos
34
-
35
- ### Pattern 1: Bulleted vs Snarled — diagnóstico
36
-
37
- ```text
38
- BULLETED METHOD
39
- ===============
40
- public function processOrder(order) {
41
- validateOrder(order)
42
- computeTotals(order)
43
- applyDiscounts(order)
44
- saveOrder(order)
45
- notifyCustomer(order)
46
- publishEvent(order)
47
- updateAnalytics(order)
48
- returnReceipt(order)
49
- }
50
- ↑ 8 linhas, todas no mesmo nível. Cada linha é praticamente extract-method-ready.
51
-
52
- SNARLED METHOD
53
- ==============
54
- public function processOrder(order) {
55
- if (order != null) {
56
- if (order.items != null && order.items.length > 0) {
57
- var total = 0
58
- for (var item of order.items) {
59
- if (item.discount) {
60
- if (item.discount.type === 'percent') {
61
- total += item.price * (1 - item.discount.value / 100) * item.qty
62
- } else if (item.discount.type === 'fixed') {
63
- total += (item.price - item.discount.value) * item.qty
64
- } else {
65
- total += item.price * item.qty
66
- }
67
- } else {
68
- total += item.price * item.qty
69
- }
70
- }
71
- // ... mais 80 linhas com nesting similar
72
- }
73
- }
74
- }
75
- ↑ control flow profundamente aninhado. Extract method não é trivial — variáveis cruzam scopes.
76
- ```
77
-
78
- **Diagnóstico:**
79
- - Conte linhas no mesmo nível de indentação. Se > 70% das linhas estão no nível 1-2 → BULLETED.
80
- - Conte profundidade máxima de aninhamento. Se ≥ 5 → SNARLED.
81
-
82
- **Estratégias divergem** — abaixo.
83
-
84
- ### Pattern 2: Scratch refactoring (cap 22)
85
-
86
- Refactor descartável para ENTENDER o método antes de mudá-lo.
87
-
88
- ```text
89
- 1. Cria branch `scratch/<method-name>-explore`
90
- 2. Refatora à vontade — extract aleatório, rename especulativo,
91
- reformata estética. Goal: tornar legível para você.
92
- 3. Lê o resultado, entende o que método faz.
93
- 4. NÃO commita nem PR-a essa branch.
94
- 5. `git checkout main`. Volta ao código original intocado.
95
- 6. AGORA você tem mental model. Refatoração real começa com
96
- passos pequenos disciplinados (single-goal editing).
97
- ```
98
-
99
- **Por que descartável:** scratch é estética + quebra contracts. Manter seria perigoso. Só conhecimento adquirido vai para a real.
100
-
101
- **Quando vale o tempo:** método > 200 linhas + você nunca tinha mexido nele. < 100 linhas raramente vale (lê direto resolve).
102
-
103
- ### Pattern 3: Single-goal editing — atomic refactoring
104
-
105
- Cada commit faz UMA coisa. Disciplina absoluta.
106
-
107
- ```text
108
- ✓ COMMIT 1: rename method (mecânico, IDE-assisted)
109
- - Antes: processOrder
110
- - Depois: processOrderLegacy
111
- - Diff: rename refactor automático
112
-
113
- ✓ COMMIT 2: extract method (mecânico)
114
- - Antes: linhas 42-58 inline em processOrderLegacy
115
- - Depois: extracted como computeTotals(items)
116
- - Diff: 17 linhas → 1 chamada
117
-
118
- ✓ COMMIT 3: extract method (mecânico)
119
- - Antes: linhas 60-85 inline
120
- - Depois: extracted como applyDiscounts(items, discounts)
121
- - Diff: 26 linhas → 1 chamada
122
-
123
- ✗ COMMIT NÃO-FEITO: extract + rename + add validation
124
- Múltiplos goals num commit = no single-goal. Difícil revisar.
125
- ```
126
-
127
- **Princípio:** cada commit é REVERTIBLE individualmente. Se PR3 tem bug, revert PR3 só, não a sequência inteira.
128
-
129
- ### Pattern 4: Safe extraction em método sem testes
130
-
131
- Extract method preservando comportamento sem ter test que valide.
132
-
133
- ```text
134
- SAFE EXTRACTION CHECKLIST
135
- =========================
136
- □ Bloco a extrair é CONTÍGUO (sem control flow saindo do meio)
137
- □ Variáveis lidas dentro do bloco mas declaradas fora → parâmetros
138
- □ Variáveis ESCRITAS dentro do bloco mas usadas fora → return values
139
- □ Bloco não tem `return`, `throw`, `break`, `continue` que afete escopo externo
140
- (se tem: extract não é seguro, escolha menor)
141
- □ Type signatures preservadas (parâmetros e retorno bem-tipados)
142
- □ Comportamento idêntico — antes do extract: lê X, computa Y, escreve Z;
143
- depois: chama método extraído que lê X, computa Y, escreve Z
144
-
145
- PROCESSO MECÂNICO
146
- =================
147
- 1. Selecionar bloco contíguo (10-30 linhas tipicamente)
148
- 2. Identificar variáveis lidas vs escritas no bloco
149
- 3. Lidas-mas-não-escritas → parâmetros (in)
150
- 4. Escritas-mas-usadas-fora → adicionar a return value (out)
151
- 5. IDE: extract method (Cmd+Opt+M no IntelliJ; "Refactor: Extract Function" no VS Code)
152
- 6. Compilar — verde?
153
- 7. Run smoke (qualquer comando manual que rodava antes) — comportamento idêntico?
154
- 8. Commit. Próximo bloco.
155
- ```
156
-
157
- **Insight:** safe extraction é seguro mesmo SEM testes porque é PURELY MECHANICAL. IDE faz com 100% de fidelidade. Risco residual = bug do IDE (raríssimo) ou erro humano em copiar manualmente (não use cópia manual — use extract automation).
158
-
159
- ### Pattern 5: Domando bulleted method
160
-
161
- Bulleted é fácil. Workflow:
162
-
163
- ```text
164
- 1. Cada linha do método é uma "frase" → cada uma vira método extraído.
165
- Antes: processOrder() com 30 linhas no nível 1
166
- Depois: processOrder() com 8 chamadas, cada uma para um helper
167
-
168
- 2. Após extract, helpers são MENORES → tests acumulam grátis:
169
- public computeTotals(order) {
170
- // 8 linhas — testável isolado agora
171
- }
172
- public applyDiscounts(order, codes) {
173
- // 12 linhas — testável isolado agora
174
- }
175
-
176
- 3. Tests acumulados cobrem comportamento UNIT:
177
- test('computeTotals — com 1 item', () => { ... })
178
- test('computeTotals — com items vazios', () => { ... })
179
-
180
- 4. processOrder() agora é orquestração — test acaba sendo
181
- integration tipo:
182
- test('processOrder — happy path orchestration', () => {
183
- processOrder(typicalOrder)
184
- expect(saved).toBeDefined()
185
- expect(notifications).toHaveLength(1)
186
- })
187
-
188
- 5. Iterativamente, código vira pirâmide de tests bem definida.
189
- ```
190
-
191
- **Esforço típico:** método 100 linhas bulleted → 6-8 commits, 1-2 dias para refactor + 5-10 testes acumulados grátis.
192
-
193
- ### Pattern 6: Domando snarled method
194
-
195
- Snarled é difícil. Estratégia: APLAINAR primeiro, depois extrair.
196
-
197
- ```text
198
- PASSO 1 — Achatar via guard clauses (early return)
199
- Antes: Depois:
200
- if (order != null) { if (order == null) return ERROR
201
- if (order.items != null) { if (order.items == null) return ERROR
202
- if (order.items.length > 0) { if (order.items.length === 0) return EMPTY
203
- // 80 linhas // 80 linhas (agora sem nesting)
204
- }
205
- }
206
- }
207
- ↑ 3 níveis viraram 0 níveis. Pure mechanical. Sem mudança comportamental.
208
-
209
- PASSO 2 — Extract method em loop interno
210
- Antes: Depois:
211
- for (item of items) { for (item of items) {
212
- if (item.discount) { total += computeItemTotal(item)
213
- if (item.discount.type === 'percent') { ↑ 1 chamada
214
- total += item.price * (1 - ...) * item.qty
215
- } else if (...) {
216
- ...
217
- }
218
- } else {
219
- total += item.price * item.qty
220
- }
221
- }
222
-
223
- function computeItemTotal(item) {
224
- if (!item.discount) return item.price * item.qty
225
- if (item.discount.type === 'percent')
226
- return item.price * (1 - item.discount.value / 100) * item.qty
227
- if (item.discount.type === 'fixed')
228
- return (item.price - item.discount.value) * item.qty
229
- return item.price * item.qty
230
- }
231
- ↑ Loop de 12 linhas → 3 linhas + função pura testável.
232
-
233
- PASSO 3 — Iterar até nível máximo de aninhamento ≤ 2.
234
-
235
- PASSO 4 — Tests no método extraído (puro, fácil de testar):
236
- test('computeItemTotal — sem desconto', ...)
237
- test('computeItemTotal — desconto percentual', ...)
238
- test('computeItemTotal — desconto fixo', ...)
239
- test('computeItemTotal — discount.type desconhecido', ...)
240
- ```
241
-
242
- **Esforço típico:** método 150 linhas snarled → 12-20 commits, 3-7 dias para refactor + 15-25 testes acumulados.
243
-
244
- ### Pattern 7: Sequência canônica de tipos de single-goal commit
245
-
246
- Em ordem do mais SEGURO ao mais ARRISCADO. Faça nessa ordem.
247
-
248
- ```text
249
- SEGURO ↓
250
- ======================================================
251
- 1. RENAME (variable, method, class, file)
252
- IDE-assisted, mecânico, comportamento idêntico
253
-
254
- 2. SAFE EXTRACTION (extract method/variable)
255
- Selecione bloco contíguo, IDE extract, sem mover lógica entre scopes
256
-
257
- 3. MOVE METHOD (entre classes)
258
- Apenas se método não usa state da origem (puro relativo à classe)
259
-
260
- 4. INTRODUCE PARAMETER OBJECT
261
- Agrupar parâmetros relacionados em DTO. Mecânico.
262
-
263
- 5. INVERT DEPENDENCY (constructor injection)
264
- New X() interno → recebe X externo. Quebra encapsulation, mas
265
- comportamento permanece (se default-arg usado).
266
-
267
- 6. CHANGE METHOD SIGNATURE
268
- Adicionar/remover parâmetro. Risk: callers podem passar wrong.
269
-
270
- 7. ALGORITHM REPLACEMENT
271
- Mudar IMPLEMENTAÇÃO mantendo contrato. Risk médio — characterization
272
- tests obrigatórios.
273
-
274
- 8. CONTRACT CHANGE
275
- Mudar pre-condition/post-condition. Risk alto — todos os callers
276
- precisam ser inspecionados.
277
- ↑ ARRISCADO
278
- ======================================================
279
- ```
280
-
281
- Stop em #5 ou #6 para refactor "limpa-e-vai". #7 e #8 = mudança comportamental, exigem characterization completa.
282
-
283
- ### Pattern 8: Effort budget de monster method
284
-
285
- | Tamanho | Tipo | Esforço de refactor | Output esperado |
286
- |---|---|---|---|
287
- | 100-150 linhas, bulleted | extract methods + acumular tests | 1-2 dias | 5-10 helpers + 5-10 tests |
288
- | 100-150 linhas, snarled | flatten + extract | 3-5 dias | 5-10 helpers + 10-15 tests |
289
- | 150-300 linhas, bulleted | extract class após methods | 3-7 dias | 5-10 helpers + nova classe + 10-15 tests |
290
- | 150-300 linhas, snarled | scratch refactor + flatten + extract | 1-2 semanas | classe + 15-25 tests |
291
- | > 300 linhas | só com aprovação stakeholder, alocação dedicada | 2-4 semanas | reescrever via sprout class? |
292
-
293
- **Heurística:** método > 300 linhas raramente vale refactor incremental. Considere sprout class — encapsular comportamento NOVO em classe nova, deixar legado intocado, eventually deprecate.
294
-
295
- ### Pattern 9: Cobertura emergente
296
-
297
- Refactor de monster method NÃO precisa de characterization completa upfront se você usa safe extraction (mecânica). Mas teste se acumula:
298
-
299
- ```text
300
- PRE-REFACTOR (T0)
301
- Coverage: 0% (untested)
302
- Confiança: baixa
303
-
304
- DURANTE REFACTOR (T1-Tn)
305
- Cada extract method → método extraído fica testável (puro/menor)
306
- Adicione 1-3 unit tests do extracted antes de seguir
307
- Coverage cresce 5-10% por extract
308
-
309
- PÓS-REFACTOR (Tfinal)
310
- Original 100 linhas → 1 método orquestrador + 8 helpers
311
- Cobertura: 60-80% (helpers cobertos; orquestrador integration)
312
- Confiança: alta
313
- ```
314
-
315
- **Sem essa disciplina:** refactor termina, código mais limpo, mas cobertura ainda 0%. Próxima mudança volta ao mesmo dilema.
316
-
317
- ## Anti-patterns
318
-
319
- ### ANTI: refactor monstro em 1 PR
320
-
321
- ```text
322
- ANTI: PR de 1500 linhas — extracted 12 methods + renamed 8 variables
323
- + moved 3 fields + fixed 2 bugs + adicionou 25 tests.
324
-
325
- PROBLEMA: PR não-revisável. Reviewer aprova "no fé". CI verde diz
326
- pouco — branch coverage caiu. Revert é all-or-nothing.
327
-
328
- CERTO: 12-25 commits/PRs em sequência. Cada um single-goal,
329
- ≤ 100 linhas, mecânico, revertível, com proof of correctness
330
- (compila + roda).
331
- ```
332
-
333
- ### ANTI: misturar refactor + bug fix + feature
334
-
335
- ```text
336
- ANTI: enquanto refatora, "ah esse if pode ser melhor", "esse loop
337
- podia usar reduce", "ah aqui tem um bug, conserto".
338
-
339
- PROBLEMA: você quebrou single-goal em ~5 lugares. Reviewer não consegue
340
- identificar o que é refactor (preserva) vs bug fix (muda).
341
- Se algo quebra, bisect aponta para PR mas não isola causa.
342
-
343
- CERTO: anote bugs encontrados num arquivo `BUGS-FOUND.md`. Não
344
- conserte agora. Após refactor terminar, faz PRs separados
345
- para cada fix com test do comportamento correto.
346
- ```
347
-
348
- ### ANTI: extract method + mover lógica
349
-
350
- ```text
351
- ANTI: extract method, mas durante extraction "noto" que lógica é
352
- melhor em outro escopo, então move pra lá durante o extract.
353
-
354
- PROBLEMA: comportamento mudou. Não é mais SAFE extraction. Você
355
- precisava de characterization mas pulou.
356
-
357
- CERTO: 2 PRs sequenciais.
358
- PR1 — extract method (idêntico, no mesmo escopo)
359
- PR2 — move method (com test que valida em ambos os contextos)
360
- ```
361
-
362
- ### ANTI: scratch refactoring committed
363
-
364
- ```text
365
- ANTI: scratch ficou bom, mantenho-o em PR.
366
-
367
- PROBLEMA: scratch fez mudanças não-mecânicas (estéticas, especulativas).
368
- Sem characterization, não há prova de comportamento idêntico.
369
- Você acabou de fazer "edit and pray" disfarçado de refactor.
370
-
371
- CERTO: scratch é descartável. SEMPRE. Real refactor recomeça do
372
- código original com passos disciplinados.
373
- ```
374
-
375
- ### ANTI: extract APENAS para mais legibilidade, sem reduzir tamanho
376
-
377
- ```text
378
- ANTI: extract de 1 linha para método com nome descritivo "para ficar
379
- mais claro". Original tinha 200 linhas, agora tem 195 + 1 linha
380
- em método novo.
381
-
382
- PROBLEMA: 5 minutos para reviewer entender a chamada extra. Tamanho
383
- do monster diminuiu 1%. Trade desfavorável.
384
-
385
- CERTO: extract de 10-30 linhas mínimo. Bloco coeso e separável,
386
- não single statement. Linha solta com nome longo é
387
- refactoring teatral.
388
- ```
389
-
390
- ### ANTI: tentar testar tudo upfront
391
-
392
- ```text
393
- ANTI: "vou characterize completo das 200 linhas em todos os 30
394
- inputs antes de tocar uma vírgula".
395
-
396
- PROBLEMA: 200 linhas com 30 inputs = 1-2 semanas de characterization.
397
- Stakeholder cancela. Refactor nunca acontece. Status quo
398
- eterno.
399
-
400
- CERTO: characterization MÍNIMA viável (5-10 inputs nos pontos óbvios).
401
- Refactor mecânico (safe extraction, rename) que PRESERVA
402
- comportamento. Acumula testes em helpers extraídos. Cobertura
403
- emerge organicamente.
404
- ```
405
-
406
- ## Verificação
407
-
408
- Antes de declarar refactor de monster method completo:
409
-
410
- 1. **Tipo identificado** — bulleted vs snarled
411
- 2. **Tamanho original < 100 linhas após refactor** — se ainda > 100, refactor não terminou
412
- 3. **Cada commit é single-goal** — rename OR extract OR move, nunca múltiplos
413
- 4. **Compilação verde a cada commit** — passos pequenos, mecânicos
414
- 5. **Smoke run após cada commit** — comportamento preservado
415
- 6. **Tests acumulados nos helpers extraídos** — coverage cresceu de 0% para ≥ 50%
416
- 7. **Bugs encontrados anotados, NÃO consertados durante refactor** — fix em PRs separados
417
- 8. **Sem scratch committed** — só conhecimento adquirido viajou
418
-
419
- ## Limiar de "pronto para feature change pós-refactor"
420
-
421
- ```text
422
- Linhas do método principal: ≤ 100 (idealmente ≤ 50)
423
- Profundidade máxima de aninhamento: ≤ 3
424
- Helpers extraídos: 5-15 (cada ≤ 30 linhas)
425
- Coverage do método principal: ≥ 50%
426
- Coverage dos helpers: ≥ 70%
427
- Bugs encontrados: anotados em BUGS-FOUND.md
428
- PRs: cada single-goal, ≤ 100 linhas, revertíveis
429
- ```
430
-
431
- Atingidos? Agora a feature change pode acontecer com confiança normal de TDD.
432
-
433
- ---
434
-
435
- ## Ver também
436
-
437
- - [`_shared-legacy/glossary.md`](../_shared-legacy/glossary.md) — vocabulário (monster method, bulleted vs snarled, scratch, single-goal, safe extraction)
438
- - [`legacy-characterization-tests`](../legacy-characterization-tests/SKILL.md) — para mudanças COMPORTAMENTAIS, characterization é obrigatório (não basta safe extraction)
439
- - [`legacy-seams-and-test-harness`](../legacy-seams-and-test-harness/SKILL.md) — break-deps é pré-requisito quando helpers extraídos têm I/O
440
- - [`legacy-effect-analysis`](../legacy-effect-analysis/SKILL.md) — sketch dentro do monster ajuda a escolher onde extrair
441
- - [`legacy-sprout-wrap-techniques`](../legacy-sprout-wrap-techniques/SKILL.md) — quando monster > 300 linhas, sprout class para novo comportamento sem refatorar
442
- - [`pre-refactor-characterization`](../pre-refactor-characterization/SKILL.md) — gate distingue safe extraction (livre) de behavioral change (requer characterization)
443
-
444
- *Material-fonte: Working Effectively with Legacy Code — Feathers, 2004 — Cap 22: "I Need to Change a Monster Method and I Can't Write Tests for It".*
1
+ ---
2
+ name: legacy-monster-methods
3
+ description: Use ao refatorar método > 100 linhas sem testes — scratch refactoring, single-goal editing, safe extraction (cap 22 Feathers). Padrões para domesticar bulleted vs snarled methods.
4
+ ---
5
+
6
+ # Legacy — Monster Methods
7
+
8
+ ## Quando usar
9
+
10
+ LLM carrega esta skill quando o user encontra método absurdamente longo (> 100 linhas) que precisa ser modificado. Trigger phrases:
11
+
12
+ - "esse método tem [N] linhas, preciso mudar"
13
+ - "monster method", "método monstro", "método gigante"
14
+ - "scratch refactoring", "refactor de rascunho"
15
+ - "single-goal editing", "edição com objetivo único"
16
+ - "extract method em método sem testes"
17
+ - "cap 22 Feathers"
18
+ - "bulleted method", "snarled method"
19
+
20
+ Carrega quando `legacy-characterization-tests` é insuficiente isoladamente — método é grande demais para enumerar inputs, mas precisa ser refatorado para ficar testável.
21
+
22
+ ## Regras absolutas
23
+
24
+ - **Monster method = > 100 linhas OU > 5 níveis de aninhamento.** Pelo menos 1 dos dois. Heurística empírica do livro.
25
+ - **Distinguir bulleted vs snarled.** Bulleted = linhas longas mas planas (mais fácil). Snarled = nesting profundo, control flow complexo (mais difícil). Estratégias diferentes.
26
+ - **Scratch refactoring é DESCARTÁVEL.** Branch lixo, refactor estético para entender, depois `git checkout main` e descarte tudo. Só conhecimento adquirido viaja para a refatoração real.
27
+ - **Single-goal editing.** UMA mudança por commit/PR. Renomear OR extrair OR mover, NUNCA os 3 juntos. Cada commit é mecânico, isolado, revisável.
28
+ - **Extract method em monster sem teste = SAFE EXTRACTION.** Apenas levantar bloco contíguo + capturar variáveis usadas como parâmetros. SEM mover lógica entre escopos. SEM mudar comportamento. Lê → executa → escreve idênticamente antes/depois.
29
+ - **Compilação verde após CADA commit.** Passo grande demais = você não está fazendo single-goal. Quebre menor.
30
+ - **Não introduza tests "no meio" do refactor.** Refactor preserva comportamento → mesmo set de tests roda verde antes/durante/depois. Test novo significa novo comportamento (PR diferente).
31
+ - **Pequenos testes em método extraído saem GRÁTIS.** Após extract method, o método extraído é menor, tipicamente puro. Test acumulado durante refactor incremental.
32
+
33
+ ## Patterns canônicos
34
+
35
+ ### Pattern 1: Bulleted vs Snarled — diagnóstico
36
+
37
+ ```text
38
+ BULLETED METHOD
39
+ ===============
40
+ public function processOrder(order) {
41
+ validateOrder(order)
42
+ computeTotals(order)
43
+ applyDiscounts(order)
44
+ saveOrder(order)
45
+ notifyCustomer(order)
46
+ publishEvent(order)
47
+ updateAnalytics(order)
48
+ returnReceipt(order)
49
+ }
50
+ ↑ 8 linhas, todas no mesmo nível. Cada linha é praticamente extract-method-ready.
51
+
52
+ SNARLED METHOD
53
+ ==============
54
+ public function processOrder(order) {
55
+ if (order != null) {
56
+ if (order.items != null && order.items.length > 0) {
57
+ var total = 0
58
+ for (var item of order.items) {
59
+ if (item.discount) {
60
+ if (item.discount.type === 'percent') {
61
+ total += item.price * (1 - item.discount.value / 100) * item.qty
62
+ } else if (item.discount.type === 'fixed') {
63
+ total += (item.price - item.discount.value) * item.qty
64
+ } else {
65
+ total += item.price * item.qty
66
+ }
67
+ } else {
68
+ total += item.price * item.qty
69
+ }
70
+ }
71
+ // ... mais 80 linhas com nesting similar
72
+ }
73
+ }
74
+ }
75
+ ↑ control flow profundamente aninhado. Extract method não é trivial — variáveis cruzam scopes.
76
+ ```
77
+
78
+ **Diagnóstico:**
79
+ - Conte linhas no mesmo nível de indentação. Se > 70% das linhas estão no nível 1-2 → BULLETED.
80
+ - Conte profundidade máxima de aninhamento. Se ≥ 5 → SNARLED.
81
+
82
+ **Estratégias divergem** — abaixo.
83
+
84
+ ### Pattern 2: Scratch refactoring (cap 22)
85
+
86
+ Refactor descartável para ENTENDER o método antes de mudá-lo.
87
+
88
+ ```text
89
+ 1. Cria branch `scratch/<method-name>-explore`
90
+ 2. Refatora à vontade — extract aleatório, rename especulativo,
91
+ reformata estética. Goal: tornar legível para você.
92
+ 3. Lê o resultado, entende o que método faz.
93
+ 4. NÃO commita nem PR-a essa branch.
94
+ 5. `git checkout main`. Volta ao código original intocado.
95
+ 6. AGORA você tem mental model. Refatoração real começa com
96
+ passos pequenos disciplinados (single-goal editing).
97
+ ```
98
+
99
+ **Por que descartável:** scratch é estética + quebra contracts. Manter seria perigoso. Só conhecimento adquirido vai para a real.
100
+
101
+ **Quando vale o tempo:** método > 200 linhas + você nunca tinha mexido nele. < 100 linhas raramente vale (lê direto resolve).
102
+
103
+ ### Pattern 3: Single-goal editing — atomic refactoring
104
+
105
+ Cada commit faz UMA coisa. Disciplina absoluta.
106
+
107
+ ```text
108
+ ✓ COMMIT 1: rename method (mecânico, IDE-assisted)
109
+ - Antes: processOrder
110
+ - Depois: processOrderLegacy
111
+ - Diff: rename refactor automático
112
+
113
+ ✓ COMMIT 2: extract method (mecânico)
114
+ - Antes: linhas 42-58 inline em processOrderLegacy
115
+ - Depois: extracted como computeTotals(items)
116
+ - Diff: 17 linhas → 1 chamada
117
+
118
+ ✓ COMMIT 3: extract method (mecânico)
119
+ - Antes: linhas 60-85 inline
120
+ - Depois: extracted como applyDiscounts(items, discounts)
121
+ - Diff: 26 linhas → 1 chamada
122
+
123
+ ✗ COMMIT NÃO-FEITO: extract + rename + add validation
124
+ Múltiplos goals num commit = no single-goal. Difícil revisar.
125
+ ```
126
+
127
+ **Princípio:** cada commit é REVERTIBLE individualmente. Se PR3 tem bug, revert PR3 só, não a sequência inteira.
128
+
129
+ ### Pattern 4: Safe extraction em método sem testes
130
+
131
+ Extract method preservando comportamento sem ter test que valide.
132
+
133
+ ```text
134
+ SAFE EXTRACTION CHECKLIST
135
+ =========================
136
+ □ Bloco a extrair é CONTÍGUO (sem control flow saindo do meio)
137
+ □ Variáveis lidas dentro do bloco mas declaradas fora → parâmetros
138
+ □ Variáveis ESCRITAS dentro do bloco mas usadas fora → return values
139
+ □ Bloco não tem `return`, `throw`, `break`, `continue` que afete escopo externo
140
+ (se tem: extract não é seguro, escolha menor)
141
+ □ Type signatures preservadas (parâmetros e retorno bem-tipados)
142
+ □ Comportamento idêntico — antes do extract: lê X, computa Y, escreve Z;
143
+ depois: chama método extraído que lê X, computa Y, escreve Z
144
+
145
+ PROCESSO MECÂNICO
146
+ =================
147
+ 1. Selecionar bloco contíguo (10-30 linhas tipicamente)
148
+ 2. Identificar variáveis lidas vs escritas no bloco
149
+ 3. Lidas-mas-não-escritas → parâmetros (in)
150
+ 4. Escritas-mas-usadas-fora → adicionar a return value (out)
151
+ 5. IDE: extract method (Cmd+Opt+M no IntelliJ; "Refactor: Extract Function" no VS Code)
152
+ 6. Compilar — verde?
153
+ 7. Run smoke (qualquer comando manual que rodava antes) — comportamento idêntico?
154
+ 8. Commit. Próximo bloco.
155
+ ```
156
+
157
+ **Insight:** safe extraction é seguro mesmo SEM testes porque é PURELY MECHANICAL. IDE faz com 100% de fidelidade. Risco residual = bug do IDE (raríssimo) ou erro humano em copiar manualmente (não use cópia manual — use extract automation).
158
+
159
+ ### Pattern 5: Domando bulleted method
160
+
161
+ Bulleted é fácil. Workflow:
162
+
163
+ ```text
164
+ 1. Cada linha do método é uma "frase" → cada uma vira método extraído.
165
+ Antes: processOrder() com 30 linhas no nível 1
166
+ Depois: processOrder() com 8 chamadas, cada uma para um helper
167
+
168
+ 2. Após extract, helpers são MENORES → tests acumulam grátis:
169
+ public computeTotals(order) {
170
+ // 8 linhas — testável isolado agora
171
+ }
172
+ public applyDiscounts(order, codes) {
173
+ // 12 linhas — testável isolado agora
174
+ }
175
+
176
+ 3. Tests acumulados cobrem comportamento UNIT:
177
+ test('computeTotals — com 1 item', () => { ... })
178
+ test('computeTotals — com items vazios', () => { ... })
179
+
180
+ 4. processOrder() agora é orquestração — test acaba sendo
181
+ integration tipo:
182
+ test('processOrder — happy path orchestration', () => {
183
+ processOrder(typicalOrder)
184
+ expect(saved).toBeDefined()
185
+ expect(notifications).toHaveLength(1)
186
+ })
187
+
188
+ 5. Iterativamente, código vira pirâmide de tests bem definida.
189
+ ```
190
+
191
+ **Esforço típico:** método 100 linhas bulleted → 6-8 commits, 1-2 dias para refactor + 5-10 testes acumulados grátis.
192
+
193
+ ### Pattern 6: Domando snarled method
194
+
195
+ Snarled é difícil. Estratégia: APLAINAR primeiro, depois extrair.
196
+
197
+ ```text
198
+ PASSO 1 — Achatar via guard clauses (early return)
199
+ Antes: Depois:
200
+ if (order != null) { if (order == null) return ERROR
201
+ if (order.items != null) { if (order.items == null) return ERROR
202
+ if (order.items.length > 0) { if (order.items.length === 0) return EMPTY
203
+ // 80 linhas // 80 linhas (agora sem nesting)
204
+ }
205
+ }
206
+ }
207
+ ↑ 3 níveis viraram 0 níveis. Pure mechanical. Sem mudança comportamental.
208
+
209
+ PASSO 2 — Extract method em loop interno
210
+ Antes: Depois:
211
+ for (item of items) { for (item of items) {
212
+ if (item.discount) { total += computeItemTotal(item)
213
+ if (item.discount.type === 'percent') { ↑ 1 chamada
214
+ total += item.price * (1 - ...) * item.qty
215
+ } else if (...) {
216
+ ...
217
+ }
218
+ } else {
219
+ total += item.price * item.qty
220
+ }
221
+ }
222
+
223
+ function computeItemTotal(item) {
224
+ if (!item.discount) return item.price * item.qty
225
+ if (item.discount.type === 'percent')
226
+ return item.price * (1 - item.discount.value / 100) * item.qty
227
+ if (item.discount.type === 'fixed')
228
+ return (item.price - item.discount.value) * item.qty
229
+ return item.price * item.qty
230
+ }
231
+ ↑ Loop de 12 linhas → 3 linhas + função pura testável.
232
+
233
+ PASSO 3 — Iterar até nível máximo de aninhamento ≤ 2.
234
+
235
+ PASSO 4 — Tests no método extraído (puro, fácil de testar):
236
+ test('computeItemTotal — sem desconto', ...)
237
+ test('computeItemTotal — desconto percentual', ...)
238
+ test('computeItemTotal — desconto fixo', ...)
239
+ test('computeItemTotal — discount.type desconhecido', ...)
240
+ ```
241
+
242
+ **Esforço típico:** método 150 linhas snarled → 12-20 commits, 3-7 dias para refactor + 15-25 testes acumulados.
243
+
244
+ ### Pattern 7: Sequência canônica de tipos de single-goal commit
245
+
246
+ Em ordem do mais SEGURO ao mais ARRISCADO. Faça nessa ordem.
247
+
248
+ ```text
249
+ SEGURO ↓
250
+ ======================================================
251
+ 1. RENAME (variable, method, class, file)
252
+ IDE-assisted, mecânico, comportamento idêntico
253
+
254
+ 2. SAFE EXTRACTION (extract method/variable)
255
+ Selecione bloco contíguo, IDE extract, sem mover lógica entre scopes
256
+
257
+ 3. MOVE METHOD (entre classes)
258
+ Apenas se método não usa state da origem (puro relativo à classe)
259
+
260
+ 4. INTRODUCE PARAMETER OBJECT
261
+ Agrupar parâmetros relacionados em DTO. Mecânico.
262
+
263
+ 5. INVERT DEPENDENCY (constructor injection)
264
+ New X() interno → recebe X externo. Quebra encapsulation, mas
265
+ comportamento permanece (se default-arg usado).
266
+
267
+ 6. CHANGE METHOD SIGNATURE
268
+ Adicionar/remover parâmetro. Risk: callers podem passar wrong.
269
+
270
+ 7. ALGORITHM REPLACEMENT
271
+ Mudar IMPLEMENTAÇÃO mantendo contrato. Risk médio — characterization
272
+ tests obrigatórios.
273
+
274
+ 8. CONTRACT CHANGE
275
+ Mudar pre-condition/post-condition. Risk alto — todos os callers
276
+ precisam ser inspecionados.
277
+ ↑ ARRISCADO
278
+ ======================================================
279
+ ```
280
+
281
+ Stop em #5 ou #6 para refactor "limpa-e-vai". #7 e #8 = mudança comportamental, exigem characterization completa.
282
+
283
+ ### Pattern 8: Effort budget de monster method
284
+
285
+ | Tamanho | Tipo | Esforço de refactor | Output esperado |
286
+ |---|---|---|---|
287
+ | 100-150 linhas, bulleted | extract methods + acumular tests | 1-2 dias | 5-10 helpers + 5-10 tests |
288
+ | 100-150 linhas, snarled | flatten + extract | 3-5 dias | 5-10 helpers + 10-15 tests |
289
+ | 150-300 linhas, bulleted | extract class após methods | 3-7 dias | 5-10 helpers + nova classe + 10-15 tests |
290
+ | 150-300 linhas, snarled | scratch refactor + flatten + extract | 1-2 semanas | classe + 15-25 tests |
291
+ | > 300 linhas | só com aprovação stakeholder, alocação dedicada | 2-4 semanas | reescrever via sprout class? |
292
+
293
+ **Heurística:** método > 300 linhas raramente vale refactor incremental. Considere sprout class — encapsular comportamento NOVO em classe nova, deixar legado intocado, eventually deprecate.
294
+
295
+ ### Pattern 9: Cobertura emergente
296
+
297
+ Refactor de monster method NÃO precisa de characterization completa upfront se você usa safe extraction (mecânica). Mas teste se acumula:
298
+
299
+ ```text
300
+ PRE-REFACTOR (T0)
301
+ Coverage: 0% (untested)
302
+ Confiança: baixa
303
+
304
+ DURANTE REFACTOR (T1-Tn)
305
+ Cada extract method → método extraído fica testável (puro/menor)
306
+ Adicione 1-3 unit tests do extracted antes de seguir
307
+ Coverage cresce 5-10% por extract
308
+
309
+ PÓS-REFACTOR (Tfinal)
310
+ Original 100 linhas → 1 método orquestrador + 8 helpers
311
+ Cobertura: 60-80% (helpers cobertos; orquestrador integration)
312
+ Confiança: alta
313
+ ```
314
+
315
+ **Sem essa disciplina:** refactor termina, código mais limpo, mas cobertura ainda 0%. Próxima mudança volta ao mesmo dilema.
316
+
317
+ ## Anti-patterns
318
+
319
+ ### ANTI: refactor monstro em 1 PR
320
+
321
+ ```text
322
+ ANTI: PR de 1500 linhas — extracted 12 methods + renamed 8 variables
323
+ + moved 3 fields + fixed 2 bugs + adicionou 25 tests.
324
+
325
+ PROBLEMA: PR não-revisável. Reviewer aprova "no fé". CI verde diz
326
+ pouco — branch coverage caiu. Revert é all-or-nothing.
327
+
328
+ CERTO: 12-25 commits/PRs em sequência. Cada um single-goal,
329
+ ≤ 100 linhas, mecânico, revertível, com proof of correctness
330
+ (compila + roda).
331
+ ```
332
+
333
+ ### ANTI: misturar refactor + bug fix + feature
334
+
335
+ ```text
336
+ ANTI: enquanto refatora, "ah esse if pode ser melhor", "esse loop
337
+ podia usar reduce", "ah aqui tem um bug, conserto".
338
+
339
+ PROBLEMA: você quebrou single-goal em ~5 lugares. Reviewer não consegue
340
+ identificar o que é refactor (preserva) vs bug fix (muda).
341
+ Se algo quebra, bisect aponta para PR mas não isola causa.
342
+
343
+ CERTO: anote bugs encontrados num arquivo `BUGS-FOUND.md`. Não
344
+ conserte agora. Após refactor terminar, faz PRs separados
345
+ para cada fix com test do comportamento correto.
346
+ ```
347
+
348
+ ### ANTI: extract method + mover lógica
349
+
350
+ ```text
351
+ ANTI: extract method, mas durante extraction "noto" que lógica é
352
+ melhor em outro escopo, então move pra lá durante o extract.
353
+
354
+ PROBLEMA: comportamento mudou. Não é mais SAFE extraction. Você
355
+ precisava de characterization mas pulou.
356
+
357
+ CERTO: 2 PRs sequenciais.
358
+ PR1 — extract method (idêntico, no mesmo escopo)
359
+ PR2 — move method (com test que valida em ambos os contextos)
360
+ ```
361
+
362
+ ### ANTI: scratch refactoring committed
363
+
364
+ ```text
365
+ ANTI: scratch ficou bom, mantenho-o em PR.
366
+
367
+ PROBLEMA: scratch fez mudanças não-mecânicas (estéticas, especulativas).
368
+ Sem characterization, não há prova de comportamento idêntico.
369
+ Você acabou de fazer "edit and pray" disfarçado de refactor.
370
+
371
+ CERTO: scratch é descartável. SEMPRE. Real refactor recomeça do
372
+ código original com passos disciplinados.
373
+ ```
374
+
375
+ ### ANTI: extract APENAS para mais legibilidade, sem reduzir tamanho
376
+
377
+ ```text
378
+ ANTI: extract de 1 linha para método com nome descritivo "para ficar
379
+ mais claro". Original tinha 200 linhas, agora tem 195 + 1 linha
380
+ em método novo.
381
+
382
+ PROBLEMA: 5 minutos para reviewer entender a chamada extra. Tamanho
383
+ do monster diminuiu 1%. Trade desfavorável.
384
+
385
+ CERTO: extract de 10-30 linhas mínimo. Bloco coeso e separável,
386
+ não single statement. Linha solta com nome longo é
387
+ refactoring teatral.
388
+ ```
389
+
390
+ ### ANTI: tentar testar tudo upfront
391
+
392
+ ```text
393
+ ANTI: "vou characterize completo das 200 linhas em todos os 30
394
+ inputs antes de tocar uma vírgula".
395
+
396
+ PROBLEMA: 200 linhas com 30 inputs = 1-2 semanas de characterization.
397
+ Stakeholder cancela. Refactor nunca acontece. Status quo
398
+ eterno.
399
+
400
+ CERTO: characterization MÍNIMA viável (5-10 inputs nos pontos óbvios).
401
+ Refactor mecânico (safe extraction, rename) que PRESERVA
402
+ comportamento. Acumula testes em helpers extraídos. Cobertura
403
+ emerge organicamente.
404
+ ```
405
+
406
+ ## Verificação
407
+
408
+ Antes de declarar refactor de monster method completo:
409
+
410
+ 1. **Tipo identificado** — bulleted vs snarled
411
+ 2. **Tamanho original < 100 linhas após refactor** — se ainda > 100, refactor não terminou
412
+ 3. **Cada commit é single-goal** — rename OR extract OR move, nunca múltiplos
413
+ 4. **Compilação verde a cada commit** — passos pequenos, mecânicos
414
+ 5. **Smoke run após cada commit** — comportamento preservado
415
+ 6. **Tests acumulados nos helpers extraídos** — coverage cresceu de 0% para ≥ 50%
416
+ 7. **Bugs encontrados anotados, NÃO consertados durante refactor** — fix em PRs separados
417
+ 8. **Sem scratch committed** — só conhecimento adquirido viajou
418
+
419
+ ## Limiar de "pronto para feature change pós-refactor"
420
+
421
+ ```text
422
+ Linhas do método principal: ≤ 100 (idealmente ≤ 50)
423
+ Profundidade máxima de aninhamento: ≤ 3
424
+ Helpers extraídos: 5-15 (cada ≤ 30 linhas)
425
+ Coverage do método principal: ≥ 50%
426
+ Coverage dos helpers: ≥ 70%
427
+ Bugs encontrados: anotados em BUGS-FOUND.md
428
+ PRs: cada single-goal, ≤ 100 linhas, revertíveis
429
+ ```
430
+
431
+ Atingidos? Agora a feature change pode acontecer com confiança normal de TDD.
432
+
433
+ ---
434
+
435
+ ## Ver também
436
+
437
+ - [`_shared-legacy/glossary.md`](../_shared-legacy/glossary.md) — vocabulário (monster method, bulleted vs snarled, scratch, single-goal, safe extraction)
438
+ - [`legacy-characterization-tests`](../legacy-characterization-tests/SKILL.md) — para mudanças COMPORTAMENTAIS, characterization é obrigatório (não basta safe extraction)
439
+ - [`legacy-seams-and-test-harness`](../legacy-seams-and-test-harness/SKILL.md) — break-deps é pré-requisito quando helpers extraídos têm I/O
440
+ - [`legacy-effect-analysis`](../legacy-effect-analysis/SKILL.md) — sketch dentro do monster ajuda a escolher onde extrair
441
+ - [`legacy-sprout-wrap-techniques`](../legacy-sprout-wrap-techniques/SKILL.md) — quando monster > 300 linhas, sprout class para novo comportamento sem refatorar
442
+ - [`pre-refactor-characterization`](../pre-refactor-characterization/SKILL.md) — gate distingue safe extraction (livre) de behavioral change (requer characterization)
443
+
444
+ *Material-fonte: Working Effectively with Legacy Code — Feathers, 2004 — Cap 22: "I Need to Change a Monster Method and I Can't Write Tests for It".*