un

guest
1 / ?
back to lessons

Nomear Não É Encontrar

Agora você conhece sete padrões MOAD. Saber os nomes importa: permite que você reconheça um padrão quando o vê. Mas a reconhecimento em uma lição controlada difere da detecção em um códigobase que nunca abriu.

Um códigobase não rotula suas defeitos. Um MOAD sedimentar não vem com um comentário que diz // O(N²) — corrija isso. Um tropa de elefantes não anuncia a si mesmo como uma corrida de cache. Eles são encontrados lendo código com uma pergunta específica na mente: *qual estrutura de dados armazena esses valores e quais operações são executadas contra ela dentro de um loop?

A detecção é uma habilidade separada do reconhecimento. Reconhecimento diz: sim, esse padrão é MOAD-0001. Detecção diz: deixe-me encontrar todos os lugares neste códigobase onde esse padrão pode existir, seja eu capaz de ver o código completo ou apenas o nome do símbolo.

Sete MOADs: substratos, assinaturas, correções

Primeiro Escaneamento

Uma primeira passada usa grep. Cada MOAD tem um substrato: uma estrutura de dados ou API cuja presença, perto de certas operações, é um sinal digno de investigação.

MOAD-0001 (Sedimentar): .contains em um loop

# Sinal: teste de pertencimento a uma lista dentro de um 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

# Sinal: campo mutável estático escrito por um sub-sistema, lido por outro
grep -rn 'static ' src/ | grep -v final | grep -v class | grep -v void

MOAD-0003 (Contexto Furtado): ThreadLocal em um executor poolado

# Sinal: ThreadLocal.set() sem garantia de ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l

MOAD-0004 (Segredo Registrado): cabeçalhos HTTP em saídas de log

# Sinal: chamada de log com variável de cabeçalho perto dos pontos de extremidade de autenticação
grep -rn 'log.*header' src/
grep -rn 'Authorization' src/ --include='*.log'

MOAD-0005 (Thundering Herd): falta de cache com nenhuma sincronização

# Sinal: cache.get() + verificação de null + cache.put() sem travamento
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 da estrutura de dados, confirme a operação executando em escala.

Selecione um MOAD de MOAD-0001 até MOAD-0005. Descreva um passo de detecção concreto em um códigobase que nunca leu antes: o que você procura, como um acerto positivo parece e o que distingue um defeito confirmado de um falso positivo.

Lendo Código para Complexidade

O grep encontra candidatos. Ler confirma. Quando você abrir um arquivo de 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. Encontre o loop externo. O que limita seu número de iterações?
2. Encontre a operação interna (.contains, .indexOf, 'in'). Em que estrutura de dados ela é executada?
3. Essa estrutura de dados cresce com o mesmo input que dirige o loop externo?
4. Sim: o custo é O(N²) onde N = tamanho da entrada. Defeito confirmado.
5. Não: a estrutura interna está limitada (configuração, enum, pequeno valor constante). Falso positivo.

Uma travessia de gráfico visitando N nós, verificando uma lista 'visited' em cada etapa: tanto o loop quanto a estrutura de dados interna crescem com N. Confirmado.

Uma solicitação de manipulação verificando uma lista de permitidos de 5 IPs de administrador: a lista nunca cresce com o volume de solicitações. Falso positivo.

O mesmo protocolo se aplica a cada MOAD: identifique o motor externo, identifique a estrutura interna, pergunte se ambos crescem juntos.

Pontuação Surge: Priorizando Seus Achados

Todas as deficiências confirmadas não merecem conserto imediato. Uma MOAD em uma biblioteca com 10.000 dependências downstream tem uma pontuação de surto mais alta do que a mesma MOAD em uma ferramenta interna privada.

Pontuação de surto = velocidade de execução × grau de entrada. Velocidade de execução: quanto mais rápido o correto funciona em uma escala de produção típica? Grau de entrada: quantos pacotes ou serviços downstream herdarão a correção automaticamente quando o upstream a incorporar?

Uma MOAD-0001 confirmada em Apache Maven's resolutor de dependências, executando em grafos de 50.000 nós, com +1.000 plugins Maven downstream que herdam as alterações automaticamente: a pontuação de surto é muito alta. Essa correção deve estar na frente de sua fila.

Uma MOAD-0001 confirmada em uma ferramenta CLI única usuário sem dependentes: pontuação de surto perto de zero. Vale corrigir, mas não é urgente.

Nós trabalhadores vs. nós glotonas. Um nó com alto betweenness & alta velocidade de execução é um trabalhador: ele manipula o fluxo crítico e esvaziará as filas downstream quando desbloqueado. Considere corrigir apenas após confirmar a capacidade downstream. Um nó com alto grau de saída & baixa velocidade de execução é um gloton: ele consome tudo que é alimentado a ele e não sente dor. Corrigir um trabalhador sem etapas downstream cria MOAD-0005 (tropas de cavalaria) em uma escala de infraestrutura.

DAG da fábrica: padrões de nós trabalhadores e glotonas

Você confirmou a MOAD-0001 em dois lugares: (A) um resolutor de dependências em uma ferramenta de build com 200.000 projetos ativos dependendo dele, executando em grafos de árvores de dependência de 10.000 nós; (B) uma utilidade de gráfico em uma pipeline de dados interna em uma única empresa, executando em grafos de 50 nós. Comparem suas pontuações de surto. Qual você consertará primeiro e quais etapas você tomará antes de divulgar?

