¿Es la optimización prematura realmente la raíz de todo mal?

215

Un colega mío cometió hoy una clase llamada ThreadLocalFormat, que básicamente movió instancias de clases de formato Java a un subproceso local, ya que no son seguras para los subprocesos y son "relativamente caras" de crear. Escribí una prueba rápida y calculé que podía crear 200,000 instancias por segundo, le pregunté si estaba creando esa cantidad, a lo que respondió "de ninguna manera cerca de esa cantidad". Es un gran programador y todos en el equipo son altamente calificados, por lo que no tenemos problemas para comprender el código resultante, pero fue claramente un caso de optimización donde no hay una necesidad real. Retrocedió el código a mi pedido. ¿Qué piensas? ¿Es este un caso de "optimización prematura" y qué tan malo es realmente?

Craig Day
fuente
23
Creo que necesita distinguir entre optimización prematura y optimización innecesaria. Prematuro para mí sugiere "demasiado temprano en el ciclo de vida", mientras que innecesario sugiere "no agrega un valor significativo". En mi opinión, el requisito de optimización tardía implica un diseño de mala calidad.
110
Sí, pero el mal es un polinomio y tiene muchas raíces, algunas de ellas son complejas.
dan_waterworth
77
Debería considerar que Knuth escribió este 1974. En los años setenta no era tan fácil escribir programas lentos como lo es hoy en día. Escribió con Pascal en mente y no con Java o PHP.
ceving
44
No. La raíz de todo mal es la avaricia.
Tulains Córdova
12
@ceving En los años 70 era tan fácil como hoy escribir programas lentos. Si elige el algoritmo incorrecto o la estructura de datos incorrecta, ¡BAM! Mal desempeño en todo el lugar. Uno podría discutir al revés. Hoy en día, son muchas más herramientas y debería ser inexcusable que un programador todavía escriba software que sufre en la operación de guardado más básica. El paralelismo se convirtió casi en una mercancía y todavía sufrimos. El rendimiento lento no puede atribuirse al lenguaje o la herramienta o la CPU o la memoria. Es un delicado equilibrio de tantas cosas, por lo que es casi imposible optimizarlo temprano.
Alex

Respuestas:

322

Es importante tener en cuenta la cita completa:

Deberíamos olvidarnos de las pequeñas eficiencias, digamos alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal. Sin embargo, no debemos dejar pasar nuestras oportunidades en ese crítico 3%.

Lo que esto significa es que, en ausencia de problemas de rendimiento medidos, no debe optimizar porque cree que obtendrá un aumento de rendimiento. Hay optimizaciones obvias (como no hacer la concatenación de cadenas dentro de un bucle cerrado), pero cualquier cosa que no sea una optimización trivialmente clara debe evitarse hasta que pueda medirse.

Los mayores problemas con la "optimización prematura" son que puede introducir errores inesperados y puede ser una gran pérdida de tiempo.

Scott Dorman
fuente
77
Siendo de Donald Knuth, no me sorprendería si tuviera alguna evidencia que lo respalde. Por cierto, Src: Programación estructurada con ir a declaraciones, ACM Journal Computing Surveys, Vol 6, No. 4, diciembre de 1974. p.268. citeseerx.ist.psu.edu/viewdoc/…
mctylr
28
... Un buen programador no se dejará llevar por la complacencia por tal razonamiento, será sabio al mirar cuidadosamente el código crítico; pero solo después de que ese código ha sido identificado (resto de la cita más completa)
mctylr
21
Hoy tuve un usuario de 20k representantes que me dijo que usar una optimización en HashSetlugar de una Listera prematura. El caso de uso en cuestión era una colección estáticamente inicializada cuyo único propósito era servir como una tabla de consulta. No creo que me equivoque al decir que hay una distinción al seleccionar la herramienta adecuada para el trabajo versus la optimización prematura. Creo que su publicación confirma esta filosofía: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.la optimización de un HashSet se ha medido y documentado a fondo.
aplastar
99
@crush: sí: Settambién es más semánticamente correcto e informativo que List, por lo que hay más que el aspecto de optimización.
Erik Allik
77
Me gustaría agregar que la optimización prematura no debe confundirse con el diseño de toda la arquitectura de su aplicación para que se ejecute rápidamente en general, escale y sea fácilmente optimizable.
Erik Allik
111

