36 puntos por GN⁺ 2026-03-19 | 1 comentarios | Compartir por WhatsApp
  • Regla 1: No se puede predecir dónde consumirá tiempo un programa. Los cuellos de botella aparecen en lugares inesperados, así que no intentes mejorar la velocidad hasta que se demuestre que realmente hay un cuello de botella
  • Regla 2: Primero mide. El ajuste de rendimiento solo debe hacerse después de medir, y solo considerar la optimización cuando una parte del código domine claramente el total
  • Regla 3: Los algoritmos sofisticados son lentos para n pequeños. Los algoritmos complejos tienen constantes grandes, así que, a menos que n crezca con frecuencia, usa un método simple. Incluso si n crece, primero hay que aplicar la regla 2
  • Regla 4: Los algoritmos complejos tienen más errores y son más difíciles de implementar. Es preferible usar algoritmos simples y estructuras de datos simples
  • Regla 5: Los datos son la clave. Si eliges la estructura de datos correcta y la organizas bien, el algoritmo se vuelve casi evidente por sí mismo. El centro de la programación no es el algoritmo, sino la estructura de datos

Filosofía y citas relacionadas

  • Las reglas 1 y 2 significan básicamente lo mismo que la máxima de Tony Hoare: “la optimización prematura es la raíz de todos los males”
  • Ken Thompson reinterpretó las reglas 3 y 4 como “cuando tengas dudas, usa el método simple (Brute Force)”
  • Las reglas 3 y 4 son ejemplos de la filosofía de diseño KISS (Keep It Simple, Stupid)
  • La regla 5 ya había sido mencionada por Fred Brooks en The Mythical Man-Month, y
    a menudo se resume como “escribir código simple usando objetos inteligentes”

