English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

invité
1 / ?
retour aux leçons

Nommer n'est pas trouver

Vous connaissez maintenant sept motifs MOAD. Connaître les noms importe : cela vous permet de reconnaître un motif quand vous le voyez. Mais la reconnaissance dans une leçon contrôlée diffère de la détection dans un codebase que vous n'avez jamais ouvert.

Un codebase ne marque pas ses défauts. Un MOAD sédimentaire ne vient pas avec un commentaire qui dit // O(N²) — fix this. Un thundering herd ne s'annonce pas comme une ruée de cache miss. Vous les trouvez en lisant le code avec une question spécifique à l'esprit : quelle structure de données contient ces valeurs, et quelles opérations s'exécutent contre elle dans une boucle ?

La détection est une compétence distincte de la reconnaissance. La reconnaissance dit : oui, ce motif est MOAD-0001. La détection dit : laissez-moi trouver tous les endroits dans ce codebase où ce motif pourrait exister, que je puisse voir le code complet ou seulement un nom de symbole.

Sept MOADs: substrats, signatures, correctifs

Premier Scan

Un premier passage utilise grep. Chaque MOAD a un substrat : une structure de données ou une API dont la présence, près de certaines opérations, est un signal qui vaut la peine d'être examiné.

MOAD-0001 (Sédimentaire) : List.contains dans une boucle

# 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): shared mutable flag across phases

# 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 in a pooled executor

# Signal: ThreadLocal.set() without guaranteed ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l

MOAD-0004 (Logged Secret): HTTP headers in log output

# 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 with no synchronization

# Signal: cache.get() + null check + cache.put() without lock
grep -rn 'cache.get' src/ -A4 | grep 'cache.put'

Ces motifs produisent des candidats, pas des défauts confirmés. Chaque candidat a besoin de triage : lire le code environnant, vérifier le type de structure de données, confirmer que l'opération s'exécute à grande échelle.

Choisissez un MOAD de MOAD-0001 à MOAD-0005. Décrivez une étape de détection concrète que vous prendriez dans un codebase que vous n'avez jamais lu avant : ce que vous recherchez, à quoi ressemble un hit positif, & ce qui distingue un défaut confirmé d'un faux positif.

Lire le Code pour la Complexité

Grep trouve des candidats. Lire confirme. Quand vous ouvrez un fichier candidat, vous lisez avec une question : le coût de cette opération grandit-il avec la taille d'entrée ?

Pour MOAD-0001, le protocole de confirmation :

1. Trouvez la boucle externe. Qu'est-ce qui limite son nombre d'itérations ?
2. Trouvez l'opération interne (.contains, .indexOf, 'in'). Quelle structure de données s'exécute-t-elle contre ?
3. Cette structure de données grandit-elle avec la même entrée qui pilote la boucle externe ?
4. Si oui : le coût est O(N²) où N = taille d'entrée. Défaut confirmé.
5. Si non : la structure interne est bornée (config, enum, petite constante). Faux positif.

Un parcours de graphe visitant N nœuds, vérifier une liste visited à chaque étape : la boucle et la structure de données interne grandissent toutes deux avec N. Confirmé.

Un gestionnaire de demande vérifier une liste blanche de 5 adresses IP administrateur : la liste blanche ne grandit jamais avec le volume de demande. Faux positif.

Le même protocole s'applique à chaque MOAD : identifier le pilote externe, identifier la structure interne, demander si les deux mettent à l'échelle ensemble.

Score de Surge : Prioriser vos découvertes

Pas tous les défauts confirmés justifient un correctif immédiat. Un MOAD dans une bibliothèque avec 10 000 dépendants en aval a un score de surge plus élevé que le même MOAD dans un outil interne privé.

Score de surge = speedup × in-degree. Speedup : à quelle vitesse le correctif s'exécute-t-il à l'échelle de production typique ? In-degree : combien de packages ou de services en aval hériter du correctif automatiquement quand l'amont le fusionne ?

Un MOAD-0001 confirmé dans le solveur de dépendances d'Apache Maven, s'exécutant sur des graphes de 50 000 nœuds, avec 1 000+ plugins Maven en aval qui héritent automatiquement des changements : le score de surge est très élevé. Ce correctif appartient à l'avant de votre queue.

Un MOAD-0001 confirmé dans un outil CLI pour un seul utilisateur sans dépendants : score de surge proche de zéro. Vaut la peine d'être corrigé, mais pas urgent.

Nœuds workaholics vs gluttons. Un nœud avec betweenness élevée & speedup élevée est un workaholic : il gère un flux critique & vidangera les queues en aval quand il est débloqué. Ne le corrigez que après avoir confirmé la capacité en aval. Un nœud avec out-degree élevée & speedup faible est un glutton : il consomme tout ce qui lui est alimenté et ne ressent aucune douleur. Corriger un workaholic sans étager la capacité en aval crée MOAD-0005 (thundering herd) à l'échelle infrastructure.

Factory DAG: workaholic & glutton node patterns

