Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x6005h: No optimices prematuramente

Proceso, diseno y construccion sistematica (0x60XX)

Universidad Nacional de Río Negro

0x6005h: No optimices prematuramente

Enunciado normativo

El orden de prioridades DEBE ser: primero correcto, luego claro, después eficiente. NO DEBE introducirse una optimización —un truco sintáctico, una variable extra o una estructura rebuscada— sin haber medido antes que el programa es lento y que la optimización es la causa.

¿Por qué existe esta regla?

El problema

La optimización prematura aplica complejidad donde todavía no hay un problema de rendimiento. El resultado típico es código más difícil de leer y de depurar, cuyas supuestas mejoras de velocidad son irrelevantes frente al tiempo que consume el usuario o la entrada/salida.

En un curso introductorio el cuello de botella casi nunca está donde el estudiante cree. Optimizar a ojo suele introducir errores de límites, suposiciones no válidas y comportamiento indefinido, y encima no acelera nada, porque el compilador ya hace ese trabajo mejor.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Bug silenciosoLa versión “optimizada” no equivale a la original en los bordes.
LegibilidadEl truco oculta la intención del código.
Pérdida de tiempoSe optimiza lo que no es el cuello de botella.
MantenibilidadCada lector futuro debe descifrar por qué está escrito así.

Fundamento en la cátedra

El lema de Knuth (“la optimización prematura es la raíz de todos los males”) es política de la materia. Se apoya en 0x0001h: La claridad y prolijidad son de máxima importancia: ante la duda, la claridad gana. Además, las herramientas profesionales (-O2) optimizan el código claro sin que el autor ensucie la fuente.

Alcance y excepciones

La regla no prohíbe tener en cuenta la eficiencia: prohíbe anteponerla a la corrección y a la claridad sin medición. Elegir un algoritmo adecuado (búsqueda lineal vs. binaria según el caso) es diseño, no micro-optimización. Cuando se detecte un problema real, se mide, se perfila y recién entonces se optimiza el punto medido.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Reimplementar strlen “más rápido”

size_t longitud_rapida(const char *s)
{
    const char *p = s - 1;
    while (*++p) {
        /* vacio a proposito: ahorra una variable */
    }
    return (size_t)(p - s);
}

Por qué falla: el truco del pre-incremento ahorra una variable, pero viola 0x0001h: La claridad y prolijidad son de máxima importancia, es más difícil de auditar y el cuello de botella real no era recorrer la cadena. La versión clara (while (s[len] != '\0') len++;) es igual de rápida con -O2.

❌ Contraejemplo 2 — Vectorizar a mano antes de medir

/* "optimizado" para procesar de a 4 */
for (int i = 0; i + 3 < n; i += 4) {
    v[i] = v[i] * f;
    v[i + 1] = v[i + 1] * f;
    v[i + 2] = v[i + 2] * f;
    v[i + 3] = v[i + 3] * f;
}
for (; i < n; i++) {
    v[i] = v[i] * f;
}

Por qué falla: duplica la lógica, introduce la variable i usada fuera del lazo y probablemente no supere al for simple con -O2. La complejidad se paga en cada lectura.

✅ Ejemplo conforme 1 — Clara primero

for (size_t i = 0; i < n; i++) {
    v[i] = v[i] * f;
}

Es la versión medible y la que el compilador optimiza. Si resultara lenta, se perfila antes de tocarla.

✅ Ejemplo conforme 2 — Optimización informada por medición

$ perf record ./programa
$ perf report
  72.3%  calcular_histograma

Recién con esa evidencia se decide mejorar calcular_histograma (por ejemplo, cambiando su algoritmo), dejando el resto del código claro.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
perf / valgrind --tool=callgrindperfiladoIdentifica el cuello de botella real antes de tocar el código.
Revisión manualTrucos sin medición ni comentario que los justifique.

Checklist de autocontrol

Reglas relacionadas