La gestión del rendimiento puede resultar una tarea compleja: las aplicaciones web modernas incluyen numerosos componentes dinámicos que pueden originar cuellos de botella en el rendimiento. ASP.NET Core ofrece una gama variada de herramientas para asistir en este proceso. En esta entrada de blog, examinaremos detenidamente cómo aplicarlas con eficacia para construir aplicaciones web altamente eficientes utilizando ASP.NET Core.
Al concebir aplicaciones, el rendimiento puede no situarse como la consideración primordial. Con frecuencia, las prioridades se centran en la construcción de las funcionalidades demandadas por el cliente y en el cumplimiento riguroso de los plazos establecidos, relegando el ajuste del rendimiento a un plano secundario. Sin embargo, cuando se acerca el momento del lanzamiento de las aplicaciones, los equipos de desarrollo se ven compelidos a acelerar el proceso para mejorar el rendimiento y alcanzar niveles óptimos. Este ajuste de última hora en el rendimiento, no planificado previamente, afecta adversamente al impulso inicial y genera extensas y estresantes jornadas para los desarrolladores. Podemos abordar esta situación de manera más efectiva.
Cuando hacemos del rendimiento una prioridad durante los ciclos de desarrollo, es posible abordar los problemas de manera progresiva, evitando así la acumulación de desafíos y reduciendo el estrés asociado. El rendimiento también tiene un impacto financiero: se ha documentado ampliamente que incluso pequeñas mejoras pueden impulsar la participación de los usuarios, generando cambios notables en las tasas de conversión. Los sitios web líderes han reconocido la crucial importancia del ajuste del rendimiento para mejorar la experiencia global del usuario. La máxima de que el tiempo es dinero refuerza este principio.
Junto con la interacción de los usuarios y el bienestar de los desarrolladores, el rendimiento de la aplicación adquiere una importancia significativa para los objetivos de SEO: Google ha elevado el rendimiento del sitio como un criterio vital en sus clasificaciones de motores de búsqueda. Asimismo, el rendimiento se convierte en una preocupación central para las aplicaciones internas de las empresas, ya que las aplicaciones lentas pueden actuar como un lastre para la eficiencia del usuario, con consecuencias económicas.
¿Cómo mejoramos el rendimiento?
Entendemos, por lo tanto, que el rendimiento debe ser una consideración desde el inicio. No obstante, el rendimiento puede ser un desafío intrincado. Los problemas de rendimiento varían según la tecnología web y la arquitectura de la canalización de aplicaciones. Afortunadamente, las plataformas de aplicaciones proporcionan cierto respaldo. Ahora, analicemos las inquietudes relacionadas con la interfaz al desarrollar aplicaciones con ASP.NET Core.
Cuando nos referimos al rendimiento del frontend, estamos hablando principalmente de dos aspectos cruciales. En primer lugar, buscamos reducir tanto el tamaño como el número de solicitudes que viajan a través del cable entre el servidor y el navegador. Para lograrlo, existen diversas estrategias, como la agrupación, compresión y almacenamiento en caché. En segundo lugar, nuestro objetivo es minimizar el tiempo de espera del usuario para que las acciones se concreten. Esto se logra comúnmente a través de la implementación de código asincrónico y evitando bloqueos que puedan afectar la experiencia del usuario. ASP.NET Core proporciona características integradas que simplifican la tarea de los desarrolladores para alcanzar estos dos objetivos de rendimiento.
¿Cómo medir la velocidad?
Aunque identificar la presencia de lentitud en una aplicación resulta simple, la obtención de mediciones efectivas del rendimiento se vuelve una tarea notablemente compleja. Se despliegan diversas métricas y corrientes de datos que pueden ser evaluadas para contribuir al rendimiento global. Además, factores como la congestión en la red complican la obtención de mediciones precisas. No obstante, esto no implica que la evaluación del rendimiento carezca de valía. Siempre y cuando se reconozca la variabilidad y las limitaciones de los puntos de referencia, aún es posible progresar.
En el momento de evaluar el desempeño, surgen dos modalidades de mediciones que se pueden ejecutar. La primera comprende mediciones individuales: consiste en transitar a través de un flujo de aplicación y determinar la duración del material. Aunque podría llevar a cabo esto utilizando un cronómetro, dispone de diversas herramientas para obtener mediciones más detalladas.
Una herramienta reconocida es Miniprofiler, concebida por los colaboradores de Stack Exchange para evaluar el rendimiento en plataformas como Stack Overflow. Se presenta como un paquete NuGet que puede instalarse con facilidad en la aplicación. Evalúa el rendimiento y muestra los resultados en una pequeña superposición en su navegador. Miniprofiler analiza exhaustivamente toda la pila, facilitando la detección de cuellos de botella, consultas SQL duplicadas y solicitudes excesivas. A continuación, se presenta una visión de Miniprofiler en funcionamiento:
Chrome DevTools también es reconocido por analizar solicitudes individuales en aplicaciones web. Además de la supervisión de solicitudes de red, Chrome DevTools incluye varios generadores de perfiles de rendimiento y herramientas de auditoría integradas. Una de las herramientas de auditoría más recientes se ubica en el panel Auditorías de Chrome DevTools. Puedes realizar una variedad de pruebas de rendimiento en tu sitio y recibirás consejos útiles de Google sobre cómo optimizar el rendimiento.
Y, naturalmente, encontramos Fiddler, la herramienta por excelencia para monitorear la capa de red de su aplicación web. Además de observar el tráfico de red, Fiddler generará estadísticas que le guiarán en la identificación de cuellos de botella en la aplicación. También posibilita la manipulación de sesiones web, la grabación de tráfico HTTP/HTTPS y la depuración de contenido web desde cualquier dispositivo. En pocas palabras: Fiddler está disponible para ayudar, ¿por qué no aprovecharlo?
Si bien evaluar el rendimiento individual es crucial, también es esencial medir el rendimiento global. Se presentan categorías de problemas de rendimiento que solo surgen bajo cargas significativas en la aplicación. La manera más efectiva de obtener información sobre el rendimiento general de la aplicación es a través del uso de una herramienta de supervisión del rendimiento de aplicaciones (APM). En el mercado existen varias herramientas APM, siendo New Relic y Application Insights las más destacadas. Application Insights, al ser un producto de Microsoft integrado en la pila, resulta especialmente beneficioso para aplicaciones ASP.NET.
Dado que siempre es posible mejorar la velocidad de las aplicaciones, existe el riesgo de sumergirse en una complejidad interminable al ajustar el rendimiento. El rendimiento debe equilibrarse con otros objetivos de desarrollo y características de la aplicación. Un buen objetivo para cualquier aplicación es evitar que el usuario espere más de un segundo para cualquier acción. Las optimizaciones de menos de un segundo pueden pasar desapercibidas para los usuarios, mientras que cualquier cosa que supere los diez segundos debe abordarse de inmediato. Si no puede completar una acción específica en un segundo, una opción a considerar es hacerla asincrónica: devuelva el control de la aplicación al usuario y notifíquele cuando se complete la tarea.
Trucos de rendimiento
Bundling and Minification
En las aplicaciones web contemporáneas, la cantidad de CSS y JavaScript necesarios para que una página web funcione puede ser asombrosa. Una estrategia eficaz para reducir esa carga es la minificación y agrupación de todos los recursos estáticos de CSS/JavaScript/otros. La minificación opera en archivos de código convencionales, legibles por humanos, eliminando todos los espacios en blanco y acortando los nombres de las variables, lo que resulta en un tamaño de archivo considerablemente menor. La agrupación fusiona diversos archivos en un solo recurso, disminuyendo la sobrecarga de conexiones simultáneas entre el servidor y el navegador para enviar múltiples archivos a través del cable. En conjunto, estas dos estrategias mejoran significativamente las comunicaciones cliente-servidor y aceleran las aplicaciones web.
En las aplicaciones web de ASP.NET, las arquitecturas del lado del cliente tienden a presentarse en dos modalidades. La primera implica realizar más operaciones en el lado del servidor e insertar vistas de Razor en el cliente. Aunque pueda estar empleando algunas bibliotecas para ofrecer validaciones del lado del cliente o cierta funcionalidad de Ajax, JavaScript se considera un componente adicional, no el controlador principal. El segundo enfoque se da al utilizar un marco de SPA como React, Angular o Vue para llevar a cabo gran parte del procesamiento en el lado del cliente. ASP.NET prefiere ceder protagonismo y permitir que la API web sirva datos desde el lado del servidor: deja que los marcos de SPA se encarguen del trabajo intensivo con JavaScript en el explorador del cliente.
Ambos estilos arquitectónicos son válidos y existen diversas herramientas para gestionar cada uno de ellos. Si está utilizando un marco de SPA o tiene numerosos archivos para entregar en el lado del cliente, debería considerar el uso de una herramienta de agrupación del lado del cliente como Webpack para empaquetar su CSS y JavaScript.
Webpack es una herramienta que reúne varios activos estáticos y los combina de manera automática. Webpack cuenta con diversos cargadores que pueden procesar diferentes tipos de archivos, y también incorpora funciones avanzadas que pueden facilitar la optimización de tus activos. Un ejemplo es la «agitación de árboles»: Webpack tiene la capacidad de analizar tus archivos JavaScript y eliminar funciones que no estás utilizando en tu código, lo que resulta en un paquete considerablemente más pequeño
.Microsoft también dispone de algunas plantillas destacadas de SPA que puedes incorporar en aplicaciones simples. Si no estás generando una SPA y solo cuentas con unos pocos archivos JavaScript, la recomendación principal es hacer uso de la herramienta BuildBundlerMinifier. Este paquete NuGet, de instalación sencilla, se encargará de agrupar los recursos durante el proceso de compilación. Su configuración es bastante accesible: se genera un archivo de configuración json que apunta a las carpetas de recursos y especifica el destino de salida para esos recursos.
CSS Preprocessing
CSS desempeña un papel esencial en la definición del estilo de tus aplicaciones web. Aunque el CSS básico puede ser poderoso, es recomendable considerar la adopción de un preprocesador como LESS o SASS, ya que proporciona funcionalidades adicionales sin sacrificar la compatibilidad. Y al comenzar a utilizar una herramienta de agrupación, puedes emplearla para crear tus propios paquetes personalizados de CSS. Además de facilitar la creación de hojas de estilo más extensas, estos preprocesadores te permiten reducir el tamaño de tu paquete CSS. La mayoría de los desarrolladores serios de CSS suelen optar por una biblioteca frontend como Bootstrap, Foundation o Material Design. No obstante, es probable que no estés utilizando todas las funciones y controles de esas bibliotecas. Si estás utilizando un preprocesador, puedes diseñar tu propia distribución personalizada y comentar todo lo que no estás utilizando. Esto disminuye el tamaño del paquete y te proporciona la flexibilidad de incorporar fácilmente esos controles si decides utilizarlos más adelante.
Compresión
Aunque la reducción del tamaño de sus archivos JavaScript y CSS contribuirá a disminuir la cantidad de datos transmitidos por el cable, esta no es la única área donde puede optimizar el tiempo. La mayoría de los navegadores admiten la compresión GZIP, que le permite comprimir sus archivos antes de enviarlos entre el servidor y el cliente. ASP.NET Core realiza automáticamente la compresión de ciertos tipos de archivos, pero no de todos; por ejemplo, el contenido de los resultados JSON no se comprime. Si está desarrollando una aplicación web de SPA, utilice el middleware de compresión de respuesta para obtener una compresión adicional y economizar de manera significativa el ancho de banda.
Caching
Aunque las solicitudes de red individuales pueden ser pequeñas, la velocidad máxima se alcanza cuando se evita completamente el uso de la red y se extrae el contenido directamente de la memoria caché. La implementación efectiva de la caché juega un papel fundamental en la mejora del rendimiento de la mayoría de las aplicaciones web, ofreciendo la posibilidad de brindar a los usuarios una experiencia optimizada y fluida. En el caso de ASP.NET, existen diversas formas de almacenamiento en caché, cada una adaptada a optimizar distintas partes de la pila y variando en la forma en que los datos son almacenados.
Dentro del marco de ASP.NET Core, el almacenamiento en caché se clasifica en dos categorías principales. La primera de ellas es el almacenamiento en caché de datos, diseñado principalmente para el procesamiento en el backend de la aplicación. Aquí, los datos se almacenan en la memoria o en una caché distribuida, como instancias de Redis o SQL Server. Esta forma de almacenamiento en caché resulta idónea para conservar los resultados de consultas frecuentes a la base de datos o para almacenar cálculos complejos que se acceden con regularidad. La capacidad de optimizar el rendimiento en esta etapa del procesamiento contribuye de manera significativa a la eficiencia general de la aplicación, mejorando la velocidad y la capacidad de respuesta.
El segundo tipo crucial de caché es la caché de respuesta, una herramienta principalmente aplicada en el lado del cliente. La caché de respuesta controla cómo el navegador del cliente almacena en caché las solicitudes de red HTTP, siendo particularmente efectiva para archivos estáticos que rara vez experimentan cambios, como JavaScript, imágenes y CSS. En el contexto de ASP.NET, se incorporan atributos de middleware y acciones del controlador que permiten una personalización precisa de los encabezados de la caché de respuestas, brindando así un control detallado sobre este proceso.
Aunque el almacenamiento en caché de respuestas es valioso para mejorar la eficiencia en la entrega de ciertos archivos, es esencial aplicarlo estratégicamente. No se recomienda utilizarlo de manera indiscriminada, especialmente en solicitudes que dependen de datos actualizados o están vinculadas a la identidad del usuario. En tales casos, el almacenamiento en caché de respuestas puede conducir a resultados no deseados.
Otra estrategia para aprovechar el almacenamiento en caché de respuestas es mediante el uso de una red de entrega de contenido (CDN). Estas redes, impulsadas por proveedores de infraestructura en la nube, se especializan en la entrega eficiente de activos estáticos a través de nodos distribuidos globalmente. Al utilizar una CDN, es posible ofrecer contenido desde ubicaciones cercanas al usuario, minimizando la latencia de la red y proporcionando una experiencia más rápida y fluida. En resumen, la combinación inteligente de almacenamiento en caché de respuestas y CDN puede ser clave para optimizar significativamente la entrega de contenido web.
Numerosas aplicaciones web desarrolladas con ASP.NET confían en bibliotecas de terceros, y resulta que la mayoría de estas bibliotecas ya están disponibles en CDNs populares. Existe una alta posibilidad de que el usuario ya haya descargado esa biblioteca desde una CDN cercana para otro sitio que haya visitado, ¿por qué no utilizarla? Esto es especialmente cierto para bibliotecas comunes como jQuery o Bootstrap, o dependencias de módulos de Node para marcos de SPA. No obstante, al utilizar una versión de CDN de bibliotecas de terceros, es necesario mantener una versión de respaldo en caso de que la ubicación de CDN deje de funcionar o se necesite una copia nueva. Puede lograr esto mediante el script TagHelper en ASP.NET Core; a continuación, se presentan algunos ejemplos de etiquetas de script para bibliotecas comunes de JavaScript:
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-test="window.jQuery" crossorigin="anonymous" integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQs... /> </script> <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal" crossorigin="anonymous" integrity="sha384-TcIQib027qvyjSMfHjOMaLkf... /> </script> <script src="~/js/site.min.js" asp-append-version="true"></script>
Microsoft Azure, por ejemplo, ofrece un servicio de CDN que se configura de manera sencilla, pudiendo vincularse con su aplicación web o depósito de almacenamiento de Azure. AWS y otros proveedores de nube también proporcionan servicios de CDN similares. En síntesis, aprovecha CDN para reducir las latencias de la red y acercar al usuario a sus ubicaciones geográficas, mejorando de esta manera la eficiencia de sus aplicaciones web.
Conclusiones
La optimización del rendimiento puede ser un desafío complejo: las aplicaciones web modernas incorporan numerosos componentes que pueden generar obstáculos en el rendimiento. No obstante, ASP.NET Core ofrece una variedad de herramientas para asistirte en este aspecto. Desde instrumentos de medición como Miniprofiler hasta middleware y útiles TagHelpers, dispones de diversas estrategias para acelerar tus aplicaciones.
Si te sientes perdido respecto a por dónde comenzar, inicia con la medición. Asegúrate de que Miniprofiler o Application Insights estén activados en tu aplicación y comienza a identificar posibles obstáculos. A partir de ahí, permite que los datos te orienten. Identifica el problema más significativo que puedas abordar y comienza a trabajar en ello. Saludos a las aplicaciones web más veloces que proporcionan una experiencia del usuario encantadora.