Las micro optimizaciones prematuras son la raíz de todo mal, porque las micro optimizaciones dejan de lado el contexto. Casi nunca se comportan como se espera.

¿Cuáles son algunas buenas optimizaciones tempranas en el orden de importancia?

  • Optimizaciones arquitectónicas (estructura de la aplicación, la forma en que está compuesta y en capas)
  • Optimizaciones de flujo de datos (dentro y fuera de la aplicación)

Algunas optimizaciones del ciclo de desarrollo medio:

  • Estructuras de datos, introduzca nuevas estructuras de datos que tengan un mejor rendimiento o menos gastos generales si es necesario
  • Algoritmos (ahora es un buen momento para comenzar a decidir entre quicksort3 y heapsort ;-))

Algunas optimizaciones del ciclo de desarrollo final

  • Encontrar hotpots de código (bucles estrechos, que deberían optimizarse)
  • Optimizaciones basadas en perfiles de partes computacionales del código
  • Las micro optimizaciones se pueden realizar ahora, ya que se realizan en el contexto de la aplicación y su impacto se puede medir correctamente.

No todas las optimizaciones iniciales son malas, las micro optimizaciones son malas si se realizan en el momento equivocado del ciclo de vida del desarrollo , ya que pueden afectar negativamente a la arquitectura, pueden afectar negativamente a la productividad inicial, pueden ser irrelevantes en cuanto al rendimiento o incluso tener un efecto perjudicial al final de desarrollo debido a diferentes condiciones ambientales.

Si el rendimiento es motivo de preocupación (y siempre debería serlo), siempre piense en grande . El rendimiento es una imagen más grande y no se trata de cosas como: ¿debería usar int o long ? Vaya de arriba hacia abajo cuando trabaje con rendimiento en lugar de abajo hacia arriba .

Pop Catalin
fuente
"Optimización: tu peor enemigo", por Joseph M. Recién llegado: flounder.com/optimization.htm
Ron Ruble
53

La optimización sin la primera medición es casi siempre prematura.

Creo que eso es cierto en este caso, y cierto también en el caso general.

Jeff Atwood
fuente
¡Aquí Aquí! La optimización no considerada hace que el código no se pueda mantener y, a menudo, es la causa de problemas de rendimiento. por ejemplo, multiprocesas un programa porque imaginas que podría ayudar al rendimiento, pero la solución real habría sido múltiples procesos que ahora son demasiado complejos para implementar.
James Anderson
a menos que esté documentado.
nawfal
Si. totalmente de acuerdo. Primero tiene que medirse. No hay forma de saber dónde están los cuellos de botella hasta que pruebe algo de extremo a extremo y mida cada uno de los pasos.
Oliver Watkins
Las medidas pueden mentir. He visto a especialistas experimentados pasar semanas leyendo rastros y ejecutando perfiles para golpear una pared donde pensaban que no había nada más que ganar. Luego leí la totalidad del código y en unas pocas horas hice algunos cambios holísticos para obtener una mejora de 10 veces. Los perfiles no mostraban rutas de acceso porque todo el código estaba mal diseñado. También he visto a los perfiladores reclamar rutas de acceso donde no debería haber ninguna. Una persona que "midiera" habría optimizado el hotpath, pero debería haberse dado cuenta de que el hotpath era un síntoma de otro código deficiente.
Bengie
42

La optimización es "malvada" si causa:

  • código menos claro
  • significativamente más código
  • código menos seguro
  • tiempo perdido del programador

En su caso, parece que ya se dedicó un poco de tiempo al programador, el código no era demasiado complejo (una suposición de su comentario que todos los miembros del equipo podrían entender), y el código es un poco más a prueba de futuro (siendo hilo seguro ahora, si entendí tu descripción). Suena como un poco malvado. :)

