Un enfoque ágil para la optimización

OptimizacionCuando empecé en esto de la programación, las aplicaciones eran mucho más sencillas desde el punto de vista arquitectonico y la optimización de las mismas era un oscuro arte que solo algunos programadores dominaban basado en conocer ciertos trucos o ser capaces de generar código en ensamblador mejor que el compilador. El rendimiento de la aplicación se obtenía a base de mejoras de implementación, o incluso derivaban de usar un lenguaje u otro (quien no ha escrito un componente en C++ para llamarlo desde VB por cuestiones de rendimiento), no tanto de temas de arquitectura. Además no existían (o no eran tan populares) los profilers y el proceso de optimización era puramente artesanal. Solo aquellas aplicaciones que tenían unos requisitos muy fuertes de rendimiento eran optimizadas de manera formal pues el coste de optimizar era muy alto. Cómo optimizar a posteriori era algo muy costoso, muchos desarrolladores caían en el demonio de la optimización temprana, tratando de hacer optima cada línea de código, sacrificando otros aspectos como la legibilidad, la mantenibilidad o la velocidad de desarrollo.

Este panorama ha cambiado radicalmente en los últimos tiempos. Los motores de este cambio radical han sido la mayor complejidad de las arquitecturas, la aparición de las máquinas virtuales de ejecución y la popularización de los profilers.

La mayor complejidad de las arquitecturas ha propiciado que las mayores ganancias en rendimiento se obtengan de una buena arquitectura, más que de detalles de implementación. Las grandes decisiones de arquitectura son las que más van ha influir sobre el rendimiento de nuestra aplicación. Si por ejemplo nos decantamos por una arquitectura que implica un constante trasiego de peticiones de red, poco podrémos hacer después si la red se convierte en un cuello de botella, salvo cambiar la arquitectura, algo que puede ser tremendamente costoso. Esto no quiere decir que una vez seleccionada una buena arquitectura nuestro código no pueda ser revisado desde el punto de vista del rendimiento para mejorar este aspecto

La popularización de las máquinas virtuales de ejecución y la mejora general de los compiladores ha hecho que la optimización a priori basada en pequeños detalles haya dejado de tener ningún sentido. Cuando hay tantas capas que pueden realizar optimizaciones automáticas e incluso adaptativas entre nuestro código y el procesador es imposible conocer en detalle como será el código máquina que finalmente se ejecute y por lo tanto, salvo tener en cuenta ciertas buenas prácticas (por ejemplo al trabajar con cadenas) poco más podemos hacer… sin usar un profiler.

Lo bueno de usar un profiler es que nos permite alejarnos completamente del peligro de caer en la optimización temprana. Resumiendo, la optimización temprana es un antipatrón que se manifiesta por optimizar aspectos de nuestra aplicación sin tener la certeza de que realmente afectan al rendimiento de la misma. Por ejemplo, podemos perder el tiempo en optimizar funciones que, debido a los patrones de uso de la aplicación, puede que no se ejecuten muy a menudo o que en última instancia el compilador puede optimizar por nosotros. Esto unido a la complejidad de las arquitecturas, que hace dificil saber cual será el cuello de botella de nuestra aplicación, hace que el mejor momento para optimizar sea cuando la aplicación ya se encuentra en preproducción, sometida a cargas de trabajo reales o cercanas a las reales.

A la hora de conseguir una aplicación que se ejecute con soltura y sin requerir un hardware extremadamente costoso, cada vez se tiende más a seguir una estrategia basada en: no olvidar el rendimiento a la hora de plantear la arquitectura y el diseño, no olvidar las buenas prácticas relacionadas con el rendimiento a la hora de la implementación (usar un analizador estático, como FxCop, es una manera excelente de no olvidarlas) y utilizar un profiler para hacer una optimización centrada en los cuellos de botella de nuestro código una vez tenemos escenarios de carga realistas.

