Limpie el código legible contra el código rápido y difícil de leer. ¿Cuándo cruzar la línea?

66

Cuando escribo un código, siempre trato de hacer que mi código sea lo más limpio y legible posible.

De vez en cuando llega un momento en el que necesitas cruzar la línea y pasar de un código limpio a un código un poco más feo para hacerlo más rápido.

¿Cuándo está bien cruzar esa línea?

    
pregunta Ken Cochrane 05.07.2011 - 03:28

10 respuestas

116

Cruzas la línea cuando

  • Ha medido que su código es demasiado lento para su uso previsto .
  • Has probado mejoras alternativas que no requieren eliminar el código.

Este es un ejemplo del mundo real: un sistema experimental que estoy ejecutando estaba produciendo datos muy lentamente, demorando más de 9 horas por ejecución y usando solo el 40% de la CPU. En lugar de desordenar el código demasiado, moví todos los archivos temporales a un sistema de archivos en memoria. Se agregaron 8 nuevas líneas de código no feo, y ahora la utilización de la CPU está por encima del 98%. Problema resuelto; no se requiere fealdad.

    
respondido por el Norman Ramsey 05.07.2011 - 04:14
57

Es una falsa dicotomía. Puede hacer que el código rápido y sea fácil de mantener.

La forma en que lo haces es escribirlo con claridad, especialmente con una estructura de datos tan simple como sea posible.

Luego descubres dónde están los drenajes de tiempo (ejecutándolo, después lo has escrito, no antes), Y arreglarlos uno por uno. (Aquí hay un ejemplo.)

Añadido: siempre escuchamos sobre compensaciones, ¿verdad, como una compensación entre el tiempo y la memoria, o una compensación entre la velocidad y la capacidad de mantenimiento? Si bien tales curvas pueden existir, no debe asumirse que cualquier programa dado está en la curva , o incluso en cualquier lugar cercano.

Cualquier programa que esté en la curva se puede hacer fácilmente (dándole a un cierto tipo de programador) mucho más lento y menos fácil de mantener, y luego no estará cerca de la curva. Dicho programa tiene mucho espacio para ser más rápido y más fácil de mantener.

En mi experiencia, ahí es donde comienzan muchos programas.

    
respondido por el Mike Dunlavey 05.07.2011 - 04:22
31

En mi existencia OSS hago mucho trabajo de biblioteca orientado al rendimiento, que está profundamente ligado a la estructura de datos de persona que llama (es decir, externa a la biblioteca), con (por diseño) sin mandato sobre los tipos entrantes. Aquí, la mejor manera de hacer que este rendimiento sea una meta-programación, que (ya que estoy en .NET-land) significa IL-emit. Eso es un código feo y feo, pero muy rápido.

De esta manera, acepto felizmente que el código de biblioteca puede ser "más feo" que el código de aplicación , simplemente porque tiene menos (o quizás no) ) control sobre las entradas , por lo que debe lograr algunas tareas a través de diferentes mecanismos. O como lo expresé el otro día:

  

"codificando sobre el acantilado de la locura, para que no tengas que hacerlo "

El código de

Ahora aplicación es ligeramente diferente, ya que es donde los desarrolladores "normales" (sanos) suelen invertir gran parte de su tiempo de colaboración / profesional; Los objetivos y expectativas de cada uno son (IMO) ligeramente diferentes.

OMI, las respuestas anteriores que sugieren que pueden ser rápidas y fáciles de mantener se refieren al código de aplicación donde el desarrollador tiene más control sobre las estructuras de datos, y No está utilizando herramientas como la meta-programación. Dicho esto, hay diferentes formas de realizar una meta-programación, con diferentes niveles de locura y diferentes niveles de sobrecarga. Incluso en ese ámbito, debe elegir el nivel apropiado de abstracción. Pero cuando desea activamente, de manera positiva y genuina, maneje datos inesperados de la manera más rápida y absoluta; bien puede ponerse feo Lidiar con eso; p

    
respondido por el Marc Gravell 05.07.2011 - 08:12
26

Cuando haya perfilado el código y verificado que realmente está causando una desaceleración significativa.

    
respondido por el Joel Rein 05.07.2011 - 03:30
13

El código limpio no es necesariamente exclusivo con el código de ejecución rápida. Normalmente, el código difícil de leer se escribía porque era más rápido de escribir, no porque se ejecuta más rápido.