John Mulder
fuente
44
Solo si el costo, según sus viñetas, es mayor que el valor amortizado entregado. A menudo, la complejidad introduce valor, y en estos casos uno puede encapsularlo de modo que pase sus criterios. También se reutiliza y continúa proporcionando más valor.
1
Esos dos primeros puntos son los principales para mí, y el cuarto punto es una consecuencia negativa de hacer una optimización prematura. En particular, es una señal de alerta cada vez que veo a alguien que vuelve a implementar características de una biblioteca estándar. Como, una vez vi a alguien implementar rutinas personalizadas para la manipulación de cadenas porque le preocupaba que los comandos integrados fueran demasiado lentos.
jhocking
8
Hacer que el hilo de código sea seguro no es optimización.
mattnz
38

Me sorprende que esta pregunta tenga 5 años y, sin embargo, nadie haya publicado más de lo que Knuth tenía que decir que un par de oraciones. Los dos párrafos que rodean la famosa cita lo explican bastante bien. El documento que se cita se llama " Programación estructurada con declaraciones ", y aunque tiene casi 40 años, trata sobre una controversia y un movimiento de software que ya no existen, y tiene ejemplos en lenguajes de programación que muchas personas nunca han visto. oído hablar, una cantidad sorprendentemente grande de lo que dijo todavía se aplica.

Aquí hay una cita más grande (de la página 8 del pdf, página 268 en el original):

La mejora en la velocidad del Ejemplo 2 al Ejemplo 2a es solo del 12%, y muchas personas lo considerarían insignificante. La sabiduría convencional compartida por muchos de los ingenieros de software actuales exige ignorar la eficiencia en lo pequeño; pero creo que esto es simplemente una reacción exagerada a los abusos que ven practicados por programadores tontos y que no pueden depurar o mantener sus programas "optimizados". En disciplinas de ingeniería establecidas, una mejora del 12%, obtenida fácilmente, nunca se considera marginal; y creo que el mismo punto de vista debería prevalecer en la ingeniería de software. Por supuesto, no me molestaría en hacer tales optimizaciones en un trabajo de una sola vez, pero cuando se trata de preparar programas de calidad, no quiero limitarme a las herramientas que me niegan tales eficiencias.

No hay duda de que el grial de la eficiencia conduce al abuso. Los programadores pierden enormes cantidades de tiempo pensando o preocupándose por la velocidad de las partes no críticas de sus programas, y estos intentos de eficiencia en realidad tienen un fuerte impacto negativo cuando se consideran la depuración y el mantenimiento. Nos debemos olvidar de pequeñas eficiencias, por ejemplo alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal.

Sin embargo, no debemos dejar pasar nuestras oportunidades en ese crítico 3%. Un buen programador no se dejará llevar por la complacencia por tal razonamiento, será sabio al mirar cuidadosamente el código crítico; pero solo después de que se haya identificado ese código. A menudo es un error hacer juicios a priori sobre qué partes de un programa son realmente críticas, ya que la experiencia universal de los programadores que han estado utilizando herramientas de medición ha sido que sus conjeturas intuitivas fallan.

Otra buena parte de la página anterior:

Mi propio estilo de programación, por supuesto, ha cambiado durante la última década, de acuerdo con las tendencias de los tiempos (por ejemplo, ya no soy tan complicado, y uso menos visitas), pero el cambio más importante en mi estilo se debe a a este fenómeno del bucle interno. Ahora miro con un ojo extremadamente icónico a cada operación en un ciclo interno crítico, buscando modificar mi programa y estructura de datos (como en el cambio del Ejemplo 1 al Ejemplo 2) para que algunas de las operaciones puedan ser eliminadas. Las razones de este enfoque son que: a) no toma mucho tiempo, ya que el ciclo interno es corto; b) la recompensa es real; y c) puedo permitirme ser menos eficiente en las otras partes de mis programas, que por lo tanto son más legibles y más fáciles de escribir y depurar.

Michael Shaw
fuente
20

A menudo he visto esta cita utilizada para justificar un código obviamente malo o un código que, si bien no se ha medido su rendimiento, probablemente podría hacerse más rápido con bastante facilidad, sin aumentar el tamaño del código o comprometer su legibilidad.