Vous avez confirmé MOAD-0001 dans deux endroits : (A) un solveur de dépendances dans un outil de construction avec 200 000 projets actifs en dépendant, s'exécutant sur des graphes de 10 000 nœuds de dépendance ; (B) un utilitaire de graphe dans un pipeline de données interne d'une seule entreprise, s'exécutant sur des graphes de 50 nœuds. Comparez leurs scores de surge. Lequel corrigez-vous en premier, et quelles étapes prenez-vous avant de divulguer ?

Scan à Merge : Un Pipeline MOAD

Un défaut confirmé avec un score de surge élevé se déplace à travers un pipeline. Chaque étape produit un artefact. Aucune étape n'est optionnelle.

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

Chaque artefact alimente l'étape suivante. Un correctif sans test ne peut pas être vérifié. Un test sans divulgation ne peut pas se propager à d'autres instances du même motif. Une divulgation sans PR en amont isole le correctif dans une branche.

Un post MOAD (UNDF) est l'étape que la plupart des ingénieurs omettent. Ils corrigent le défaut, envoient un PR, et se considèrent comme faits. Mais un correctif sans un post nommé signifie que chaque futur ingénieur qui rencontre le même motif doit redécouvrir à la fois le problème et le correctif indépendamment. Un post MOAD ferme la boucle de connaissance : il nomme le motif, montre la méthode de détection, & établit un lien vers le correctif. Les futurs chercheurs trouvent le correctif en cherchant le nom du motif.

Patcher la planète à l'échelle. Un seul correctif MOAD-0001 dans une bibliothèque largement utilisée se propage à chaque projet qui l'importe. Un post MOAD assure que les ingénieurs dans les projets qui ne mettront jamais à jour cette bibliothèque apprennent toujours le correctif. Les deux chemins s'exécutent en parallèle.

Écrire un Ticket de Défaut

Un bon ticket de défaut répond à cinq questions :

1. Où : fichier exact, classe, fonction, et plage de lignes
2. Quoi : le type de structure de données et l'opération contre elle
3. Pourquoi : l'analyse de complexité (O(N²) ou pire, avec N défini)
4. Impact : quelles entrées déclenchent le comportement du pire cas, et à quelle échelle
5. Correctif : la structure de données ou primitive à substituer

Un ticket qui répond à tous les cinq est autosuffisant : un mainteneur qui n'a jamais lu votre analyse peut reproduire votre découverte et vérifier votre correctif. Les tickets qui sautent (3) ou (4) exigent que le mainteneur répète votre analyse de complexité avant de pouvoir fusionner. Cette friction réduit la probabilité de fusion.

La crédibilité se combine. Un premier PR qui inclut un ticket clair, un correctif bien ciblé, & un test de référence est fusionné. Un deuxième PR du même auteur est examiné avec moins de friction. Un troisième PR est examiné par le mainteneur qui a fusionné les deux premiers. La réputation en open source est un ledger d'artefacts : chaque correctif accepté gagne la confiance pour le suivant.

Écrivez un ticket de défaut minimal pour un MOAD-0001 que vous vous attendriez à trouver dans une bibliothèque de graphe. Incluez : (1) un nom de fichier/fonction plausible, (2) la structure de données & l'opération, (3) une déclaration de complexité, (4) un scénario d'impact typique, (5) le correctif.

Lire un Candidat Réel

Voici un vrai candidat MOAD-0001 en Python. Lisez-le et complétez le protocole de triage.

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

Questions de triage :

1. Quelle structure de données est `seen`?
2. Quelle opération s'exécute contre elle à la ligne 6 ?
3. `seen` grandit-il avec la taille d'entrée ?
4. La boucle qui pilote les appels récursifs grandit-elle aussi avec la taille d'entrée ?
5. Est-ce un MOAD-0001 confirmé ou un faux positif ?
Travaillez à travers les cinq questions de triage pour ce code. Ensuite, écrivez le correctif d'une ligne et expliquez pourquoi il ne change pas le résultat de la fonction.

Votre Correctif

Un défaut confirmé avec un score de surge élevé a besoin d'un correctif complet : le correctif de code, un test qui prouve l'amélioration, & un aperçu du post MOAD.

Le test doit être un test de performance, pas un test de justesse. Un test de justesse passe avant et après le correctif — c'est le point ; le résultat ne change pas. Un test de performance à deux tailles d'entrée prouve l'amélioration :

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')

Avant le correctif, le temps écoulé grandit de façon quadratique avec n. Après le correctif, il grandit de manière linéaire. Imprimez les deux et incluez les nombres dans la description de votre PR.

Un aperçu du post MOAD couvre : le nom du motif, le substrat (solveur de dépendances Python), la méthode de détection (grep pour in seenseen commence comme []), le correctif, & un lien vers votre PR. Le post va à undefect.com en domaine public. Les futurs ingénieurs cherchant 'Python list membership in loop slow' le trouveront.

Vous avez confirmé & corrigé MOAD-0001 dans un outil d'empaquetage Python populaire. Avant d'ouvrir le PR, quelles trois choses incluez-vous dans la description du PR, et pourquoi chacune importe-t-elle au mainteneur ?