¿Debe un desarrollador apuntar primero a la legibilidad o al rendimiento? [cerrado]

82

A menudo, un desarrollador se enfrentará a la elección entre dos formas posibles de resolver un problema: una que sea idiomática y legible y otra que sea menos intuitiva, pero que funcione mejor. Por ejemplo, en los lenguajes basados ​​en C, hay dos formas de multiplicar un número por 2:

int SimpleMultiplyBy2(int x)
{
    return x * 2; 
}

y

int FastMultiplyBy2(int x)
{
    return x << 1;
}

La primera versión es más sencilla de adquirir para lectores técnicos y no técnicos, pero la segunda puede funcionar mejor, ya que el desplazamiento de bits es una operación más sencilla que la multiplicación. (Por ahora, supongamos que el optimizador del compilador no detectaría esto ni lo optimizaría, aunque eso también es una consideración).

Como desarrollador, ¿cuál sería mejor como intento inicial?

JohnMcG
fuente
Un poco duro. Buena pregunta sobre una preocupación que todos tenemos en ocasiones. +1
Inisheer
3
Este ejemplo es obviamente artificial y trivial. Realmente no tendría una función con un multiplicador codificado.
JohnMcG
1
El punto es que veo muchas preguntas como "¿<funciona mejor que <=?" Ésta es la pregunta incorrecta: la pregunta correcta (la primera) es cuál es idiomática o convencional, luego preocuparse por el rendimiento.
JohnMcG
1
Esta es una de las mejores preguntas que he leído en stackoverflow. Esto llega a la esencia de cómo funcionan las computadoras, no solo a la semántica del lenguaje. +1
WolfmanDragon
2
@OutlawLemur Soy consciente de eso. Pero algunas personas preguntan si sería mejor, por ejemplo, construir bucles usando <o <= (con el valor de comparación incrementado de antemano en el último caso).
JohnMcG

Respuestas:

108

Te perdiste uno.

Primero codifique para la corrección, luego para la claridad (¡los dos a menudo están conectados, por supuesto!). Finalmente, y solo si tiene evidencia empírica real de que realmente necesita, puede considerar la optimización. La optimización prematura es realmente mala. La optimización casi siempre le cuesta tiempo, claridad y facilidad de mantenimiento. Será mejor que se asegure de comprar algo que valga la pena con eso.

Tenga en cuenta que los buenos algoritmos casi siempre superan la afinación localizada. No hay ninguna razón por la que no pueda tener un código correcto, claro y rápido. Sin embargo, tendrás una suerte irracional de llegar allí comenzando concentrándote en "rápido".

simon
fuente
Esta es de lejos la mejor respuesta aquí. Modifica el algoritmo, no el código. Con cambios sutiles, puedo hacer que un jscript Sieve of Erastosthenes supere a una versión de C ++ idéntica. (No el tamiz de Atkins, mi propio método.)
Peter Wone
2
Lástima que no puedas marcar como favorito las respuestas. :)
Sandor Davidhazi
59

En mi opinión, la versión legible obvia primero, hasta que se mida el rendimiento y se requiera una versión más rápida.

Kenny
fuente
Estoy de acuerdo. El año pasado implementé un componente importante como parte del código base de Java del lado del servidor de mi empresa e hice todo lo posible para hacerlo legible. Más tarde resultó que había problemas de rendimiento e hizo una revisión importante de su diseño que condujo a algo que es un poco menos legible de alguna manera.
Ryan Delucchi
46

Tómalo de Don Knuth

La optimización prematura es la raíz de todos los males (o al menos la mayoría) en la programación.

Ryan
fuente
La cita no es de Don en sí, sino de Hoare. Don acaba de hacerlo popular. Consulte wikipedia.
Kohlerm
1
Y es una cita selectiva de una cláusula de un párrafo completo, que contiene algunas salvedades muy importantes.
Marqués de Lorne
19

Legibilidad 100%

Si su compilador no puede hacer la optimización "x * 2" => "x << 1" por usted - ¡obtenga un nuevo compilador!