Escribir código "sucio" en un intento de hacerlo más rápido es discutiblemente imprudente, ya que no sabes con certeza que tus cambios realmente mejoren nada. Knuth lo puso mejor:

  

"Debemos olvidarnos de las pequeñas eficiencias, digamos que aproximadamente el 97% del tiempo: la optimización prematura es la raíz de todos los males . Sin embargo, no debemos dejar pasar nuestras oportunidades en ese 3% crítico. A un buen razonador no se sentirá complacido con este razonamiento, será prudente que examine detenidamente el código crítico; pero solo después de que ese código haya sido identificado ".

En otras palabras, primero escribe el código limpio. Luego, haga un perfil del programa resultante y vea si ese segmento es, de hecho, un cuello de botella en el rendimiento. Si es así, optimice la sección según sea necesario y asegúrese de incluir muchos comentarios de documentación (posiblemente incluyendo el código original) para explicar las optimizaciones. Luego, haga un perfil del resultado para verificar que realmente realizó una mejora.

    
respondido por el tylerl 05.07.2011 - 09:19
10

Dado que la pregunta dice "rápido código difícil de leer ", la respuesta simple nunca es. Nunca hay una excusa para escribir un código que sea difícil de leer. ¿Por qué? Dos razones.

  1. ¿Qué sucede si te atropella un autobús en tu camino a casa esta noche? ¿O (más optimista, y más típicamente) retirado de este proyecto y reasignado a otra cosa? El pequeño beneficio que imaginas que has obtenido con tu enredo de códigos se ve totalmente superado por el hecho de que nadie más puede entenderlo . El riesgo que esto representa para los proyectos de software es difícil de exagerar. Trabajé una vez con un importante fabricante de PBX (si trabaja en una oficina, es probable que tenga uno de sus teléfonos en su escritorio). Su gerente de proyecto me dijo un día que su producto principal, el software propietario que convirtió una caja estándar de Linux en un intercambio de teléfono con todas las funciones, era conocido dentro de la empresa como "la burbuja". Nadie lo entendió más. Cada vez que implementan una nueva característica. golpearon la compilación, luego retrocedieron, cerraron los ojos, contaron hasta veinte y luego se asomaron entre los dedos para ver si funcionaba. Ninguna empresa necesita un producto central que ya no controle, pero es un escenario muy común.
  2. ¡Pero necesito optimizar! Bien, entonces ha seguido todos los consejos excelentes en otras respuestas a esta pregunta: su código está fallando en sus casos de prueba de rendimiento, lo ha perfilado cuidadosamente, ha identificado los cuellos de botella. , proponga una solución ... y va a implicar algo de bit-twiddling . Bien: ahora adelante y optimiza. Pero aquí está el secreto (y es posible que desee sentarse para este): la optimización y la reducción en el tamaño del código fuente no son lo mismo . Los comentarios, los espacios en blanco, los corchetes y los nombres de variables significativos son ayudas enormes para la legibilidad que no le cuestan absolutamente nada porque el compilador los tirará. (O si está escribiendo un lenguaje no compilado como JavaScript, y sí, hay razones muy válidas para optimizar JavaScript; pueden tratarse con un compressor .) Largas líneas de código minimalista y abarrotado (como el que muntoo ha publicado aquí ) no tienen nada que ver con la optimización: ese es un programador que intenta mostrar lo inteligentes que son están empaquetando tanto código en la menor cantidad de caracteres posible. Eso no es inteligente, es estúpido. Un programador verdaderamente inteligente es aquel que puede comunicar sus ideas claramente a los demás.
respondido por el Mark Whitaker 05.07.2011 - 09:18
4

Cuando es código desechable. Lo digo literalmente: cuando escribes un script para realizar un cálculo o tarea de una sola vez, y sabes con tanta certeza que nunca tendrás que hacer esa acción otra vez para poder 'recuperar el archivo de origen' sin dudarlo, luego puedes elegir la ruta fea.

De lo contrario, es una falsa dicotomía: si crees que necesitas hacerlo más rápido para hacerlo más rápido, lo estás haciendo mal. (O sus principios sobre lo que es un buen código necesitan revisión. El uso de goto es, de hecho, bastante elegante cuando es la solución adecuada al problema. Sin embargo, rara vez lo es.)

    
respondido por el maaku 05.07.2011 - 06:49
3

