A medida que una solución en .NET se expande, el tiempo destinado a los analizadores Roslyn durante la compilación tiende a aumentar. He observado una solución web donde el tiempo de ejecución de los analizadores Roslyn era realmente desproporcionado. Específicamente, el 70% del tiempo total se dedicaba a los analizadores Roslyn, mientras que el 30% restante se destina al proceso de compilación en general. El tiempo total de construcción variaba entre 2 y 3 minutos, dependiendo de las especificaciones de la máquina.
La duración de la compilación impacta de manera directa en tres aspectos fundamentales:
- La eficiencia de los desarrolladores, cuyo tiempo de espera diario puede volverse considerable.
- Métricas vinculadas a la entrega y la implementación continua. Una compilación más lenta implica tiempos de validación más prolongados para las solicitudes de cambio y las versiones de lanzamiento.
- La satisfacción y motivación de los desarrolladores, quienes experimentan frustración al esperar en cada modificación de código.
La duración de la compilación en una solución .NET puede ser justificada por varios factores, como la cantidad de código, las interdependencias entre proyectos y el grado de acoplamiento entre ellos, entre otros. En este primer artículo, nos enfocaremos exclusivamente en el impacto de los analizadores Roslyn en el tiempo de compilación. Después de leer este artículo, estará capacitado para identificar su influencia en sus soluciones .NET y aplicar medidas para reducirlo, sin descuidar la calidad y la garantía que proporcionan.
Los sospechosos de siempre
.NET integra analizadores Roslyn destinados a evaluar el estilo y la calidad del código. Estas reglas están marcadas por códigos que empiezan con CA, CS e ID. Dependiendo de la plataforma de destino, se habilita un conjunto predeterminado de estos analizadores. La propiedad AnalysisLevel puede ser ajustada para agregar o reducir reglas. Diversos paquetes NuGet destacados, como xUnit.net, FluentAssertions, StyleCop, Entity Framework Core y otros, incorporan automáticamente una cantidad significativa de analizadores de Roslyn. Esto facilita la adhesión a las convenciones y prácticas recomendadas por estas bibliotecas.
La complicación radica en la posibilidad de que no se requieran todas las reglas de análisis proporcionadas por estos paquetes. Recientemente, me encontré con una solución .NET que presentaba una referencia indirecta a Entity Framework Core, a pesar de que este último no se estaba utilizando. Tras un análisis meticuloso, observé que las reglas de análisis de Entity Framework Core estaban sumando un segundo al tiempo total de compilación. Ahora, exploremos cómo enfoqué la identificación de este inconveniente.
Análisis del impacto de los analizadores Roslyn en el tiempo de compilación
Para iniciar, será necesario instalar una herramienta externa desarrollada por Kirill Osenkov. Kirill, un experto en MSBuild y destacado ingeniero de software en Microsoft, creó una herramienta llamada MSBuild Structured Log Viewer, diseñada para examinar los registros de compilación generados por MSBuild. Siga el enlace proporcionado e instálalo.
En segundo lugar, deberá activar los informes del analizador durante la compilación de sus proyectos. Esto se logra mediante la adición de la siguiente línea a su proyecto. Se recomienda incorporarlo a todos los proyectos de la solución, y la manera más eficiente es utilizando un archivo Directory.Build.props en la raíz de la solución.
<Project> <PropertyGroup> <ReportAnalyzer>true</ReportAnalyzer> </PropertyGroup> </Project>
En la tercera instancia, se hace indispensable compilar la solución y dar origen a un archivo *.binlog. Este procedimiento puede ejecutarse a través de la línea de comandos, siguiendo la instrucción que se presenta a continuación:
dotnet build /bl
El parámetro /bl corresponde a la abreviatura de /binarylogger . Tras finalizar la compilación, debería encontrar un archivo *.binlog en la carpeta principal de la solución o del proyecto. Realice un doble clic en dicho archivo para abrirlo mediante el Visor de registros estructurados de MSBuild.
Los usuarios de Rider se benefician al no tener la necesidad de ejecutar comandos en la interfaz de línea de comandos (CLI). La integración del MSBuild Structured Log Viewer está incorporada. Basta con realizar clic derecho en un proyecto o solución, seleccionar «Acciones de compilación avanzadas» y optar por «Reconstruir solución con diagnóstico» para una reconstrucción completa de la solución, o «Reconstruir proyectos seleccionados con diagnóstico» para uno o más proyectos individuales. El visor de registros se abrirá de manera automática tras concluir la compilación.
Identificación de los analizadores Roslyn con mayor impacto
Al abrir un archivo de registro binario generado con la propiedad <ReportAnalyzer>true</ReportAnalyzer> configurada en <PropertyGroup>, el Visor de registros estructurados de MSBuild presenta una sección de Resumen del analizador en la parte inferior de la vista de árbol principal. Esta sección es expandible, brindando un análisis detallado de cada analizador Roslyn, desde el más lento hasta el más rápido. Cada analizador Roslyn también puede expandirse para mostrar las reglas individuales ejecutadas, junto con sus tiempos de ejecución y dispuestas en orden de más lento a más rápido.
- StyleCop tiene una gran repercusión, con más de un minuto y medio.
- FakeItEasy tiene un impacto considerable de más de 30 segundos.
- AsyncFixer añade casi 30 segundos.
Un profesional experimentado en desarrollo podría cuestionarse si realmente es imprescindible contar con AsyncFixer, por mencionar uno. Las últimas versiones de .NET (6, 7, 8) incorporan un número creciente de analizadores Roslyn diseñados para elevar la calidad del código, especialmente en el ámbito del uso de async/await. Sin embargo, pocos conocen que algunas reglas deben ser habilitadas mediante la propiedad AnalysisLevel, como, por ejemplo:
<PropertyGroup> <!-- Enables all .NET built-in analysis rules that come from the .NET 6 SDK --> <!-- Simply a must-have for projects targeting .NET Standard 2.0 as the default level is very low --> <AnalysisLevel>6.0-All</AnalysisLevel> </PropertyGroup>
Desactivación de analizadores Roslyn innecesarios
Una vez que se hayan identificado los analizadores de Roslyn que tienen un impacto más significativo en el tiempo de compilación, se puede realizar una investigación detallada y tomar decisiones colaborativas sobre la necesidad de ciertas reglas. Si se opta por desactivar algunas, la forma más rápida de hacerlo es mediante la creación de un archivo editorconfig en la ubicación principal de la solución. En este ejemplo, desactivo la regla de análisis StyleCop, así como diversas reglas SA0001 del SDK de AWS a las que se hace referencia de manera indirecta en mi proyecto, pero que no estoy empleando.
[*.{cs,vb}] dotnet_diagnostic.SA0001.severity = none dotnet_diagnostic.SecurityTokenService1000.severity = none dotnet_diagnostic.SecurityTokenService1001.severity = none dotnet_diagnostic.SecurityTokenService1002.severity = none dotnet_diagnostic.SecurityTokenService1003.severity = none dotnet_diagnostic.SecurityTokenService1004.severity = none
Compilar compilaciones de producción más rápido
Cuando tu equipo utiliza solicitudes de incorporación de cambios para integrar nuevas características en la rama principal, es altamente probable que implementen puertas de calidad para garantizar una compilación correcta del proyecto, pruebas exitosas, ausencia de advertencias y errores, entre otros criterios. En términos generales, esto sugiere que el código en la rama principal tiene una calidad sobresaliente y está preparado para su implementación en producción. Considerando que las reglas de análisis de código ya se han aplicado durante el proceso de integración continua, es probable que no sea necesario añadir análisis de código adicionales al tiempo de compilación para la entrega en producción. Puedes desactivar de manera sencilla la ejecución de los analizadores Roslyn modificando el comando o utilizando la propiedad establecida en: dotnet build dotnet publish RunAnalyzers false.
dotnet build -c Release -p:RunAnalyzers=false
En el contexto del proyecto de ejemplo, al desactivar el análisis de código se logra una notable reducción en el tiempo de compilación, pasando de aproximadamente 2 minutos a menos de 50 segundos. Para equipos que mantienen un ritmo acelerado con múltiples implementaciones en producción a lo largo del día, esto podría tener un impacto sustancial en las métricas vinculadas con la entrega e implementación continua. Adicionalmente, en el escenario de utilizar un proveedor de servicios en la nube para compilar imágenes de Docker, también podría derivar en una disminución de costos.
Conclusiones
En este post dedicado a optimizar el tiempo de compilación en soluciones .NET, exploramos métodos efectivos para identificar los analizadores Roslyn que ejercen un mayor impacto en dicho proceso. Además, examinamos cómo desactivar reglas de análisis de código innecesarias y evitar la ejecución de analizadores Roslyn durante la compilación de entregables destinados a producción.
Estas estrategias, al reducir la carga de trabajo asociada con los analizadores, pueden significativamente acelerar el tiempo de compilación y mejorar la eficiencia del proceso. Este artículo busca proporcionar herramientas prácticas y soluciones para optimizar la experiencia de desarrollo en entornos .NET. Esperamos que estas recomendaciones sean de utilidad y estaremos explorando más tácticas en futuras entregas de esta serie. ¡Gracias por tu lectura y esperamos que encuentres útiles estas optimizaciones en tu trabajo diario!