También recuerde que el 99,9% del tiempo de su programa se gasta esperando la entrada del usuario, esperando las consultas de la base de datos y esperando las respuestas de la red. A menos que esté haciendo los múltiples 20 bajillones de veces, no se notará.

James Curran
fuente
8

En su ejemplo dado, el 99,9999% de los compiladores generarán el mismo código para ambos casos. Lo que ilustra mi regla general: escriba primero para mejorar la legibilidad y el mantenimiento, y optimizar solo cuando sea necesario.

Paul Tomblin
fuente
Los compiladores de C compilarán en un código ensamblador diferente para los dos ejemplos mostrados. El primero crea un bucle, mientras que el segundo crea una instrucción de desplazamiento a la izquierda. Esto debería ser cierto para todos los compiladores de estilo C, ya que no he probado cada uno, no puedo hacer promesas al respecto.
WolfmanDragon
Para este ejemplo específico, ciertamente. Hay muchos casos en los que eso no es así, por lo que la pregunta general sigue siendo buena
Mark Baker
@WolfmanDragon, ¿de qué diablos estás hablando? ¿Por qué "* 2" generaría un bucle? Cuando lo intento con "gcc -O2 -s", obtengo instrucciones adicionales en ambos casos.
Paul Tomblin
1
Si su compilador crea un bucle en esa función, ¡le recomiendo que obtenga otro compilador!
Martin Vilcans
8

Legibilidad segura. No se preocupe por la velocidad a menos que alguien se queje

Millas
fuente
8

Legibilidad.

La codificación para el rendimiento tiene su propio conjunto de desafíos. Joseph M. Newcomer lo dijo bien

La optimización solo importa cuando importa. Cuando importa, importa mucho, pero hasta que sepa que es importante, no pierda mucho tiempo haciéndolo. Incluso si sabe que es importante, necesita saber dónde es importante. Sin datos de rendimiento, no sabrá qué optimizar y probablemente optimizará lo incorrecto.

El resultado será oscuro, difícil de escribir, difícil de depurar y difícil de mantener un código que no resuelve su problema. Por tanto, tiene la doble desventaja de (a) aumentar los costes de desarrollo y mantenimiento del software, y (b) no tener ningún efecto en el rendimiento.

nwahmaet
fuente
5

Legibilidad. El momento de optimizar es cuando llegue a la prueba beta. De lo contrario, nunca sabrá realmente en qué necesita dedicar el tiempo.

Yo no
fuente
5

Primero buscaría la legibilidad . Teniendo en cuenta el hecho de que con el tipo de lenguajes optimizados y las máquinas enormemente cargadas que tenemos en estos días, la mayor parte del código que escribimos de manera legible funcionará decentemente.

En algunos escenarios muy raros, donde está bastante seguro de que va a tener un cuello de botella de rendimiento (puede ser de algunas malas experiencias pasadas), y logró encontrar algún truco extraño que puede brindarle una gran ventaja de rendimiento, puede optar por ese. Pero deberías comentar muy bien ese fragmento de código, lo que ayudará a que sea más legible.

Vijesh VP
fuente
4

Un factor que a menudo se pasa por alto en este debate es el tiempo extra que necesita un programador para navegar, comprender y modificar el código menos legible. Teniendo en cuenta que el tiempo de un programador es de cien dólares la hora o más, este es un costo muy real.
Cualquier ganancia de rendimiento se contrarresta con este costo adicional directo en el desarrollo.

Rik
fuente
4

Poner un comentario allí con una explicación lo haría legible y rápido.

Realmente depende del tipo de proyecto y de la importancia del desempeño. Si está construyendo un juego en 3D, generalmente hay muchas optimizaciones comunes que querrá agregar en el camino, y no hay razón para no hacerlo (simplemente no se deje llevar demasiado pronto). Pero si está haciendo algo complicado, coméntelo para que cualquiera que lo mire sepa cómo y por qué lo está haciendo.

Gerald
fuente
3

La respuesta depende del contexto. En la programación de controladores de dispositivos o en el desarrollo de juegos, por ejemplo, la segunda forma es un idioma aceptable. En aplicaciones empresariales, no tanto.