En general, creo que las primeras micro optimizaciones pueden ser una mala idea. Sin embargo, las macro optimizaciones (cosas como elegir un algoritmo O (log N) en lugar de O (N ^ 2)) a menudo valen la pena y deben hacerse temprano, ya que puede ser un desperdicio escribir un algoritmo O (N ^ 2) y luego bótelo completamente a favor de un enfoque O (log N).

Tenga en cuenta que las palabras pueden ser : si el algoritmo O (N ^ 2) es simple y fácil de escribir, puede tirarlo más tarde sin mucha culpa si resulta ser demasiado lento. Pero si ambos algoritmos son igualmente complejos, o si la carga de trabajo esperada es tan grande que ya sabe que necesitará el más rápido, la optimización temprana es una decisión de ingeniería sólida que reducirá su carga de trabajo total a largo plazo.

Por lo tanto, en general, creo que el enfoque correcto es averiguar cuáles son sus opciones antes de comenzar a escribir código y elegir conscientemente el mejor algoritmo para su situación. Lo más importante, la frase "la optimización prematura es la raíz de todo mal" no es excusa para la ignorancia. Los desarrolladores de carrera deberían tener una idea general de cuánto cuestan las operaciones comunes; deberían saber, por ejemplo,

  • que las cadenas cuestan más que los números
  • que los lenguajes dinámicos son mucho más lentos que los de tipo estático
  • Las ventajas de las listas de matrices / vectores sobre las listas enlazadas, y viceversa.
  • cuándo usar una tabla hash, cuándo usar un mapa ordenado y cuándo usar un montón
  • que (si funcionan con dispositivos móviles) "double" e "int" tienen un rendimiento similar en equipos de escritorio (FP puede ser incluso más rápido) pero "double" puede ser cien veces más lento en dispositivos móviles de gama baja sin FPU;
  • que la transferencia de datos a través de Internet es más lenta que el acceso al HDD, los HDD son mucho más lentos que la RAM, la RAM es mucho más lenta que la caché y los registros L1, y las operaciones de Internet pueden bloquearse indefinidamente (y fallar en cualquier momento).

Y los desarrolladores deben estar familiarizados con una caja de herramientas de estructuras de datos y algoritmos para que puedan usar fácilmente las herramientas adecuadas para el trabajo.

Tener muchos conocimientos y una caja de herramientas personal le permite optimizar casi sin esfuerzo. Poner mucho esfuerzo en una optimización que podría ser innecesaria es malo (y admito caer en esa trampa más de una vez). Pero cuando la optimización es tan fácil como elegir un conjunto / tabla hash en lugar de una matriz, o almacenar una lista de números en doble [] en lugar de cadena [], entonces ¿por qué no? Puede que no esté de acuerdo con Knuth aquí, no estoy seguro, pero creo que estaba hablando de optimización de bajo nivel, mientras que yo estoy hablando de optimización de alto nivel.

Recuerde, esa cita es originalmente de 1974. En 1974 las computadoras eran lentas y el poder de cómputo era costoso, lo que dio a algunos desarrolladores una tendencia a optimizar en exceso, línea por línea. Creo que contra eso estaba presionando Knuth. No decía "no te preocupes por el rendimiento en absoluto", porque en 1974 eso sería una locura. Knuth estaba explicando cómo optimizar; en resumen, uno debe enfocarse solo en los cuellos de botella, y antes de hacerlo debe realizar mediciones para encontrar los cuellos de botella.

Tenga en cuenta que no puede encontrar los cuellos de botella hasta que haya escrito un programa para medir, lo que significa que algunas decisiones de rendimiento deben tomarse antes de que exista algo para medir. A veces, estas decisiones son difíciles de cambiar si se equivocan. Por esta razón, es bueno tener una idea general de cuánto cuestan las cosas para que pueda tomar decisiones razonables cuando no hay datos disponibles.