Entiendasemé, en ningún caso quiero decir que debamos dejar el asguramiento del rendimiento de nuestra aplicación para el final del desarrollo. Es algo que debemos hacer iterativamente, de manera contínua, siempre que completemos un escenario de nuestra aplicación que tenga unos requisitos determinados de rendimiento o que pueda impactar sobre el rendimiento de otros escenarios.

Otro aspecto fundamental a la hora de abordar la optimización es el ‘hasta donde’. Todo es optimizable, siempre se puede dar un paso más, pero cada paso siempre es un poco más costoso que el anterior, por eso no siempre es económicamente rentable dar el siguiente paso. Para saber donde pararse en temas de optimízación es necesario establecer para cada escenario que lo requiera, unas condiciones de rendimiento objetivas, realistas y medibles que cubran las expectativas del usuario.

Si bien siguiendo la filosofía aquí comentada nuestras aplicaciones no deberían tener excesivos problemas de rendimiento, es un realidad que muchas veces los problemas de rendimiento solo se manifestarán cuando ya tengamos la aplicación en producción. Si el problema es de arquitectura, probablemente tendremos un proyecto fallido, pero sino es el caso siempre queda una esperanza, usar un profiler sobre la aplicación en producción, pero esa es otra historia… que pronto contaré.

Pensandoun poco y tras releer este post… ¿quizás la moraleja de toda esta historia es que si tienes buenos arquitectos es probable que no te tengas que preocupar de la optimización? Las personas sobre los bits una vez más…

4 comentarios en “Un enfoque ágil para la optimización”

  1. Buenas Rodrigo. Que el rendimiento de las aplicaciones dependen de la arquitectura de la misma es algo evidente, yo siempre defiendo ese punto pero es la primera vez que lo veo plasmado en un post. El uso de profiler es válido solo si nuestra arquitectura es medianamente correcta y encontramos cuellos de botella importantes porque de lo contrario las mejoras serán marginales o requerirán cambios drásticos que seguramente no serán viables.
    Además de las buenas prácticas, y siguiendo con la convicción de que la mayor parte pasa por la arquitectura, el uso de los patrones correctos ayuda muchísimo a crear aplicaciones performantes. También pienso que el estudio de los antipatrones ayuda mucho sobre todo a no cometer abusos en el eso de ciertas características arquitectónicas o algorítmicas.
    Por último, creo que un desempeño mínimo debiera ser un requerimiento implicito en todos los proyectos y que para lograrlo es necesaria una declaración (una visión) general de la arquitectura.
    Tus post son muy buenos pero este en particular me tocó.
    Saludos y felices fiestas.

  2. Lucas, comparto totalmente lo que has comentado. Lo patrones son una piedra angular en toda arquitectura, la caraterística más importante de una arquitectura es la coherencia, y los patrones son una excelente vía para lograrla.

    Un saludo, gracias por tu comentario y felices fiestas.

  3. >> quién no ha escrito un componente en C++ para llamarlo desde VB por cuestiones de rendimiento

    Rodri, yo escribí componentes en C++ para llamarlos desde VB porque ¡en VB no se podían hacer! 🙂

    Creo que este post y el mío (http://geeks.ms/blogs/ohernandez/archive/2007/12/23/la-relaci-243-n-entre-linq-y-don-knuth.aspx) se complementan, el tuyo más orientado hacia el “programming-in-the-large” y el mío al “programming-in-the-small”.

    Abrazo – Octavio

  4. Totalmente de acuerdo Octavio!!! Escribí mi post antes de leer el tuyo, pero son completamente complementarios. De hecho los dos hablamos sobre ‘el demonio de la optimizacón temprana’…

    Cuanta razón tienes en lo que comentas en tu post, mucha gente está mirando de manera muy miope a LINQ… yo también lo hice en su momento, tengo que reconocerlo. Pero la verdad es que la legibilidad, la facilidad, la mantenibilidad y la integración son valores mucho más importantes que el rendimiento (siempre que se cubran los requisitos de rendimiento claro).

    Gracias por tu comentario!!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *