Nombrar No Es Encontrar
Ahora conoces siete patrones MOAD. Saber los nombres importa: te permite reconocer un patrón cuando lo ves. Pero el reconocimiento en una lección controlada difiere de la detección en un códigobase que nunca has abierto.
Un códigobase no etiqueta sus defectos. Un MOAD sedimentario no viene con un comentario que diga // O(N²) — corrije esto. Una multitud rugiente no se anuncia como una estampida de cache. Los encuentras leyendo código con una pregunta específica en mente: qué estructura de datos almacena estos valores y qué operaciones se ejecutan contra ella dentro de un bucle?
La detección es una habilidad separada del reconocimiento. El reconocimiento dice: sí, ese patrón es MOAD-0001. La detección dice: déjame encontrar todos los lugares en este códigobase donde ese patrón podría existir, ya sea que pueda ver el código completo o solo el nombre del símbolo.
Primera Escaneo
Una primera pasada utiliza grep. Cada MOAD tiene un sustrato: una estructura de datos o API cuya presencia, cerca de ciertas operaciones, es una señal digna de investigación.
MOAD-0001 (Sedimentary): .contains() en un bucle
# Señal: prueba de pertenencia en una variable de lista dentro de un bucle
grep -rn '.contains(' src/ | grep -v HashSet | grep -v TreeSet
grep -rn 'visited =' src/ | grep -v set | grep -v Set
MOAD-0002 (Intertangle): bandera mutable compartida entre fases
# Señal: campo mutable estático escrito por un sub-sistema, leído por otro
grep -rn 'static ' src/ | grep -v final | grep -v class | grep -v void
MOAD-0003 (Leaked Context): ThreadLocal en un ejecutor de pool
# Señal: ThreadLocal.set() sin garantía de ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l
MOAD-0004 (Logged Secret): encabezados HTTP en la salida de registro
# Señal: llamada de registro con la variable de encabezados cerca de puntos de extremo de autenticación
grep -rn 'log.*header' src/
grep -rn 'Authorization' src/ --include='*.log'
MOAD-0005 (Thundering Herd): fallo de caché sin sincronización
# Señal: cache.get() + verificación de nulos + cache.put() sin bloqueo
grep -rn 'cache.get' src/ -A4 | grep 'cache.put'
Estos patrones producen candidatos, no defectos confirmados. Cada candidato necesita triaje: leer el código circundante, verificar el tipo de estructura de datos, confirmar que la operación se ejecuta a gran escala.
Lectura de Código para la Complejidad
Grep encuentra candidatos. Leerlos confirma. Cuando abras un archivo de candidatos, lee con una pregunta: ¿cuesta esta operación crecer con el tamaño de la entrada?
Para MOAD-0001, el protocolo de confirmación:
1. Encuentra el bucle externo. ¿Qué limita su recuento de iteraciones?
2. Encuentra la operación interna (.contains, .indexOf, 'in'). ¿Con qué estructura de datos se ejecuta?
3. ¿Esa estructura de datos crece con la misma entrada que hace girar el bucle externo?
4. Si es así: el costo es O(N²) donde N = tamaño de la entrada. Defecto confirmado.
5. Si no: la estructura interna está limitada (config, enumeración, pequeño número constante). Falso positivo.
Una travesía de gráficos que visita N nodos, comprobando una lista 'visited' en cada paso: tanto el bucle como la estructura de datos interna crecen con N. Confirmado.
Un manejador de solicitudes que verifica una lista de permitidos de 5 direcciones IP de administrador: la lista de permitidos nunca crece con el volumen de solicitudes. Falso positivo.
El mismo protocolo se aplica a cada MOAD: identifica el conductor externo, identifica la estructura interna, pregunta si ambos escalan juntos.
Puntuación Surge: Priorizando Tus Hallazgos
No todos los defectos confirmados requieren una reparación inmediata. Un MOAD en una biblioteca con 10.000 dependencias descendentes tiene una puntuación de oleada más alta que el mismo MOAD en una herramienta interna privada.
Puntuación de oleada = aceleración × grado de entrada. Aceleración: ¿Cuánto más rápido funciona la solución en una escala de producción típica? Grado de entrada: ¿Cuántas paquetes o servicios de bajada heredarían automáticamente la solución cuando el upstream la fusiona?
Un MOAD-0001 confirmado en el resolutor de dependencias de Apache Maven, funcionando en gráficos de 50.000 nodos, con +1.000 plugins Maven descendentes que heredan los cambios automáticamente: la puntuación de oleada es muy alta. Esta solución debe estar en la primera línea de su cola.
Un MOAD-0001 confirmado en una herramienta CLI para un solo usuario sin dependientes: puntuación de oleada cercana a cero. Vale la pena arreglarlo, pero no es urgente.
Nodos trabajadores vs. nodos glotones. Un nodo con alto entretenimiento y alta aceleración es un trabajador: maneja el flujo crítico y vaciará las colas de bajada cuando se desbloquee. Sólo desbloquee a un trabajador después de confirmar la capacidad de bajada. Un nodo con alto grado de salida y baja aceleración es un glotón: consume todo lo que se le alimenta y no siente dolor. Arreglar a un trabajador sin etapas de capacidad de bajada crea MOAD-0005 (manada trueno) a una escala de infraestructura.
Escaneo para Fusionar: Una Línea de Producción MOAD
Un defecto confirmado con un alto puntaje de sobrecarga pasa por una línea de producción. Cada etapa produce un artefacto. No hay etapa opcional.
escaneo → lista de candidatos (salida de grep, resultados de análisis estático)
tiquet → descripción del defecto (número MOAD, ubicación, análisis de complejidad)
patch → cambio de código (intercambio de estructura de datos, adopción de primitivos)
prueba → prueba unitaria (demostración O(1): tiempo la solución en N = 100 y N = 10,000)
UNDF → divulgación pública (undefect.com, dominio público)
divulgar → referencia a CVE o CWE si es relevante para la seguridad
PR → solicitud de extracción upstream con parche + prueba + enlace UNDF
fusionar → aceptación del mantenedor; la solución se propaga a través de un aumento de versión
Cada artefacto alimenta la siguiente etapa. Un parche sin una prueba no se puede verificar. Una prueba sin una divulgación no puede propagarse a otras instancias del mismo patrón. Una divulgación sin una solicitud de extracción upstream deja la solución atrapada en una rama.
Una publicación MOAD (UNDF) es la etapa que más ingenieros omiten. Solucionan el defecto, envían una solicitud de extracción y consideran que han terminado. Pero una solución sin una publicación llamada significa que cada futuro ingeniero que encuentre el mismo patrón debe descubrir tanto el problema como la solución de manera independiente. Una publicación MOAD cierra el bucle de conocimiento: nombra el patrón, muestra el método de detección y enlaza al parche. Los investigadores futuros encuentran la solución buscando el nombre del patrón.
Parches planetarios a gran escala. Una solución MOAD-0001 en una biblioteca ampliamente utilizada se propaga a todos los proyectos que la importan. Una publicación MOAD asegura que los ingenieros en proyectos que nunca actualizarán esa biblioteca aún aprendan la solución. Ambos caminos corren en paralelo.
Escribir un Tiquet de Defecto
Un buen tiquet de defecto responde a cinco preguntas:
1. Dónde: archivo exacto, clase, función y rango de líneas
2. Qué: el tipo de estructura de datos y la operación contra ella
3. Por qué: el análisis de complejidad (O(N²) o peor, con N definido)
4. Impacto: qué entradas disparan el comportamiento peor, y a qué escala
5. Solución: la estructura de datos o primitivo para sustituir
Un tiquet que responde a todos los cinco es autónomo: un mantenedor que nunca haya leído su análisis puede reproducir su hallazgo y verificar su solución. Los tiquetes que omitan (3) o (4) requieren que el mantenedor repita su análisis de complejidad antes de que puedan fusionar. Esa fricción reduce la probabilidad de fusión.
La credibilidad se acumula. Un primer PR que incluye una entrada clara, una parche bien dirigido y una prueba de referencia se fusiona. Un segundo PR del mismo autor se revisa con menos fricción. Un tercer PR se revisa por el mantenedor que fusionó los dos primeros. La reputación en el software de código abierto es un registro de artefactos: cada parche aceptado gana confianza para el siguiente.
Lectura de un Candidato Real
Aquí hay un candidato real MOAD-0001 en Python. Léelo y completa el protocolo de triaje.
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
Interrogantes de triaje:
1. ¿Cuál es la estructura de datos de `seen`?
2. ¿Qué operación se ejecuta contra ella en la línea 6?
3. ¿Crecerá `seen` con tamaño de entrada?
4. ¿El bucle que controla las llamadas recursivas también crecerá con tamaño de entrada?
5. ¿Es esto un MOAD-0001 confirmado o un falso positivo?
Tu parche
Una deficiencia confirmada con un alto puntaje de surgencia necesita una solución completa: la solución de código, una prueba que demuestre la mejora y un esbozo de publicación de MOAD.
La prueba debe ser una prueba de rendimiento, no una prueba de corrección. Una prueba de corrección pasa antes y después de la solución - ese es el punto; la salida no cambia. Una prueba de rendimiento en dos tamaños de entrada demuestra la mejora:
import time
def build_graph(n):
# n paquetes, cada uno dependiendo del 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 de la solución, el tiempo de ejecución crece cuadráticamente con n. Después de la solución, crece linealmente. Imprima ambos y incluya los números en la descripción del PR.
Un esquema de publicación de MOAD cubre: el nombre del patrón, la base de datos (resolutor de dependencias de Python), el método de detección (grep para in seen donde seen comienza como []), la solución, y un enlace a tu PR. El post se envía a undefect.com como dominio público. Ingenieros futuros buscando 'Python list membership in loop slow' lo encontrarán.