Namngivning är inte att hitta
Du känner nu till sju MOAD-mönster. Att känna till namn är viktigt: det låter dig känna igen ett mönster när du ser det. Men igenkänning i en kontrollerad lektion skiljer sig från detektionen i en kodbas som du aldrig har öppnat.
En kodbas märker inte sina defekter. En sedimentär MOAD kommer inte med en kommentar som säger // O(N²) — fix this. En thundering herd presenterar sig inte som en cache miss-stampede. Du hittar dem genom att läsa kod med en specifik fråga i åtanke: vilken datastruktur håller dessa värden, och vilka operationer körs mot den inom en slinga?
Detektionen är en skicklighet separat från igenkänning. Igenkänning säger: ja, det mönstret är MOAD-0001. Detektionen säger: låt mig hitta alla platser i denna kodbas där det mönstret kan existera, oavsett om jag kan se den fullständiga koden eller bara ett symbolnamn.
Första skanning
En första genomgång använder grep. Varje MOAD har ett substrat: en datastruktur eller ett API vars närvaro, nära vissa operationer, är en signal värd att undersöka.
MOAD-0001 (Sedimentary): List.contains i en slinga
# 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): delad muterbar flagga mellan faser
# 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 i en poolad executor
# Signal: ThreadLocal.set() without guaranteed ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l
MOAD-0004 (Logged Secret): HTTP-headers i loggutdata
# 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 utan synkronisering
# Signal: cache.get() + null check + cache.put() without lock
grep -rn 'cache.get' src/ -A4 | grep 'cache.put'
Dessa mönster producerar kandidater, inte bekräftade defekter. Varje kandidat behöver bedömning: läs omkring koden, verifiera datastrukturstypen, bekräfta att operationen körs i skala.
Läsa kod för komplexitet
Grep hittar kandidater. Läsning bekräftar dem. När du öppnar en kandidatfil läser du med en fråga: växer denna operationskostnad med indatastorlek?
För MOAD-0001 är bekräftelseprotokollet:
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.
En grafgenomgång som besöker N noder, kontrollerar en visited-lista på varje steg: både slingen och den inre datastrukturen växer med N. Bekräftad.
En begärandehantererare som kontrollerar en tillåtna-lista med 5 admin-IP-adresser: tillåten-listan växer aldrig med begärandevolym. Falsk positiv.
Samma protokoll gäller för varje MOAD: identifiera den yttre drivaren, identifiera den inre strukturen, fråga dig själv om båda skalas tillsammans.
Surge-poäng: Prioritering av dina fynd
Inte alla bekräftade defekter motiverar omedelbar fixning. En MOAD i ett bibliotek med 10 000 nedströmsberoenden har ett högre surge-poäng än samma MOAD i ett privat internt verktyg.
Surge-poäng = speedup × in-degree. Speedup: hur mycket snabbare kör fixningen vid typisk produktionskala? In-degree: hur många nedströmpaket eller tjänster skulle ärva fixningen automatiskt när upstream slagit ihop den?
En bekräftad MOAD-0001 i Apache Mavens beroendeupplösare, körande på grafer med 50 000 noder, med 1 000+ nedströmsMaven-plugins som ärver ändringar automatiskt: surge-poänget är mycket högt. Denna fix hör till framsidan av din kö.
En bekräftad MOAD-0001 i ett verktyg med en enda användare utan beroenden: surge-poäng nära noll. Värt att fixa, men inte brådskande.
Workaholic vs. glutton noder. En nod med högt mittemellan & högt speedup är en workaholic: den hanterar kritiskt flöde & kommer att spöla nedströmskökerna när den är olåst. Fixa den bara efter att ha bekräftat nedströmskapacitet. En nod med högt out-degree & lågt speedup är en glutton: den konsumerar allt som matas till den och känner ingen smärta. Att fixa en workaholic utan mellanlagring av nedströmskapacitet skapar MOAD-0005 (thundering herd) vid infrastrukturskalor.
Skanning till sammanslagning: En MOAD-pipeline
En bekräftad defekt med ett högt surge-poäng går genom en pipeline. Varje steg producerar en artefakt. Inget steg är valfritt.
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
Varje artefakt matar nästa steg. En patch utan ett test kan inte verifieras. Ett test utan en avslöjning kan inte spridas till andra fall av samma mönster. En avslöjning utan en upstream PR strander fixningen i en fork.
En MOAD-post (UNDF) är det steg som de flesta ingenjörer utelämnar. De fixar defekten, skickar ett PR, och anser sig färdiga. Men en fix utan ett namngivet inlägg betyder att varje framtida ingenjör som möter samma mönster måste återupptäcka både problemet och fixningen oberoende. En MOAD-post stänger kunskapsloopen: den namnger mönstret, visar detektionsmetoden, & länkar till patchen. Framtida forskare hittar fixningen genom att söka efter mönsternamnet.
Planeten lappning i skala. En enda MOAD-0001-fix i ett allmänt använt bibliotek propagerar till varje projekt som importerar det. En MOAD-post säkerställer att ingenjörer i projekt som aldrig kommer att uppgradera det biblioteket fortfarande lär sig fixningen. Båda vägarna körs parallellt.
Skriva en defektbiljett
En bra defektbiljett svarar på fem frågor:
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
En biljett som svarar på alla fem är självständig: en underhållare som aldrig har läst din analys kan reproducera ditt fynd och verifiera din fix. Biljetter som skippar (3) eller (4) kräver att underhållaren upprepar din komplexitetsanalys innan de kan slå ihop. Den friktionen minskar sannolikheten för sammanslagning.
Trovärdighet förenar sig. En första PR som inkluderar en tydlig biljett, en väl riktad patch, & ett benchmark-test blir ihopslaget. En andra PR från samma författare granskas med mindre friktion. En tredje PR granskas av underhållaren som slog ihop den första två. Rykte i öppen källkod är en ledger av artefakter: varje accepterad patch tjänar tillit för nästa.
Läsa en riktigt kandidat
Här är en riktigt MOAD-0001-kandidat i Python. Läs den och slutför bedömningsprotokollet.
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
Bedömningsfrågor:
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?
Din patch
En bekräftad defekt med ett högt surge-poäng behöver en komplett patch: kodfix, ett test som bevisar förbättringen, & en MOAD-postöversikt.
Testet måste vara ett prestationstest, inte ett riktighetstest. Ett riktighetstest passerar före och efter fixningen — det är poängen; utdata ändras inte. Ett prestationstest vid två indatastorlekar bevisar förbättringen:
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')
Före fixningen växer tidsutrymmet kvadratiskt med n. Efter fixningen växer det linjärt. Skriv båda ut och inkludera siffrorna i din PR-beskrivning.
En MOAD-postöversikt täcker: mönsternamnet, substratet (Python-beroendeupplösare), detektionsmetoden (grep för in seen där seen börjar som []), fixningen, & en länk till din PR. Inlägget går till undefect.com som public domain. Framtida ingenjörer som söker efter 'Python list membership in loop slow' hittar det.