Su mejor opción es mirar alrededor del código (o en aplicaciones exitosas similares ) para verificar cómo lo hacen otros desarrolladores.

ilitirit
fuente
3

utilizando << sería mediante una micro optimización. Entonces la regla de Hoare (no Knuts):

La optimización prematura es la raíz de todos los males.

se aplica y debería utilizar la versión más legible en primer lugar.

Esta es la regla, en mi humilde opinión, a menudo se usa mal como excusa para diseñar software que nunca se puede escalar o funcionar bien.

Kohlerm
fuente
3

Ambos. Su código debe equilibrar ambos; legibilidad y rendimiento. Porque ignorar cualquiera de los dos arruinará el ROI del proyecto, que al final del día es todo lo que le importa a su jefe.

La mala legibilidad da como resultado una menor capacidad de mantenimiento, lo que resulta en más recursos gastados en mantenimiento, lo que resulta en un ROI más bajo.

Un mal desempeño da como resultado una disminución de la inversión y de la base de clientes, lo que se traduce en un menor ROI.

Kon
fuente
2

Cuanto más grande sea la base de código, más legibilidad es crucial. Tratar de entender alguna función diminuta no es tan malo. (Especialmente porque el nombre del método en el ejemplo te da una pista). No es tan bueno para una pieza épica de súper código escrito por el genio solitario que acaba de dejar de codificar porque finalmente ha visto la parte superior de la complejidad de su habilidad y es lo que acaba de hacer. escribió para usted y nunca lo entenderá.

mspmsp
fuente
2

Si le preocupa la legibilidad de su código, no dude en agregar un comentario para recordar qué y por qué está haciendo esto.

Michael McCarty
fuente
1

El desplazamiento de bits frente a la multiplicación es una optimización trivial que no gana casi nada . Y, como se ha señalado, su compilador debería hacer eso por usted. Aparte de eso, la ganancia es despreciable de todos modos, al igual que la CPU en la que se ejecuta esta instrucción.

Por otro lado, si necesita realizar cálculos serios, necesitará las estructuras de datos adecuadas. Pero si su problema es complejo, averiguarlo es parte de la solución. Como ilustración, considere buscar un número de identificación en una matriz de 1000000 objetos sin clasificar. Luego reconsidere el uso de un árbol binario o un mapa hash.

Pero las optimizaciones como n << C suelen ser despreciables y triviales para cambiar en cualquier momento. Hacer que el código sea legible no lo es.

mstrobl
fuente
1

Depende de la tarea a resolver. Por lo general, la legibilidad es más importante, pero todavía hay algunas tareas en las que debe pensar en el rendimiento en primer lugar. Y no puede dedicar un día o dedicarse a la creación de perfiles y la optimización después de que todo funcione a la perfección, porque la optimización en sí misma puede requerir reescribir una parte suficiente de un código desde cero. Pero no es común hoy en día.

Akalenuk
fuente
1

Siempre debe optimizar al máximo, el rendimiento siempre cuenta. La razón por la que tenemos bloatware hoy en día es que la mayoría de los programadores no quieren hacer el trabajo de optimización.

Habiendo dicho eso, siempre puede poner comentarios donde la codificación ingeniosa necesita aclaración.

Lance Roberts
fuente
Estoy de acuerdo en cierto nivel. No creo que debas poner micro optimizaciones como se dijo en la pregunta original. Debe diseñar su sistema de tal manera que utilice los recursos de manera óptima. Hay mucho más rendimiento que ganar en ese campo.
Erik van Brakel
Hoy tenemos bloatware, pero no culpo a la falta de optimización. Lo culpo al diseño excesivo, aplastar moscas con bazucas, construir transatlánticos cuando solo se necesitan botes de remos. Entonces, por supuesto, es pesado.
Mike Dunlavey
Estoy de acuerdo con ambos en que la optimización del diseño es la primera prioridad. También diría que esa misma actitud debería aplicarse a todos los niveles del proceso de ingeniería de software. Si no se molesta en hacer la optimización a nivel de código, probablemente también le falte durante el diseño.
Lance Roberts
1

