Controla la calidad de tu código con NDepend


NDepend

Como freelance, la calidad del código que entrego es algo primordial para mí. El aprendizaje continuo y la intuición son los métodos que utilizaba hasta ahora para lograrla, pero gracias a NDepend cuento con una herramienta que aporta datos objetivos sobre la calidad de mi código.

Y lo que se puede medir, se puede mejorar.

Qué es NDepend

NDepend es un analizador de código que genera informes navegables con métricas objetivas sobre la calidad del código analizado. Cada métrica está documentada y es monitorizable y editable.

Además es capaz de evaluar la deuda técnica del proyecto en días y horas: puedes crear un histórico de métricas y evaluar a medida que vas avanzando en tu proyecto si el código añadido ha generado o no más deuda técnica.

Cómo puede ayudarte

  • NDepend previene la aplicación de código sospechoso (code smells, me encanta este término).
  • Te alerta sobre código que es primordial corregir antes de enviar la aplicación a producción.
  • Detecta las partes de la aplicación más complejas para que les prestes más atención.
  • Te ayuda a gestionar un código heredado (code legacy).
  • Genera una estimación objetiva de la deuda técnica del proyecto y la monitoriza en el tiempo a medida que añades más código.
  • Genera gráficos visuales sobre las dependencias del proyecto.

Todo esto te convierte al final en un mejor programador, consciente de los puntos más conflictivos de tu proyecto y capaz de sortear futuros problemas en forma de dependencias o deuda técnica.

Curva de aprendizaje

NDepend es una aplicación muy completa, extraerle el máximo rendimiento requiere de cierta dedicación, pero poco a poco irás comprendiendo lo que significa cada concepto y con el tiempo serás capaz de leer las gráficas sin mayor dificultad.

las 4 Gráficas más importantes de NDepend

1. Dashboard

Se trata del cuadro de mando de las métricas del análisis. Por ejemplo:

  • 11.999 líneas de código
  • 517 archivos de código fuente
  • Estimación del esfuerzo para realizar la aplicación: 327 días
  • Deuda técnica: 46 días
  • 14 días y 2 horas de esfuerzo para reducir la deuda técnica de C a B
  • 7 alertas de fallos primordiales a revisar
  • 9 alertas de reglas críticas no superadas

NDepend Dashboard

2. Code metrics view

Esta gráfica te permite navegar por las métricas de tu código de manera visual. 

  • Paso 1: Selecciona un nivel de análisis: método, campo, tipo, namespace o ensamblado.
  • Paso 2: Selecciona una métrica para el tamaño: por ejemplo las lineas de código (LOC)
  • Paso 3. Selecciona una métrica para el color: por ejemplo el porcentaje de cobertura (Perecentage Coverage)

Visualmente podrás ver qué métodos de tu proyecto tienen más lineas de código (aquellos con rectángulos mayores) y cuáles tienen menor porcentage de cobertura (los más próximos al rojo).

Code métrics View

3. Gráfico de dependencias

El gráfico de dependencias visualiza la arquitectura de la aplicación y las dependencias entre sus componentes. Aprovecha el gráfico para tomar mejores decisiones.

Gráfico de dependencias

4. Matriz de dependencias

Tiene el mismo objetivo que la gráfica de dependencias anterior, sin embargo, la matriz es más adecuada para códigos base mucho más grandes.

Matriz de dependencias

Ejecución Stand-alone

Cada versión de NDepend se distribuye en un archivo .zip. Al descomprimirlo se obtiene una carpeta con todos los archivos necesarios para su funcionamiento.

Aquí tengo dos versiones de NDepend, una en cada carpeta. 

Carpetas de versiónes de NDepend

Dentro de cada carperta se encuentra el archivo VisualNDepend.exe, que te permite ejecutar la aplicación de manera individual y sin necesidad de ninguna otra instalación.

Visual NDepend.exe

Visual NDepend Stand-alone:

NDepend Standalone

Integración EN Visual Studio

Pero lo más habitual es que quieras utilizar su extensión para Visual Studio.

Contenido carpeta versión NDependEjecuta NDepend.VisualStudioExtension.Installer.exe y selecciona en qué Visual Studio quieres instalarlo. En mi caso lo estoy probando con Visual Studio 2017:

Instalador extensión de Visual Studio NDepend

EJEMPLO PrÁCTICO 1

Vamos a ver qué pasa con dos de mis proyectos propios. Uno iniciado en el 2011 con MVC primera versión que ha evolucionado hasta MVC5, y un segundo proyecto que es un prototipo de aplicación con arquitectura limpia.

Dashboard de un proyecto en MVC en producción desde el 2011:

Dashboard de un proyecto MVC en producción desde 2011

Métricas para definir el tamaño del proyecto

  • Casi 11.000 lineas de código.
  • Esfuerzo estimado 353 días. Sería equivalente a 2 años de programación de una sola persona.
  • 5 ensamblados
  • 228 archivos de código