1 comentarios

 
GN⁺ 2026-03-19
Comentarios en Hacker News
  • Me hizo recordar la charla de Jonathan Blow
    Él lo abordó desde la perspectiva de la productividad. En las primeras etapas del desarrollo de Braid, implementó casi todo con arreglos simples y solo lo cambiaba cuando aparecía un cuello de botella
    Me quedó grabada la frase: “Más importante que la velocidad o la memoria es el tiempo de vida humana que toma implementar un programa”

    • Los juegos procesan repetidamente una gran cantidad de objetos similares a más de 60 cuadros por segundo, así que una estructura basada en arreglos es un valor predeterminado razonable
    • En desarrollo de juegos, hay que renderizar un frame en 16 ms, por lo que las tablas de tamaño fijo y la búsqueda lineal son patrones comunes. Es una elección estructural para evitar la imprevisibilidad de la asignación dinámica
    • Esta perspectiva también aplica al desarrollo general fuera de los juegos. Todos trabajamos con plazos y restricciones de costo, así que el tiempo de ingeniería en sí mismo también cuesta
    • Aun así, hay que tener cuidado al extender directamente las lecciones de los juegos a la programación general. Los juegos se centran más en código de propósito específico que en reutilización, mientras que el software general se centra en los datos
    • En mi caso, soy del tipo que empieza con un hash map en lugar de un arreglo
  • Si te tomas en serio la Rule 1, las Rule 3~5 salen de forma natural
    Si aceptas la premisa de que no puedes predecir los cuellos de botella, entonces escribir código simple y medir se vuelve la única estrategia racional
    En la práctica, lo que más suele fallar no es la optimización prematura sino la abstracción prematura. Se crean capas complejas por una flexibilidad que no hace falta, y eso termina elevando el costo de mantenimiento

    • En el equipo citamos seguido la frase: “Las abstracciones deben surgir de forma natural, no diseñarse por adelantado”
    • La abstracción prematura desperdicia tiempo de desarrollo, aumenta la deuda técnica y eleva la probabilidad de bugs. A menudo aparece con la excusa de “prepararse para problemas futuros”
    • Como texto relacionado, vale la pena revisar el artículo de Philip Wadler
    • Yo valoro más la legibilidad y mantenibilidad que el rendimiento. Por eso, para mí la Rule 4 es la base, y la Rule 1 es su consecuencia
    • Viví un caso donde separaron en exceso archivos de configuración complejos. Al final, 8 archivos YAML simples eran más que suficientes
  • Tuve la experiencia de tener que implementar una función de búsqueda en un dataset a las 2 de la madrugada en los 90
    Como estaba cansado, lo hice primero con búsqueda lineal y lo dejé para arreglar después, pero en la práctica la diferencia fue de apenas 6 segundos en una prueba de 4 horas
    Al final sí lo cambié, pero no hubo una diferencia significativa

    • Con n pequeño, la búsqueda lineal incluso puede ser más rápida
    • Pero un algoritmo O(n²) trae el riesgo de que “se pueda desplegar, pero al final explote en producción
  • Estoy totalmente de acuerdo con la Rule 5
    Cuanto más difícil es el problema, más se resuelve con mejoras iterativas en las estructuras de datos y la API. Si la estructura está bien definida, el flujo de control se vuelve natural
    Los LLM son débiles para este tipo de pensamiento estructural. Pueden proponer bien flujos de control complejos, pero no diseñan bien estructuras de datos componibles

    • En mi experiencia, la Rule 5 es prácticamente la Rule 1. Hay un dicho que dice: “Si me muestras el código me confundo, pero si me muestras el esquema de la base de datos, todo queda claro”
    • En servicios distribuidos, la Rule 5 suele ignorarse. En vez de dividirlo en varias llamadas HTTP y a la BD, una estructura que permita resolverlo con una sola llamada suele ser más eficiente
  • Vengo de ingeniería eléctrica (E.E.), y gracias a la Rule 3 no tuve grandes problemas al comienzo de mi carrera
    Pero más adelante, al pasar a sistemas grandes, n creció y la complejidad sí empezó a importar de verdad
    El “big iron” de la época de Rob Pike se parece bastante al entorno embebido actual

    • Discrepo en parte con la Rule 3. Con entradas pequeñas no importa tanto, pero con entradas grandes el rendimiento Big-O sí importa.
      Si dos algoritmos tienen una dificultad de implementación parecida, elijo el que sea más rápido con entradas grandes
      Texto relacionado: Less Than Quadratic
    • El significado de “fancy” debe interpretarse según el dominio del problema. Si n es pequeño, un enfoque simple es mejor, pero si n es grande, un algoritmo avanzado es indispensable
      A menudo la gente elige un enfoque O(n²) demasiado simple y termina viendo cómo explota en producción
    • Mi padre disfrutaba usar lookup table desde la época de Fortran. Es una forma clásica de optimización para reducir cálculos repetidos
  • Creo que las reglas de Pike son mejores que los aforismos tradicionales
    Frases como “la optimización prematura es la raíz de todos los males” pierden contexto y se prestan a malentendidos
    La versión de Pike es clara y difícil de usar mal
    Había una formulación antigua que resumía la Rule 5 como “haz que el código tonto use objetos inteligentes”,
    pero en la era de la orientación a objetos eso terminó degenerando en una creencia equivocada que oculta la complejidad

    • Es importante mantener el vínculo con la forma histórica de pensar
    • La expresión “clickbait mental de los aforismos clásicos” se siente como una especie de metáfora ingeniosa
  • Después de más de 10 años operando la misma base de código, interioricé por completo las reglas de Pike
    Seguir los principios KISS/DRY y mantener tecnologías probadas en lugar de modas ha sido más estable a largo plazo
    De hecho, el documento de principios de desarrollo de nuestro equipo dice casi lo mismo que las reglas de Pike

  • En los primeros años de C++ en los 90, cambié una lista doblemente enlazada por una simple reasignación de arreglos,
    y no solo desaparecieron los bugs, sino que además resultó más rápido.
    Aprendí que una buena estrategia es hacer operaciones costosas con menos frecuencia

  • Es interesante comparar la regla de “no optimices sin medir” con Latency Numbers Every Programmer Should Know de Jeff Dean
    Dean dice que con conocimiento previo se puede predecir el rendimiento
    Al final, ambas posturas pueden reconciliarse: en la etapa de diseño eliges una estructura intuitivamente rápida, y después de implementar haces el ajuste fino basado en mediciones

    • El código realmente rápido usa ambos enfoques. En la etapa de diseño considera la eficiencia de caché, y después elimina cuellos de botella con profiling
    • Las cifras de latencia solo muestran el límite teórico de un algoritmo; el rendimiento real depende de la implementación y del entorno de ejecución
    • Lo que prohíbe la “optimización prematura” es el tuning local a nivel de hacks. Tener en cuenta la velocidad en el diseño general es totalmente normal
  • La Rule 1 y 2 son absolutas solo cuando se trata de problemas nuevos
    Cuando construyes sistemas repetidamente dentro del mismo dominio, puedes predecir de antemano dónde estarán los cuellos de botella
    Un desarrollador con experiencia puede tener una idea aproximada del rendimiento incluso antes de diseñar

    • Yo también he predicho con precisión los cuellos de botella en la mayoría de los casos. Muchas veces cambié el enfoque tras pruebas de rendimiento previas
    • Pero en 30 años de experiencia, aunque la intuición sobre que habría un cuello de botella suele acertar, no se puede predecir con exactitud dónde ni cuándo aparecerá
    • También hubo bromas del tipo “¿qué va a saber Rob Pike?”, pero él es una de las personas que hicieron Unix y Go. Sus reglas tienen una razón de ser