Scan to Merge: Uma Pipeline MOAD

Uma defeito confirmada com um alto pontuação de surto passa por uma pipeline. Cada estágio produz um artefato. Nenhum estágio é opcional.

scan    → lista de candidatos (saída grep, resultados de análise estática)
ticket  → descrição de defeito (número MOAD, localização, análise de complexidade)
patch   → mudança de código (substituição de estrutura de dados, adoção de primitivos)
test    → teste unitário (prova O(1): temporize a correção em N = 100 e N = 10,000)
UNDF    → divulgação pública (undefect.com, domínio público)
disclose → referência CVE ou CWE se relevante para segurança
PR      → solicitação de pull upstream com patch + teste + link UNDF
merge   → aceitação do mantenedor; correção se propaga via atualização de versão

Cada artefato alimenta o próximo estágio. Uma patch sem um teste não pode ser verificado. Um teste sem uma divulgação não pode se propagar para outras instâncias do mesmo padrão. Uma divulgação sem uma solicitação de pull upstream mantém a correção em um ramo.

Uma postagem MOAD (UNDF) é o estágio que mais engenheiros omitem. Eles corrigem o defeito, submetem uma PR e consideram-se feito. Mas uma correção sem uma postagem nomeada significa que todo engenheiro que encontrar o mesmo padrão no futuro deve descobrir tanto o problema quanto a correção independentemente. Uma postagem MOAD fecha o laço de conhecimento: nomeia o padrão, mostra o método de detecção e vincula à correção. Os pesquisadores futuros encontram a correção buscando pelo nome do padrão.

Patching planetário em larga escala. Uma correção MOAD-0001 em uma biblioteca amplamente usada se propaga para todos os projetos que a importam. Uma postagem MOAD garante que os engenheiros nos projetos que nunca atualizarem essa biblioteca ainda aprendam a correção. Ambos os caminhos correm em paralelo.

Escrevendo um Bilhete de Defeito

Um bom bilhete de defeito responde cinco perguntas:

1. Onde: arquivo exato, classe, função e intervalo de linha
2. O quê: o tipo de estrutura de dados e a operação contra ela
3. Por quê: a análise de complexidade (O(N²) ou pior, com N definido)
4. Impacto: quais entradas desencadeiam o comportamento de pior caso e em que escala
5. Correção: a substituição da estrutura de dados ou primitivo

Um bilhete que responde a todos os cinco é autocontido: um mantenedor que nunca leu sua análise pode reproduzir seu achado e verificar sua correção. Bilhetes que pulam (3) ou (4) requerem que o mantenedor repita sua análise de complexidade antes de poderem integrar. Essa fricção reduz a probabilidade de integração.

Credibilidade se acumula. Um primeiro PR que inclui uma entrada clara, uma patch bem alvo e um teste de benchmark é incorporado. Um segundo PR do mesmo autor é revisado com menos fricção. Um terceiro PR é revisado pelo mantenedor que incorporou os primeiros dois. A reputação no open source é um livro-razão de artefatos: cada patch aceita gera confiança para o próximo.

Escreva um bilhete de defeito mínimo para um MOAD-0001 que você espera encontrar em uma biblioteca de gráficos. Inclua: (1) um nome de arquivo / função plausível, (2) a estrutura de dados e operação, (3) uma declaração de complexidade, (4) um cenário de impacto típico, (5) a correção.

Lendo um Candidato Real

Aqui está um candidato MOAD-0001 real em Python. Leia 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. Qual é a estrutura de dados 'seen'?
2. Qual operação é executada contra ela na linha 6?
3. O 'seen' cresce com o tamanho de entrada?
4. O loop que dirige as chamadas recursivas também cresce com o tamanho de entrada?
5. Este é um MOAD-0001 confirmado ou um falso positivo?
Passe pelo protocolo de triagem para esses cinco perguntas. Em seguida, escreva a correção de uma linha e explique por que ela não muda a saída da função.

Sua Patch

Uma defeito confirmado com um alto score de surto precisa de uma correção completa: a correção de código, um teste que provê o aprimoramento e um esboço de post MOAD.

O teste deve ser um teste de desempenho, não um teste de corretude. Um teste de corretude passa antes e depois da correção - esse é o ponto; a saída não muda. Um teste de desempenho em duas tamanhos de entrada prova o aprimoramento:

import time

def build_graph(n):
    # n pacotes, cada um dependendo do anterior
    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, o tempo de execução cresce quadraticamente com n. Depois da correção, cresce linearmente. Imprima ambos e inclua os números na descrição do PR.

A MOAD post outline cobre: o nome do padrão, a base (resolutor de dependências Python), o método de detecção (grep para in seen onde seen começa como []), a correção e um link para seu PR. O post vai para o undefect.com como domínio público. Futuros engenheiros procurando por 'Python list membership in loop slow' encontrarão.

Você confirmou e corrigiu MOAD-0001 em uma ferramenta popular de embalagem Python. Antes de abrir o PR, o que três coisas você inclui na descrição do PR e por que cada um importa para o mantenedor?