Nomear Não é Encontrar
Você agora conhece sete padrões MOAD. Saber nomes é importante: permite reconhecer um padrão quando você o vê. Mas o reconhecimento em uma lição controlada é diferente da detecção em uma base de código que você nunca abriu.
Uma base de código não rotula seus defeitos. Um MOAD sedimentar não vem com um comentário que diz // O(N²) — corrigir isto. Um rebanho trovejante não se anuncia como um cache miss stampede. Você os encontra lendo código com uma pergunta específica em mente: que estrutura de dados mantém esses valores, & que operações executam contra ela dentro de um loop?
A detecção é uma habilidade separada do reconhecimento. O reconhecimento diz: sim, esse padrão é MOAD-0001. A detecção diz: deixe-me encontrar todos os lugares nesta base de código onde esse padrão pode existir, se eu posso ver o código completo ou apenas um nome de símbolo.
Primeira Varredura
Uma primeira passagem usa grep. Cada MOAD tem um substrato: uma estrutura de dados ou API cuja presença, perto de certas operações, é um sinal que vale a pena investigar.
MOAD-0001 (Sedimentário): List.contains em um loop
# Signal: membership test on a list variable inside a loop
grep -rn '.contains(' src/ | grep -v HashSet | grep -v TreeSet
grep -rn 'visited =' src/ | grep -v set | grep -v Set
MOAD-0002 (Intertangle): bandeira mutável compartilhada entre fases
# Signal: static mutable field written by one subsystem, read by another
grep -rn 'static ' src/ | grep -v final | grep -v class | grep -v void
MOAD-0003 (Leaked Context): ThreadLocal em um executor em pool
# Signal: ThreadLocal.set() without guaranteed ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l
MOAD-0004 (Logged Secret): cabeçalhos HTTP na saída de log
# Signal: log call with headers variable near auth endpoints
grep -rn 'log.*header' src/
grep -rn 'Authorization' src/ --include='*.log'
MOAD-0005 (Thundering Herd): cache miss sem sincronização
# Signal: cache.get() + null check + cache.put() without lock
grep -rn 'cache.get' src/ -A4 | grep 'cache.put'
Esses padrões produzem candidatos, não defeitos confirmados. Cada candidato precisa de triagem: leia o código circundante, verifique o tipo de estrutura de dados, confirme que a operação é executada em escala.
Lendo Código para Complexidade
Grep encontra candidatos. A leitura os confirma. Quando você abre um arquivo candidato, você lê com uma pergunta: o custo desta operação cresce com o tamanho da entrada?
Para MOAD-0001, o protocolo de confirmação:
1. Find the outer loop. What bounds its iteration count?
2. Find the inner operation (.contains, .indexOf, 'in'). What data structure does it run against?
3. Does that data structure grow with the same input that drives the outer loop?
4. If yes: the cost is O(N²) where N = input size. Confirmed defect.
5. If no: the inner structure is bounded (config, enum, small constant). False positive.
Um grafo que visita N nós, verificando uma lista visited em cada passo: tanto o loop quanto a estrutura de dados interna crescem com N. Confirmado.
Um manipulador de requisições verificando uma lista de permissões de 5 IPs de administrador: a lista de permissões nunca cresce com o volume de requisições. Falso positivo.
O mesmo protocolo se aplica a cada MOAD: identifique o driver externo, identifique a estrutura interna, pergunte-se se ambos escalam juntos.
Surge Score: Priorizando Suas Descobertas
Nem todos os defeitos confirmados garantem correção imediata. Um MOAD em uma biblioteca com 10.000 dependentes downstream tem uma pontuação de surge maior do que o mesmo MOAD em uma ferramenta interna privada.
Surge score = speedup × in-degree. Speedup: quanto mais rápido a correção é executada em escala típica de produção? In-degree: quantos pacotes ou serviços downstream herdariam a correção automaticamente quando o upstream os mesclar?
Um MOAD-0001 confirmado no dependency resolver do Apache Maven, executado em grafos de 50.000 nós, com 1.000+ plugins Maven downstream que herdam alterações automaticamente: surge score é muito alto. Esta correção pertence à frente de sua fila.
Um MOAD-0001 confirmado em uma ferramenta CLI de usuário único sem dependentes: surge score próximo a zero. Vale a pena corrigir, mas não urgente.
Workaholic vs. nós glutão. Um nó com alta betweenness & alta speedup é um workaholic: ele lida com fluxo crítico & varrará filas downstream quando desbloqueado. Corrija-o apenas depois de confirmar a capacidade downstream. Um nó com alta out-degree & baixa speedup é um glutão: consome tudo o que é alimentado & não sente dor. Corrigir um workaholic sem preparar capacidade downstream cria MOAD-0005 (thundering herd) em escala de infraestrutura.
Escanear para Mesclar: Um Pipeline MOAD
Um defeito confirmado com uma pontuação de surge alta passa por um pipeline. Cada etapa produz um artefato. Nenhuma etapa é opcional.
scan → candidate list (grep output, static analysis results)
ticket → defect description (MOAD number, location, complexity analysis)
patch → code change (data structure swap, primitive adoption)
test → unit test (O(1) proof: time the fix at N=100 and N=10,000)
UNDF → public disclosure post (undefect.com, public domain)
disclose → CVE or CWE reference if security-relevant
PR → upstream pull request with patch + test + UNDF link
merge → maintainer acceptance; fix propagates via version bump
Cada artefato alimenta a próxima etapa. Um patch sem teste não pode ser verificado. Um teste sem divulgação não pode se propagar para outras instâncias do mesmo padrão. Uma divulgação sem um PR upstream prende a correção em um fork.
Um post MOAD (UNDF) é a etapa que a maioria dos engenheiros omite. Eles corrigem o defeito, enviam um PR, e se consideram prontos. Mas uma correção sem um post nomeado significa que todo engenheiro futuro que encontrar o mesmo padrão deve redescobrir tanto o problema quanto a correção independentemente. Um post MOAD fecha o loop do conhecimento: ele nomeia o padrão, mostra o método de detecção, & vincula ao patch. Pesquisadores futuros encontram a correção pesquisando o nome do padrão.
Planet patching em escala. Uma única correção MOAD-0001 em uma biblioteca amplamente usada se propaga para cada projeto que a importa. Um post MOAD garante que engenheiros em projetos que nunca atualizarão essa biblioteca ainda aprendam a correção. Ambos os caminhos funcionam em paralelo.
Escrevendo um Tíquete de Defeito
Um bom tíquete de defeito responde cinco perguntas:
1. Where: exact file, class, function, and line range
2. What: the data structure type and the operation against it
3. Why: the complexity analysis (O(N²) or worse, with N defined)
4. Impact: what inputs trigger worst-case behavior, and at what scale
5. Fix: the data structure or primitive to substitute
Um tíquete que responde aos cinco é independente: um mantenedor que nunca leu sua análise pode reproduzir sua descoberta & verificar sua correção. Tíquetes que pulam (3) ou (4) exigem que o mantenedor repita sua análise de complexidade antes de poder mesclar. Esse atrito reduz a probabilidade de mescla.
Credibilidade compõe. Um primeiro PR que inclui um tíquete claro, um patch bem direcionado, & um teste de benchmark é mesclado. Um segundo PR do mesmo autor é revisado com menos atrito. Um terceiro PR é revisado pelo mantenedor que mesclou os dois primeiros. A reputação no open source é um registro de artefatos: cada patch aceito ganha confiança para o próximo.
Lendo um Candidato Real
Aqui está um candidato real de MOAD-0001 em Python. Leia-o e complete o protocolo de triagem.
class DependencyResolver:
def resolve(self, package, resolved=None, seen=None):
if resolved is None:
resolved = []
if seen is None:
seen = []
if package in seen:
return
seen.append(package)
for dep in self.registry.get_dependencies(package):
self.resolve(dep, resolved, seen)
resolved.append(package)
return resolved
Perguntas de triagem:
1. What data structure is `seen`?
2. What operation runs against it on line 6?
3. Does `seen` grow with input size?
4. Does the loop that drives recursive calls also grow with input size?
5. Is this a confirmed MOAD-0001 or a false positive?
Seu Patch
Um defeito confirmado com uma pontuação de surge alta precisa de um patch completo: a correção de código, um teste que prova a melhoria, & um esboço de post MOAD.
O teste deve ser um teste de performance, não um teste de correção. Um teste de correção passa antes & depois da correção — esse é o ponto; saída não muda. Um teste de performance em dois tamanhos de entrada prova a melhoria:
import time
def build_graph(n):
# n packages, each depending on the previous one
return {f'pkg{i}': [f'pkg{i-1}'] if i > 0 else [] for i in range(n)}
for n in [100, 1000, 5000]:
registry = build_graph(n)
resolver = DependencyResolver(registry)
start = time.perf_counter()
resolver.resolve(f'pkg{n-1}')
elapsed = time.perf_counter() - start
print(f'n={n}: {elapsed:.4f}s')
Antes da correção, tempo decorrido cresce quadraticamente com n. Depois da correção, ele cresce linearmente. Imprima ambos & inclua os números na descrição do PR.
Um esboço de post MOAD cobre: o nome do padrão, o substrato (Python dependency resolver), o método de detecção (grep para in seen onde seen começa como []), a correção, & um link para seu PR. O post vai para undefect.com como domínio público. Engenheiros futuros pesquisando por 'Python list membership in loop slow' encontrarão.