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 consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | La versión “optimizada” no equivale a la original en los bordes. |
| Legibilidad | El truco oculta la intención del código. |
| Pérdida de tiempo | Se optimiza lo que no es el cuello de botella. |
| Mantenibilidad | Cada 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_histogramaRecién con esa evidencia se decide mejorar calcular_histograma (por ejemplo,
cambiando su algoritmo), dejando el resto del código claro.
⚠️ Casos límite¶
Elección de algoritmo: es legítima y esperable (burbuja vs.
qsort), porque no complica la lectura.Restricciones del enunciado: si se exige una complejidad temporal, se diseña para cumplirla desde el inicio del algoritmo.
Micro-optimizaciones claras: un
switchen vez de una cadena deifpuede ser a la vez más claro y más rápido; no es prematura.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
perf / valgrind --tool=callgrind | perfilado | Identifica el cuello de botella real antes de tocar el código. |
| Revisión manual | — | Trucos sin medición ni comentario que los justifique. |
Checklist de autocontrol¶
¿El programa es correcto y claro antes que rápido?
¿Medí dónde está el cuello de botella?
¿La optimización introdujo suposiciones no válidas en los bordes?
¿La versión optimizada sigue siendo legible?
Reglas relacionadas¶
0x0001h: La claridad y prolijidad son de máxima importancia — claridad como prioridad.
0x2014h: Cada función debe caber en una sola idea y en 25 líneas — una idea por función.
0x0017h: Agrupá sentencias relacionadas y separá bloques lógicos — separar cálculo de presentación para medir mejor.