Métricas sobre la deuda técnica.

  • Deuda de 6,57 % que se traduce en 23 días de trabajo para corregirla.
  • 5 días y 4 horas para reducir la deuda de B a A.

Errores primordiales y reglas críticas no superadas

  • 2 errores primordiales
  • 8 reglas críticas no superadas

Inevitablemente lo que más me llama la atención son los números en rojo. Vamos a ver qué pasa si hago clic en el 2 rojo de Quality Gates.

Aparece la siguinte ventana:

2 Quality Gates Fail

Cada una de estas reglas es a su vez navegable. Al hacer clic sobre "8 rules Critical Rules Violated" llegamos a ver el resultado de estos fallos:

Rules matched de NDepend

Y aquí ya podemos ir intuyendo los problemas reales que está teniendo la aplicación. Por nombrar algunas:

  • Tipos demasiado grandes.
  • Tipos con demasiados parámetros (7 es el máximo de parámetros permitidos, pero lo puedes cambiar por el valor que desees).
  • Namespaces mutuamente dependientes (esto es grave).
  • No he llamado al método Dipose (¡Ups!)

Cada una de estas reglas es navegable y te conduce al método del código que la está incumpliendo. Tras varias horas de trabajo he ido corrigiendo algunos errores, pero ya veo que la cosa no va a ser rápida. Debería dedicarles unos 23 días para dejarla en modo aceptable.

Veamos la gráfica de complejidad:

Gráfico de complejidad

La capa de servicios es la que tiene los métodos más complejos. OrderService, OfferService y CheckoutService son clases claramente complejas. El fallo es que por aquel entonces programaba alojando la lógica de negocio en la capa de servicios, confundiendo y acoplándola con la persistencia de los datos. Casi cualquier proyecto legacy sufre de este mal.

Para mejorar la mantenibilidad de este código, los miembros coloreados son los candidatos por los que empezar.

Ejemplo práctico 2

La segunda aplicación que he probado es un proyecto más pequeño que consistía en un prototipo para una aplicación Web. El framework utilizado es .Net Core 2.2 con Razor Pages. En este caso, un punto que me gustaría analizar es el coste de desarrollo.

Vemaos que conclusiones puedo sacar:

Dashboard proyecto .Net Core

Las 3.572 líneas de código indican que se trata de un código base mucho menor que el anterior.

Este proyecto lo estimé previamente y le tuve que poner un precio. Pongamos que el precio hora para el cálculo es 20 € / hora. Un precio hora a la baja.

  • 127 días * 8 horas / día * 20 € / hora = 20.320 € ¡Vaya! muy por encima del precio por el que lo vendí :(

Como segundo punto me gustaría comparar la gráfica de complejidad del proyecto anterior con este más reciente:

Gráfico de complejidad del código

Puedo sacar dos conclusiones rápidas:

  1. El código que generaba antes era más complejo que el que genero ahora. Punto positivo.
  2. Antes codificaba la lógica de negocio en la capa de servicios. Ahora alojo la lógica en la capa de Dominio. Punto positivo.

Corrigiendo los problemas detectados

Manos a la obra, veamos qué pasa cuando empiezo a pelearme con el código y a intentar solventar las alertas que me indica NDepend. No es una tarea trivial, hay que dedicarle bastantes horas para ir corrigiendo los problemas. Estos son los tres primeros puntos con los que me he topado, se trata de tres ejemplos de aprendizaje:
 

  1. Namespaces dependientes. En una clase con un Namespace utilizas otra clase de otro Namespace que a su vez utiliza una tercera clase que está en el mismo Namespace que la inicial. No sé si es posible explicarlo mejor. Namespaces mutuamente dependientes. Esto suele suceder cuando un Namespace de más bajo nivel (más largo, vaya) utiliza un Namespace de más alto nivel.
     
  2. Struct sin Equals. No suelo utilizar structs en mi código. Quizá por inercia, quizá por desonocimiento. El caso es que este Struct utilizado lo cogí prestado de StackOverflow, you know ;). Vale pues resulta que para que los structs sean comparables entre ellos lo mejor es sobreescribir el método Equals. Así defines los campos fundamentales que representan la identidad del Struct.
     
  3. Las reglas son editables. Por ejemplo, hay una regla que se llama "Absencia de la I en interfaces" que te avisa si una interface que tienes definida no empieza por I. Pues desde que leí el post IInterface considered harmful ya no me gusta esta convención así que he tenido que editar dicha regla definiéndola a mi gusto. 

Conclusión

NDepend es una fantástica herramienta para añadir al arsenal del buen programador. Instálatelo, juega con él y mantén una actitud abierta que te permita aprender y mejorar.

Es para ti si...

  • Le das importancia a la calidad de tu código y quieres auditarlo de un modo objetivo.
  • Sueles trabajar con código heredado y quieres mejorarlo.
  • Quieres realizar una estimación objetiva del coste de desarrollo de una aplicación.
  • Programas en equipo y necesitas controlar la calidad del código que se sube a producción.



Quizá algun día empiece a enviar una newsletter, si te gustaría recibirla subscríbete aquí

Archivo