Qué tan temprano para optimizar y cuánto preocuparse por el rendimiento dependen del trabajo. Al escribir scripts que solo ejecutará unas pocas veces, preocuparse por el rendimiento en general es una pérdida de tiempo completa. Pero si trabaja para Microsoft u Oracle y está trabajando en una biblioteca que miles de otros desarrolladores van a usar de miles de maneras diferentes, puede pagar para optimizar al máximo, de modo que pueda cubrir todos los diversos usar casos de manera eficiente. Aun así, la necesidad de rendimiento siempre debe equilibrarse con la necesidad de legibilidad, facilidad de mantenimiento, elegancia, extensibilidad, etc.

Qwertie
fuente
2
Amén. La optimización prematura es lanzada demasiado liberalmente en estos días por personas que intentan justificar el uso de la herramienta incorrecta para el trabajo. Si conoce la herramienta adecuada para el trabajo con anticipación, entonces no hay excusa para no usarla.
aplastar
13

Personalmente, como se cubrió en un hilo anterior , no creo que la optimización temprana sea mala en situaciones en las que sabes que tendrás problemas de rendimiento. Por ejemplo, escribo software de análisis y modelado de superficies, donde trato regularmente con decenas de millones de entidades. La planificación del rendimiento óptimo en la etapa de diseño es muy superior a la optimización tardía de un diseño débil.

Otra cosa a tener en cuenta es cómo escalará su aplicación en el futuro. Si considera que su código tendrá una larga vida útil, también es una buena idea optimizar el rendimiento en la etapa de diseño.

En mi experiencia, la optimización tardía proporciona recompensas exiguas a un alto precio. La optimización en la etapa de diseño, a través de la selección de algoritmos y ajustes, es mucho mejor. Dependiendo de un generador de perfiles para comprender cómo funciona su código no es una excelente manera de obtener un código de alto rendimiento, debe saberlo de antemano.

Shane MacLaughlin
fuente
Esto es ciertamente correcto. Supongo que la optimización prematura es cuando el código se hace más complejo / difícil de entender para obtener beneficios poco claros, de una manera que solo tiene un impacto local (el diseño tiene un impacto global).
Paul de Vrieze
2
Se trata de definiciones. Tomo la optimización como diseño y escritura de código para que funcione de manera óptima. La mayoría aquí parece tratarlo como pirateo con el código una vez que han descubierto que no es lo suficientemente rápido o eficiente. Paso mucho tiempo optimizando, generalmente durante el diseño.
3
Optimice el diseño al principio, optimice el código al final.
BCS
Tiene mucha razón en su caso, sin embargo, para la mayoría de los programadores, creen que tendrán problemas de rendimiento, pero en realidad nunca lo harán. Muchos se preocupan por el rendimiento cuando se trata de 1000 entidades, cuando una prueba básica de los datos muestra que el rendimiento está bien hasta que llegan a 1000000 entidades.
Toby Allen
1
"¡La planificación para un rendimiento óptimo en la etapa de diseño es muy superior a la optimización tardía de un diseño débil" y "la optimización tardía proporciona recompensas exiguas a un alto precio" muy bien dicho! Probablemente no sea cierto para el 97% de todos los sistemas producidos, pero es para muchos, desconcertantemente, muchos sistemas.
Olof Forshell
10

De hecho, aprendí que la no optimización prematura es más a menudo la raíz de todo mal.

Cuando la gente escribe software, inicialmente tendrá problemas, como inestabilidad, funciones limitadas, mala usabilidad y mal rendimiento. Todo esto generalmente se arregla cuando el software madura.

Todo esto, excepto el rendimiento. A nadie parece importarle el rendimiento. La razón es simple: si un software falla, alguien corregirá el error y eso es todo, si falta una característica, alguien lo implementará y listo, si el software tiene un mal rendimiento, en muchos casos no se debe a la falta de microoptimización, pero debido al mal diseño y nadie va a tocar el diseño del software. SIEMPRE.

Mira a Bochs. Es lento como el infierno. ¿Alguna vez será más rápido? Tal vez, pero solo en el rango de un pequeño porcentaje. Nunca obtendrá un rendimiento comparable al software de virtualización como VMWare o VBox o incluso QEMU. ¡Porque es lento por diseño!

Si el problema de un software es que es lento, entonces porque es MUY lento y esto solo se puede solucionar mejorando el rendimiento por una multitud. + 10% simplemente no hará que un software lento sea rápido. Y generalmente no obtendrá más del 10% con optimizaciones posteriores.

