Analizando tu código sin morir en el intento
A lo largo de mi trayectoria profesional, siempre he sido y sigo siendo un firme defensor de las buenas prácticas de programación, esforzándome para que los proyectos en los que participo sean motivo de orgullo. Sin embargo, quienes llevamos tiempo en proyectos sabemos que, por muy bueno que sea alguien o por mucho conocimiento que tenga, no puede hacer que un proyecto sea excelente por sí solo. Todo ese conocimiento debe compartirse entre los miembros del equipo para que puedan aplicarlo y así evitar cometer errores. ¿Cómo se puede lograr esto? Hace tiempo, era un firme defensor de herramientas de análisis estático de código, como SonarQube o Kiwan. Estas herramientas analizaban el código una vez que lo subías a la rama y te mostraban sugerencias/recomendaciones para mejorarlo. No obstante, hay aspectos que no terminan de encajar en los equipos. El primero es el tiempo: tienes que subir tu código y luego consultar qué cosas puedes mejorar. ¿Qué ocurría la mayoría de las veces? Que, al final, los últimos días del proyecto se dedicaban a “solucionar” lo que, según estas herramientas, estaba mal, pero el objetivo no es solo corregir, sino aprender. Y cuando el equipo lo hace de esta manera en el último día, no se aprende realmente (es como cuando estudiabas todo la noche antes de un examen, ¿sinceramente, te acordabas de lo que habías estudiado una semana después?). Además, hay otro motivo por el cual actualmente tampoco confío tanto en estas herramientas: además de ser un análisis sintáctico, el código tiene un contexto, un “por qué”. A veces, haces las cosas de cierta forma porque lo consideras necesario. Un ejemplo trivial: si hacemos un proyecto con una arquitectura Vertical Slice, independientemente de si el equipo lo hace mejor o peor, la herramienta probablemente señalará que hay código repetido o que se podría refactorizar. Pero, según Vertical Slice, cada “feature” debe tener todo lo necesario para ser independiente de las otras, y no podemos reutilizar una clase modelo (DTO), aunque la base sea la misma (se podría, pero entonces no lo llamaríamos Vertical Slice aunque esa conversación daría para otro post). Está claro que este es un ejemplo muy obvio, pero puede haber decisiones que se toman debido a la casuística de ese desarrollo, y aunque no sean la mejor opción desde el punto de vista estático, sí lo son para cumplir con los requisitos de la aplicación. Además, he visto proyectos con una puntuación “A” en Sonar que eran, sinceramente, de los más chapuceros que he visto, mientras que otros con una “C” mostraban un rendimiento espectacular gracias a las decisiones que se tomaron.
También hay otro punto de punto de vista que es como ve el equipo la incoporación de estas herramientas. Muchos equipos lo ven como una herramienta de control, de supervisión y ante tal perspectiva un equipo no la adopta de una forma ni eficiente ni eficaz, el equipo tiene que llegar a un grado de madurez en el que sea consciente de que esta herramienta su objetivo principal es el de incrementar el valor de lo que se esta desarrollando/entregando sino da igual lo buena que sea la herramienta o opción que el equipo de desarrollo no la va utilizar. Así que como consejo de alguíen que se ha equivocado muchas veces antes de decidir que quieres poner establece un plan para la adopción de dicha herramienta.
Roslyn
Todo lo comentado anteriormente corresponde a la época de .NET Framework. Con la reescritura del framework para mejorar su rendimiento, hacerlo multiplataforma y posicionarlo como uno de los lenguajes más utilizados en las empresas, se realizaron muchos cambios, y uno de ellos fue Roslyn. Para quienes no lo conozcan, Roslyn es el nombre en clave del proyecto de la plataforma de compiladores de .NET, que toma su nombre de una ciudad homónima en Washington, EE.UU. ¿Qué hace especial a Roslyn en comparación con el compilador anterior?
Es un proyecto open source, lo que significa que cualquier persona puede crear su propia “versión” de C# y adaptar los requisitos a sus necesidades. Es más que un compilador; es un conjunto de herramientas y compiladores que, combinados, otorgan al lenguaje una potencia espectacular. Te muestra el resultado en tiempo real (recordemos que uno de los mayores problemas de las herramientas de análisis de código estático es que los resultados se obtenían a posteriori). Es multiplataforma, lo que permite su uso en cualquier sistema operativo. Al final, esta opción no quedó relegada solo a quienes quisieran modificar algunas reglas de compilación. Sin embargo, su verdadero valor no se percibió de inmediato.
Con Roslyn, las empresas que se dedican a analizar código en C# han empezado a priorizar la creación de analizadores que nos ayuden a mejorar nuestro código. Cuando hablo de mejorar, no me refiero solo a reducir el número de líneas de código, sino a optimizar el rendimiento, permitir que el equipo aprenda de sus errores, los solucione y evolucione. Por eso, no hay mejor alternativa que ofrecer al desarrollador advertencias o mensajes críticos junto con una referencia que explique por qué la propuesta es mejor. Con todas estas virtudes, considero esencial tener estas herramientas dentro de los equipos.
Mucha gente dirá que para eso están las revisiones de Pull Request. Mi opinión personal es que una Pull Request debe validar que se ha cumplido con lo requerido; discutir si una variable va en mayúsculas, se define con var, con un _, o según el estándar acordado, es algo que una máquina puede hacer por nosotros. Así, podemos centrarnos en lo que realmente aporta valor y beneficio al proyecto.
¿Donde obtenemos los Analyzers?
Naturalmente, todo lo que encontramos en el ecosistema de .NET se puede obtener desde NuGet. Si buscamos cuáles son los más descargados, podemos hacernos una idea de las preferencias de la comunidad:
Colecciones de Analizadores
- El propio compilador oficial de Roslyn ofrece una serie de analizadores que podemos utilizar: Microsoft.CodeAnalysis.NetAnalyzers, Microsoft.CodeAnalysis.BannedApiAnalyzers, Microsoft.CodeAnalysis.PublicApiAnalyzers, Microsoft.CodeAnalysis.Analyzers, Roslyn.Diagnostics.Analyzers.
- StyleCop tampoco se ha quedado atrás y también ha publicado una serie de analizadores que podemos encontrar en StyleCopAnalyzers.
- SonarLint, continuando con la evolución de sus reglas anteriores, ofrece su paquete de analizadores.
- BlowinCleanCode es un paquete bastante interesante que se enfoca en el principio de responsabilidad, la encapsulación y las buenas prácticas: BlowinCleanCode.
Seguridad
- La seguridad es un aspecto crucial que debemos tener en cuenta, y es importante identificar posibles vulnerabilidades en nuestro código. SecurityCodeScan es una opción que aborda estas necesidades.
- PumaSecurity es un analizador de seguridad que ofrece un análisis continuo y en tiempo real del código fuente de aplicaciones C#.
ASP.NET Core y Web
- AngleSharp es una biblioteca de análisis sintáctico que maneja HTML5, CSS3 y XML para construir un DOM basado en la especificación oficial del W3C.
- AspNetCoreAnalyzers proporciona analizadores específicos para Microsoft.AspNetCore.
Async/Multithread
Uno de los grandes desafíos de los equipos es el uso correcto de la asincronía y el multihilo. Muchas fugas de memoria y cuellos de botella en las aplicaciones son consecuencia de un mal uso de estos conceptos. Estos analizadores pueden ayudarte a encontrar soluciones “mágicas” a algunos problemas de tus desarrollos:
- AsyncFixer: Diagnósticos avanzados de Async/Await y CodeFixes para C#.
- SmartAnalyzers.MultithreadingAnalyzer: Diagnósticos avanzados de multihilos y CodeFixes para C#.
Bibliotecas de terceros
Algunas de las bibliotecas más “utilizadas/famosas” también han añadido analizadores para garantizar su buen uso. Librerías como Moq, xUnit y nSubstitute ofrecen esta ayuda para asegurar el correcto uso de sus funcionalidades.
Como estandarizamos la forma de trabajar de los equipos.
Los analizadores que hemos mencionado anteriormente no deben incluirse todos en tu proyecto, sino pobre del IDE y el tiempo de compilación del mismo. Lo importante es seleccionar aquellos que se consideren más adecuados para el equipo. Hay que tener en cuenta que, cuántos más analizadores se utilicen, más probable es que surjan contradicciones entre ellos. Es fundamental abordar los aspectos más importantes del desarrollo y luego decidir cuáles son los analizadores más óptimos para tu equipo.
Por lo general, la práctica común es instalar el paquete NuGet en cada proyecto de la solución. Sin embargo, esto puede ser un poco tedioso, especialmente si se busca que todos los equipos de tu organización sigan las mismas pautas. ¿Cómo podemos estandarizar esto? Con los cambios introducidos, Microsoft ha lanzado una utilidad llamada Build.props
, que es un archivo destinado a estandarizar lo que llevarán todos los proyectos de una solución.
Este archivo es una excelente solución para unificar el naming en todos los proyectos, establecer bibliotecas comunes e instalar los analizadores que queremos usar. De esta manera, podemos crear una “plantilla” para aplicarla en todos los proyectos y equipos. Si no estás utilizando esta herramienta, te recomiendo leer la documentación oficial para su uso.
Resumen
En resumen, la clave para asegurar la calidad en nuestros proyectos no radica únicamente en utilizar herramientas de análisis estático o seguir al pie de la letra las reglas que estas imponen. Es esencial comprender el contexto de cada decisión de desarrollo y fomentar un aprendizaje continuo dentro del equipo. Herramientas como Roslyn y los analizadores específicos que seleccionemos pueden ser de gran ayuda, pero siempre deben ser complementadas con un enfoque humano que valore el criterio profesional y la colaboración. Así, podremos lograr no solo un código limpio, sino también un equipo que evoluciona y mejora con cada proyecto.
Y tú que analyzers usas? Te parece una buena opción?
Happy codding