Siempre que el costo estimado de un menor rendimiento en el mercado sea mayor que el costo estimado de mantenimiento del código para el módulo de código en cuestión.

La gente todavía hace SSE / NEON / etc codificados a mano. Ensamblaje para intentar vencer al software de algunos competidores en el popular chip de CPU de este año.

    
respondido por el hotpaw2 05.07.2011 - 04:50
3

No olvide que puede hacer que el código difícil de leer sea fácil de entender mediante la documentación y los comentarios adecuados.

En general, el perfil después de haber escrito un código fácil de leer que realiza la función deseada. Los cuellos de botella pueden requerir que hagas algo que lo haga parecer más complicado, pero puedes solucionarlo explicándote a ti mismo.

    
respondido por el Carlos 05.07.2011 - 10:59
0

Para mí es una proporción de estabilidad (como en cemento cementado, arcilla cocida en el horno, encerado en piedra, escrito con tinta permanente). Cuanto más inestable sea su código, ya que cuanto mayor sea la probabilidad de que necesite cambiarlo en el futuro, más fácilmente será flexible, como la arcilla húmeda, para mantenerse productivo. También hago hincapié en la flexibilidad y no legibilidad. Para mí, la facilidad para cambiar el código es más importante que la facilidad para leerlo. El código puede ser fácil de leer y una pesadilla para cambiar, y ¿de qué sirve poder leer y entender fácilmente los detalles de la implementación si son una pesadilla para cambiar? A menos que sea solo un ejercicio académico, normalmente el punto de poder entender fácilmente el código en una base de código de producción es con la intención de poder cambiarlo más fácilmente según sea necesario. Si es difícil de cambiar, muchos de los beneficios de la legibilidad salen por la ventana. La legibilidad solo es generalmente útil en el contexto de la flexibilidad, y la flexibilidad solo es útil en el contexto de la inestabilidad.

Naturalmente, incluso el código más difícil de mantener imaginable, independientemente de lo fácil o difícil que sea leerlo, no plantea un problema si nunca hay una razón para cambiarlo, solo úselo. Y es posible lograr tal calidad, especialmente para el código de sistema de bajo nivel donde el desempeño a menudo tiende a contar más. Tengo un código C que todavía utilizo con regularidad, que no ha cambiado desde finales de los 80. No ha necesitado cambiar desde entonces. El código es fugaz, escrito en los días en que se jugueteaban los bits, y apenas lo entiendo. Sin embargo, todavía es aplicable hoy en día, y no necesito entender su implementación para aprovecharla al máximo.

Escribir pruebas a fondo es una forma de mejorar la estabilidad. Otro es el desacoplamiento. Si su código no depende de nada más, entonces la única razón para que cambie es si él mismo necesita cambiar. A veces, una pequeña cantidad de duplicación de código puede servir como un mecanismo de desacoplamiento para mejorar drásticamente la estabilidad de una manera que lo convierte en un intercambio digno si, a cambio, obtiene un código que ahora es completamente independiente de cualquier otra cosa. Ahora ese código es invulnerable a los cambios en el mundo exterior. Mientras tanto, el código que depende de 10 bibliotecas externas diferentes tiene 10 veces más razones para cambiar en el futuro.

Otra cosa útil en la práctica es separar su biblioteca de las partes inestables de su base de código, posiblemente incluso compilándola por separado, como podría hacer con bibliotecas de terceros (que también están destinadas a ser utilizadas, no modificadas, al menos no por tu equipo). Solo ese tipo de organización puede evitar que las personas lo manipulen.

Otro es el minimalismo. Cuanto menos intente hacer su código, más probable será que pueda hacer lo que hace bien. Los diseños monolíticos son casi permanentemente inestables, ya que a medida que se les agrega más y más funcionalidad, más incompletos parecen.

La estabilidad debe ser su objetivo principal siempre que intente escribir un código que, inevitablemente, será difícil de cambiar, como el código SIMD paralelizado que ha sido micro-sintonizado hasta la muerte. Contrarresta la dificultad de mantener el código al maximizar la probabilidad de que no tenga que cambiar el código y, por lo tanto, no tendrá que mantenerlo en el futuro. Eso reduce los costos de mantenimiento a cero, sin importar lo difícil que sea mantener el código.

    
respondido por el user204677 08.12.2017 - 02:24

Lea otras preguntas en las etiquetas