Entonces, si el rendimiento es CUALQUIERA importante para su software, debe tenerlo en cuenta desde el principio, al diseñarlo, en lugar de pensar "oh sí, es lento, pero podemos mejorarlo más adelante". ¡Porque no puedes!

Sé que eso realmente no se ajusta a su caso específico, pero responde a la pregunta general "¿Es la optimización prematura realmente la raíz de todo mal?" - con un claro NO.

Cada optimización, como cualquier característica, etc., debe diseñarse e implementarse cuidadosamente. Y eso incluye una evaluación adecuada de costo y beneficio. No optimice un algoritmo para guardar algunos ciclos aquí y allá, cuando no cree una ganancia de rendimiento medible.

Solo como un ejemplo: puede mejorar el rendimiento de una función al incluirla, posiblemente ahorrando un puñado de ciclos, pero al mismo tiempo, probablemente aumente el tamaño de su ejecutable, aumentando las posibilidades de fallas de TLB y caché que cuestan miles de ciclos o incluso operaciones de paginación, que matarán el rendimiento por completo. Si no comprende estas cosas, su "optimización" puede resultar mala.

La optimización estúpida es más malvada que la optimización "prematura", pero ambas son aún mejores que la no optimización prematura.

mosquito
fuente
6

Hay dos problemas con PO: en primer lugar, el tiempo de desarrollo que se usa para el trabajo no esencial, que podría usarse para escribir más funciones o corregir más errores, y en segundo lugar, la falsa sensación de seguridad de que el código se ejecuta de manera eficiente. PO a menudo implica optimizar el código que no va a ser el cuello de botella, sin darse cuenta del código que lo hará. El bit "prematuro" significa que la optimización se realiza antes de que se identifique un problema utilizando las medidas adecuadas.

Básicamente, sí, esto suena como una optimización prematura, pero no necesariamente lo retiraría a menos que presente errores, después de todo, ¡ahora se ha optimizado (!)

harriyott
fuente
¿Quieres decir "escribir más pruebas" en lugar de "escribir más funciones", verdad? :)
Greg Hewgill
1
más funciones implica más pruebas :)
workmad3
Er, si! Eso es exactamente lo que quise decir ...
harriyott
2
El código introduce una mayor complejidad y probablemente no se utilizará universalmente. Respaldarlo (y cosas similares) mantiene el código limpio.
Paul de Vrieze
3

Creo que es lo que Mike Cohn llama 'chapado en oro' el código, es decir, pasar tiempo en cosas que podrían ser agradables pero que no son necesarias.

Él aconsejó contra eso.

PS 'Gold-chapado' podría ser una especie de funcionalidad de campanas y silbatos en cuanto a especificaciones. Cuando observa el código, toma la forma de una optimización innecesaria, clases 'preparadas para el futuro', etc.

Ilya Kochetov
fuente
2
Creo que "chapado en oro" es diferente a las optimizaciones. Por lo general, las optimizaciones se tratan de tratar de obtener el mayor rendimiento, mientras que el "chapado en oro" se trata de agregar las "campanas y silbatos" (toda la funcionalidad adicional) que no es crítica para el producto pero que se ve / se siente genial.
Scott Dorman
3

Como no hay ningún problema para comprender el código, este caso podría considerarse como una excepción.

Pero, en general, la optimización conduce a un código menos legible y menos comprensible y debe aplicarse solo cuando sea necesario. Un ejemplo simple: si sabe que tiene que ordenar solo un par de elementos, utilice BubbleSort. Pero si sospecha que los elementos podrían aumentar y no sabe cuánto, entonces optimizar con QuickSort (por ejemplo) no es malo, sino imprescindible. Y esto debe considerarse durante el diseño del programa.