No tiene sentido optimizar si no conoce sus cuellos de botella. Es posible que haya hecho una función increíblemente eficiente (generalmente a expensas de la legibilidad hasta cierto punto) solo para descubrir que esa parte del código casi nunca se ejecuta, o está gastando más tiempo en el disco o la base de datos de lo que nunca ahorrará bits. Por lo tanto, no puede microoptimizar hasta que tenga algo que medir, y luego podría comenzar por la legibilidad. Sin embargo, debe tener en cuenta tanto la velocidad como la comprensibilidad al diseñar la arquitectura general, ya que ambos pueden tener un impacto masivo y ser difíciles de cambiar (según el estilo de codificación y las metodologías).

ICR
fuente
1

Se estima que alrededor del 70% del costo del software está en mantenimiento. La legibilidad hace que un sistema sea más fácil de mantener y, por lo tanto, reduce el costo del software durante su vida útil.

Hay casos en los que el rendimiento es más importante que la legibilidad, que dicen que son pocos y distantes entre sí.

Antes de sacrificar la legibilidad, piense "¿Estoy (o su empresa) preparado para hacer frente al costo adicional que estoy agregando al sistema al hacer esto?"

Peter Tomlins
fuente
1

No trabajo en Google, así que optaría por la opción del mal. (mejoramiento)

En el capítulo 6 de "Programming Pearls" de Jon Bentley, describe cómo un sistema se aceleró 400 veces mediante la optimización en 6 niveles de diseño diferentes. Creo que al no preocuparse por el rendimiento en estos 6 niveles de diseño, los implementadores modernos pueden lograr fácilmente 2-3 órdenes de magnitud de desaceleración en sus programas.

caballo de papel
fuente
1

Como casi todos dijeron en sus respuestas, prefiero la legibilidad . 99 de cada 100 proyectos que ejecuto no tienen requisitos de tiempo de respuesta estrictos, por lo que es una elección fácil.

Antes incluso de empezar a codificar, ya debería saber la respuesta. Algunos proyectos tienen ciertos requisitos de rendimiento, como "es necesario poder ejecutar la tarea X en Y (mili) segundos". Si ese es el caso, tienes un objetivo por el que trabajar y sabes cuándo tienes que optimizar o no. (con suerte) esto se determina en la etapa de requisitos de su proyecto, no al escribir el código.

La buena legibilidad y la capacidad de optimizar más adelante son el resultado de un diseño de software adecuado. Si su software tiene un diseño sólido, debería poder aislar partes de su software y reescribirlas si es necesario, sin romper otras partes del sistema. Además, la mayoría de los casos de optimización verdaderos que he encontrado (ignorando algunos trucos reales de bajo nivel, esos son incidentales) han sido cambiar de un algoritmo a otro, o almacenar datos en la memoria caché en lugar de en el disco / red.

Erik van Brakel
fuente
1

La legibilidad es el PRIMER objetivo.

En la década de 1970, el ejército probó algunas de las entonces "nuevas" técnicas de desarrollo de software (diseño de arriba hacia abajo, programación estructurada, equipos de programadores principales, por nombrar algunos) para determinar cuál de ellas marcaba una diferencia estadísticamente significativa.

LA ÚNICA técnica que marcó una diferencia estadísticamente significativa en el desarrollo fue ...

AÑADIR LÍNEAS EN BLANCO al código del programa.

La mejora en la legibilidad en esos códigos preestructurados y orientados a objetos fue la única técnica en estos estudios que mejoró la productividad.

==============

La optimización solo debe abordarse cuando todo el proyecto se haya probado unitariamente y esté listo para la instrumentación. Nunca se sabe DÓNDE necesita optimizar el código.

En sus libros emblemáticos Kernigan y Plauger de finales de la década de 1970 SOFTWARE TOOLS (1976) y SOFTWARE TOOLS IN PASCAL (1981) mostraron formas de crear programas estructurados utilizando un diseño de arriba hacia abajo. Crearon programas de procesamiento de texto: editores, herramientas de búsqueda, preprocesadores de código.