m_pGladiator
fuente
1
No estoy de acuerdo Yo diría que nunca uses un tipo de burbuja. Quicksort se ha convertido en un estándar de facto y se entiende bien, y es tan fácil de implementar como una burbuja en todos los escenarios. El mínimo común denominador ya no es tan bajo;)
1
Para un número realmente pequeño de elementos, la recursión requerida para la clasificación rápida puede hacerlo más lento que una clasificación de burbujas decente ... sin mencionar que una clasificación de burbujas es más rápida en el peor de los casos de clasificación rápida (es decir, clasificación rápida de una lista ordenada)
workmad3
sí, pero ese es solo un ejemplo de cómo seleccionar algoritmos para diferentes necesidades;)
Es cierto, pero tendría la clasificación rápida como mi clasificación predeterminada. Si pensara que bubbleort mejoraría el rendimiento, esto sería una optimización, no al revés. Elijo QuickSort como predeterminado porque se entiende bien y, en general, es mejor.
2
Mi idea de una ordenación predeterminada es lo que la biblioteca me da (qsort (), .sort (), (sort ...), lo que sea).
David Thornley
3

Descubrí que el problema con la optimización prematura ocurre principalmente cuando se reescribe el código existente para que sea más rápido. Puedo ver cómo podría ser un problema escribir una optimización enrevesada en primer lugar, pero sobre todo veo que la optimización prematura levanta su cabeza fea para arreglar lo que no está (se sabe que está) roto.

Y el peor ejemplo de esto es cuando veo que alguien vuelve a implementar características de una biblioteca estándar. Esa es una gran bandera roja. Como, una vez vi a alguien implementar rutinas personalizadas para la manipulación de cadenas porque le preocupaba que los comandos integrados fueran demasiado lentos.

Esto da como resultado un código que es más difícil de entender (malo) y gasta mucho tiempo en el trabajo que probablemente no sea útil (malo).

jhocking
fuente
3

Desde una perspectiva diferente, según mi experiencia, la mayoría de los programadores / desarrolladores no planean el éxito y el "prototipo" casi siempre se convierte en la Versión 1.0. Tengo experiencia de primera mano con 4 productos originales separados en los que el front-end con clase, sexy y altamente funcional (básicamente la interfaz de usuario) resultó en una amplia adopción y entusiasmo por parte de los usuarios. En cada uno de estos productos, los problemas de rendimiento comenzaron a aparecer en tiempos relativamente cortos (1 a 2 años), particularmente a medida que los clientes más grandes y exigentes comenzaron a adoptar el producto. Muy pronto, el rendimiento dominó la lista de problemas, aunque el desarrollo de nuevas características dominó la lista de prioridades de la administración. Los clientes se sintieron cada vez más frustrados a medida que cada versión agregaba nuevas características que sonaban geniales pero eran casi inaccesibles debido a problemas de rendimiento.

Por lo tanto, los defectos de diseño e implementación muy fundamentales que eran de poca o ninguna preocupación en el "tipo prototipo" se convirtieron en los principales obstáculos para el éxito a largo plazo de los productos (y las empresas).

La demostración de su cliente puede verse y funcionar muy bien en su computadora portátil con XML DOM, SQL Express y muchos datos en caché del lado del cliente. El sistema de producción probablemente bloqueará una quemadura si tiene éxito.

En 1976 todavía estábamos debatiendo las formas óptimas de calcular una raíz cuadrada u ordenar una gran matriz y el adagio de Don Knuth se dirigió al error de enfocarse en optimizar ese tipo de rutina de bajo nivel al principio del proceso de diseño en lugar de enfocarse en resolver el problema y luego optimizando regiones localizadas de código.

Cuando uno repite el adagio como una excusa para no escribir código eficiente (C ++, VB, T-SQL o de otro tipo), o para no diseñar adecuadamente el almacén de datos, o para no considerar la arquitectura de la red, entonces IMO solo están demostrando un comprensión muy superficial de la naturaleza real de nuestro trabajo. Rayo

Rayo
fuente
1
Jaja, o cuando la demo con tres usuarios se convierte en la versión 1.0 con mil.
Olof Forshell
1

Supongo que depende de cómo se defina "prematuro". Hacer que la funcionalidad de bajo nivel sea rápida cuando estás escribiendo no es inherentemente malo. Creo que es un malentendido de la cita. A veces pienso que esa cita podría servir para algo más de calificación. Sin embargo, haría eco de los comentarios de m_pGladiator sobre la legibilidad.

Dominic Rodger
fuente
1

La respuesta es, depende. Argumentaré que la eficiencia es un gran problema para ciertos tipos de trabajo, como las consultas complejas de bases de datos. En muchos otros casos, la computadora pasa la mayor parte del tiempo esperando la entrada del usuario, por lo que optimizar la mayoría del código es, en el mejor de los casos, una pérdida de esfuerzo y, en el peor de los casos, es contraproducente.

En algunos casos, puede diseñar por eficiencia o rendimiento (percibido o real), seleccionando un algoritmo apropiado o diseñando una interfaz de usuario para que ciertas operaciones costosas ocurran en segundo plano, por ejemplo. En muchos casos, la creación de perfiles u otras operaciones para determinar los puntos de acceso le brindarán un beneficio de 10/90.

Un ejemplo de esto que puedo describir es el modelo de datos que hice una vez para un sistema de gestión de casos judiciales que tenía alrededor de 560 tablas. Comenzó normalizado ('bellamente normalizado' como lo expresó el consultor de cierta firma de los 5 grandes) y solo tuvimos que agregar cuatro elementos de datos desnormalizados:

  • Una vista materializada para soportar una pantalla de búsqueda

  • Una tabla mantenida por disparador para admitir otra pantalla de búsqueda que no se pudo hacer con una vista materializada.

  • Una tabla de informes denormalizados (esto solo existía porque tuvimos que asumir algunos informes de rendimiento cuando un proyecto de almacén de datos se enlazó)

  • Una tabla mantenida por el disparador para una interfaz que tenía que buscar el más reciente de un gran número de eventos dispares dentro del sistema.

Este era (en ese momento) el proyecto J2EE más grande en Australasia, más de 100 años de tiempo de desarrollo, y tenía 4 elementos denormalizados en el esquema de la base de datos, uno de los cuales realmente no pertenecía allí en absoluto.

Preocupado por TunbridgeWells
fuente
1

La optimización prematura no es la raíz de TODO el mal, eso es seguro. Sin embargo, hay inconvenientes:

  • invierte más tiempo durante el desarrollo
  • inviertes más tiempo probándolo
  • invierte más tiempo reparando errores que de otra forma no estarían allí

En lugar de una optimización prematura, uno podría hacer pruebas de visibilidad tempranas para ver si existe una necesidad real de una mejor optimización.

Herr_Alien
fuente
1

La mayoría de los que se adhieren a "PMO" (la cita parcial, es decir) dicen que las optimizaciones deben basarse en mediciones y las mediciones no pueden realizarse hasta el final.

También es mi experiencia en el desarrollo de grandes sistemas que las pruebas de rendimiento se realizan al final, a medida que el desarrollo está por terminar.

Si siguiéramos los "consejos" de estas personas, todos los sistemas serían extremadamente lentos. También serían caros porque sus necesidades de hardware son mucho mayores de lo previsto originalmente.

Durante mucho tiempo he abogado por hacer pruebas de rendimiento a intervalos regulares en el proceso de desarrollo: indicará tanto la presencia de un nuevo código (donde anteriormente no había ninguno) como el estado del código existente.

  • El rendimiento del código recientemente implementado puede compararse con el del código existente existente. Con el tiempo se establecerá una "sensación" del rendimiento del nuevo código.
  • Si el código existente se vuelve loco de repente, comprende que le ha sucedido algo y puede investigarlo de inmediato, no (mucho) más tarde cuando afecta a todo el sistema.

Otra idea favorita es instrumentar el software en el nivel del bloque de funciones. A medida que el sistema se ejecuta, recopila información sobre los tiempos de ejecución de los bloques de funciones. Cuando se realiza una actualización del sistema, se puede determinar qué bloques de funciones funcionan como lo hicieron en la versión anterior y cuáles se han deteriorado. En la pantalla de un software, se puede acceder a los datos de rendimiento desde el menú de ayuda.

Echa un vistazo a esta excelente pieza sobre lo que PMO podría o no significar.

Olof Forshell
fuente