Cuando se INSTRUMENTÓ la función de formateo de texto completa, descubrieron que la mayor parte del tiempo de procesamiento se gastaba en tres rutinas que realizaban la entrada y salida de texto (en el libro original, las funciones io ocupaban el 89% del tiempo. En el libro pascal, estas funciones consumido 55%!)

Pudieron optimizar estas TRES rutinas y produjeron los resultados de un mayor rendimiento con un tiempo y un costo de desarrollo razonables y manejables.

SystemSmith
fuente
1

Primero la legibilidad. Pero incluso más que legibilidad es simplicidad, especialmente en términos de estructura de datos.

Recuerdo a un estudiante que estaba haciendo un programa de análisis de la visión, que no podía entender por qué era tan lento. Simplemente siguió las buenas prácticas de programación: cada píxel era un objeto y funcionaba enviando mensajes a sus vecinos ...

mira esto

Mike Dunlavey
fuente
1

Si no hay legibilidad, será muy difícil obtener una mejora del rendimiento cuando realmente la necesite.

El rendimiento solo debe mejorarse cuando sea un problema en su programa, hay muchos lugares donde sería un cuello de botella en lugar de esta sintaxis. Digamos que está aplastando la mejora de 1ns en un << pero ignoró ese tiempo de 10 minutos IO.

Además, con respecto a la legibilidad, un programador profesional debe poder leer / comprender términos de informática. Por ejemplo, podemos nombrar un método enqueue en lugar de tener que decir putThisJobInWorkQueue.

Yuan
fuente
Si bien estoy de acuerdo, creo que tienes un mal ejemplo. Por ejemplo, como alguien que no sabe nada sobre su código base, poner en cola significa menos para mí. No quiero saber cómo, quiero saber qué. El ejemplo que dio dice mucho mejor.
Shaun Sweet
0

Primero escriba para facilitar la lectura, pero espere que los lectores sean programadores . Cualquier programador que se precie debería saber la diferencia entre una multiplicación y un desplazamiento de bits, o ser capaz de leer el operador ternario donde se usa apropiadamente, ser capaz de buscar y comprender un algoritmo complejo (estás comentando tu código, ¿verdad? ), etc.

La sobreoptimización temprana es, por supuesto, bastante mala para meterte en problemas más adelante cuando necesites refactorizar, pero eso realmente no se aplica a la optimización de métodos individuales, bloques de código o declaraciones.

wprl
fuente
0

Yo diría que busque legibilidad.

Pero en el ejemplo dado, creo que la segunda versión ya es lo suficientemente legible, ya que el nombre de la función indica exactamente lo que está sucediendo en la función.

Si siempre tuviéramos funciones que nos dijeran, qué hacen ...

Dan jabón
fuente
0

¿Cuánto cuesta una hora de tiempo de procesador?

¿Cuánto cuesta una hora de tiempo de programador?

Andy Lester
fuente
¿Cuánto cuesta una hora de tiempo de usuario final? ahora mutip que por el número de usuarios.
gbjbaanb
gbjbaanb: Mis pensamientos exactamente. El comentario de Andy solo funciona para servicios que el usuario final nunca verá, e incluso así no es una buena comparación.
Erik van Brakel
0

En mi humilde opinión, ambas cosas no tienen nada que hacer. Primero debe buscar un código que funcione, ya que es más importante que el rendimiento o lo bien que se lee. Respecto a la legibilidad: su código siempre debe ser legible en cualquier caso.

Sin embargo, no veo por qué el código no se puede leer y ofrecer un buen rendimiento al mismo tiempo. En su ejemplo, la segunda versión es tan legible como la primera para mí. ¿Qué tiene de menos legible? Si un programador no sabe que desplazar a la izquierda es lo mismo que multiplicar por una potencia de dos y desplazar a la derecha es lo mismo que dividir por una potencia de dos ... bueno, entonces tienes muchos más problemas básicos que la legibilidad general.

Mecki
fuente