Automatizando el ciclo de control de la deuda técnica

Publicado por Eduardo Riol el

QADeuda TécnicaSonarQubeBitbucket ServerJenkins

"A ese proyecto no hay quien le meta mano"
"Ha pasado tanta gente por ese código que no se entiende nada"
"Tiemblo al pensar en lo que me va a costar hacer cambios en ese software"

¿Te suenan estos pensamientos? ¿Te los ha transmitido algún cliente? ¿Los has sufrido en tus propias carnes? Bueno, pues eso es que te has enfrentado a la temida Deuda Técnica.

¿Y qué es exactamente la deuda técnica? Pues no es otra cosa que el esfuerzo futuro que debemos realizar para arreglar defectos, vulnerabilidades y problemas de mantenimiento que en su momento introdujimos en nuestro software por alguna urgencia, plazo de entrega ajustado o falta de conocimiento.

Al igual que pasa con la deuda financiera, la deuda técnica acarrea intereses, lo que quiere decir que cuanto más tiempo dejamos pasar desde que introducimos los problemas hasta que intentamos su resolución, mayor será el esfuerzo necesario para arreglarlos.

También, al igual que ocurre con la deuda financiera, un poco de deuda técnica en ocasiones es necesaria y puede servir como impulso para probar rápidamente un MVP de nuestro producto, facilitar la implantación de una idea de negocio o reducir nuestro Time-to-market. Lo importante en este caso es saber cuánta deuda técnica estamos introduciendo, dar visibilidad al equipo sobre ella y trazar unas pautas y un plan para su control.

Bajando un poco a tierra, cuando hablamos de deuda técnica nos referimos a problemas como:

  • Código duplicado.
  • Complejidad ciclomática.
  • Vulnerabilidades.
  • Baja cobertura de tests unitarios.
  • Uso de métodos obsoletos (sí, así se dice deprecated en español :P).
  • Ausencia de estilo de programación.
  • ... y en general cualquier defecto no funcional detectable mediante análisis estático de código.

No es mi intención explicar cada uno de estos conceptos en detalle, para eso está Google, pero sí explicar qué podemos hacer para solucionar estos problemas.

¿Pero cómo controlamos la deuda técnica?

La deuda técnica es uno de esos aspectos del desarrollo que hay que agarrar por los cuernos, y hacerlo lo más pronto posible, antes de que se desboque. No es que sea imposible controlar la deuda técnica en proyectos legacy donde nunca se ha considerado este problema, pero sí que en muchas ocasiones, llegado este caso, habrá que reducir el alcance al objetivo menos ambicioso de intentar no introducir deuda técnica en el nuevo código que se escriba a causa de modificaciones y nuevas características del software.

Tanto para el caso de nuevos proyectos, como para aquellos que tenemos bajo mantenimiento, vamos a proponer un ciclo automatizado de control de la deuda técnica, por pasos, que nos ayude a mantener el problema dominado y siempre visible para nuestro equipo.

Para simplificar la propuesta, supondremos que ya contamos con las siguientes herramientas instaladas en nuestro entorno/organización:

Al final, con el objetivo de poder ejecutar nuestro ciclo automatizado de control de la deuda técnica, la idea es implementar un ecosistema como éste:

Empezamos con un caso básico: Eclipse + Bitbucket Server

Como posiblemente ya sepas, el primer paso en todo proceso de automatización relativo al código es involucrar en él a nuestro repositorio de código. Para este caso supongamos que estamos trabajando con Eclipse y nuestro repositorio de código es Bitbucket Server, si bien cualquier otro escenario con otras herramientas sería igualmente válido. Puede parecer que no hay necesidad de dedicar unas líneas a este paso, pero aún quedan organizaciones que no tienen una base de código gestionada con la que empezar el proceso de automatización.

En nuestro caso partiremos de un proyecto que actualmente ya tenemos en Eclipse (nosotros hemos descargado el código del reproductor de música MusicDNA desde GitHub, pero podría valer cualquier otro software). Para mandar el código a nuestro Bitbucket Server, seguimos los pasos que se inician al indicarle a Eclipse que queremos compartir nuestro proyecto a través de Click derecho > Team > Share Project:

Una vez tenemos el repositorio Git local creado en el proyecto, tenemos que hacer Commit & Push del código para que Eclipse nos pregunte a qué repositorio remoto queremos enviar el código (este repositorio remoto lo habremos creado previamente en Bitbucket Server obteniendo la url del mismo):

Una vez hecho esto, ya tendremos nuestro proyecto de Eclipse compartido y sincronizado a través de Bitbucket Server:

¿Qué hemos conseguido en este paso?
Tener una base de código gestionada y común a toda la organización y una bonita aplicación web que nos ofrece una vista amigable de nuestros repositorios de código.

¿Pero qué limitaciones tenemos?
Aún no tenemos ningún tipo de mecanismo de medición y control de la deuda técnica.

Midiendo la deuda técnica: SonarQube

Para mantener bajo control la deuda técnica necesitamos un analizador de código que nos informe de todas las métricas de nuestro código que suponen un riesgo para la futura mantenibilidad del software. Aquí es donde entra en juego SonarQube, la herramienta de análisis estático de código más conocida.

Lo que vamos a hacer en nuestro entorno local es descargar SonarQube Scanner y configurar el fichero conf\sonar-scanner.properties con los datos de nuestro servidor SonarQube.

Tras esto configuramos un nuevo fichero sonar-project.properties en el directorio raíz de nuestro proyecto, con los siguientes datos mínimos:

sonar.projectKey=MusicDNA
sonar.projectName=MusicDNA
sonar.projectVersion=0.1
sonar.sources=.

Y ejecutamos bin\sonar-scanner.bat en línea de comandos sobre el directorio de nuestro proyecto MusicDNA. De este modo, una vez que finalice el análisis, podremos ver en nuestro servidor SonarQube el resultado del mismo:

Navegando podremos ver los bugs, vulnerabilidades y principales métricas de nuestro código, así como la deuda técnica acumulada en el mismo.

¿Qué hemos conseguido en este paso?
Tener una herramienta con una base de reglas y unas métricas comunes para mantener bajo control la deuda técnica.

¿Pero qué limitaciones tenemos?
El análisis lo estamos lanzando localmente de forma manual y los desarrolladores pueden olvidarse de esta tarea. Además, estamos midiendo la deuda técnica de las versiones en desarrollo que tiene cada desarrollador en su máquina, no la deuda técnica del código integrado.

Nada de análisis exclusivamente locales: Introduciendo Jenkins en nuestro ciclo

Lo que realmente nos interesa a la hora de conseguir automatizar este ciclo de control de la deuda técnica es que los análisis de código se puedan lanzar desde nuestro servidor de integración continua, por dos razones:

  • En primer lugar porque ya no tendremos que lanzar los análisis localmente y podremos planificarlos para su ejecución como parte de las tareas o jobs de desarrollo, o en jobs aislados si así lo deseamos.
  • En segundo lugar porque en función de los resultados del análisis, podremos desencadenar eventos tales como el envío de correos, u otros más interesantes que veremos más adelante.

Lo primero que debemos hacer es instalar el plugin de SonarQube en nuestro Jenkins y, una vez hecho esto, configurar el plugin para que pueda conectarse a nuestro servidor SonarQube, en Configurar el Sistema:

Además, ya no usaremos el SonarQube Scanner local (aunque podríamos referenciarlo desde Jenkins), sino que usaremos el que el propio Jenkins se encarga de instalar, entrando en Global Tool Configuration y detallando la instalación del scanner que nos interese:

Una vez tenemos el plugin de SonarQube configurado en nuestro Jenkins, creamos un nuevo job (tarea) de Control de la Deuda Técnica, en el que indicamos, aparte del nombre del job y su descripción, el origen del código a analizar:

Y el paso de SonarQube Scanner que se ejecuta como parte del job:

Si nos fijamos, el campo Analysis properties contiene las mismas propiedades que usábamos en el fichero sonar-project.properties cuando ejecutábamos el análisis en local.

Además, si queremos que al acabar la ejecución del job, éste envíe un correo con los resultados, podemos hacer uso del plugin Email-ext para Jenkins, configurando nuestro servidor de correo en Jenkins y añadiendo un paso de envío de correos en el job de Control de la Deuda Técnica. Puedes encontrar esta configuración en la página del propio plugin en el enlace que ponemos a la wiki de Jenkins.

Una vez configurado el job por completo, podemos ejecutarlo y obtener por la consola de Jenkins los resultados del análisis:

¿Qué hemos conseguido en este paso?
Librarnos de tener que lanzar los análisis de código localmente, pudiendo planificarlos incluyéndolos dentro de nuestras tareas automatizadas de desarrollo.

¿Pero qué limitaciones tenemos?
El feedback que obtiene el equipo de desarrollo sigue siendo limitado y en momentos arbitrarios, independientes del momento en el que se integra el código.

Automatizando el análisis: Webhook desde Bitbucket a Jenkins

Para permitirnos la realización de los análisis cada vez que el desarrollador realice un push a la base de código, haremos uso de los webhooks que podemos programar desde Bitbucket Server a Jenkins.

Un webhook no es otra cosa que una petición a un enlace web concreto, en nuestro caso dicha petición estará programada cada vez que se realice un push a la rama master del repositorio, que lanzará una tarea en Jenkins que realizará el análisis de código y obtendrá las métricas de deuda técnica a través de la interfaz de SonarQube.

En el caso de Bitbucket Server, existe un add-on que nos permite programar un webhook a Jenkins desde cualquier repositorio. Este add-on se llama Webhook to Jenkins for Bitbucket y, como cualquier add-on, necesitaremos permisos de administrador en Bitbucket Server para su instalación.

Una vez instalado el add-on, desde la sección Hooks dentro de la configuración de nuestro proyecto en Bitbucket Server, habilitamos el webhook a Jenkins indicando los parámetros necesarios:

Para que el webhook funcione, es importante que en la configuración del job de Jenkins que hemos creado previamente, marquemos la opción de Consultar repositorio (SCM):

¿Qué hemos conseguido en este paso?
Introducir el control de la deuda técnica en nuestro ciclo de Integración Continua: los análisis se lanzan en el momento en el que integramos el código, obteniéndose un feedback temprano de la deuda técnica introducida a través de las notificaciones que envía Jenkins.

¿Pero qué limitaciones tenemos?
El feedback lo estamos obteniendo vía consola de Jenkins o en el mejor de los casos, vía email y... todo el mundo sabe el caso que le hacemos al email. ¿No existe una alternativa más transparente, colaborativa y actual?

Mejorando el feedback y la colaboración: Notificaciones con Slack

Slack es una herramienta de comunicación y colaboración para equipos que va mucho más allá del chat tradicional. Una de las características más interesantes que ofrece es la posibilidad de integrarse con nuestras herramientas de desarrollo a través de webhooks. De esta manera podemos hacer que Jenkins envíe avisos a Slack cada vez que un análisis finalice, y Slack publique notificaciones en el canal elegido, por ejemplo el del equipo de desarrollo que trabaja sobre el software analizado, favoreciéndose la colaboración y la transparencia sobre los resultados obtenidos y pudiendo prescindir del email como herramienta de notificación de resultados.

Para configurar las notificaciones primero debemos acceder vía web al App Directory de Slack (normalmente añadiendo /apps a la url de nuestro equipo de Slack). Allí usamos el buscador para buscar Jenkins y encontrar los datos que necesitamos para integrarla con nuestro canal. Una vez llegamos a la página de Jenkins en Slack, pulsamos el botón Add Configuration, eligiendo el canal al que queremos enviar las notificaciones (y que idealmente será el canal habitual de trabajo de nuestro equipo sobre la aplicación a analizar):

Al confirmar la integración tras pulsar a Add Jenkins CI Integration, nos aparecerán todas las instrucciones a seguir para configurar el envío de notificaciones desde los jobs de Jenkins al canal elegido de Slack.

Una vez hecha la configuración global del plugin de Slack en Jenkins, simplemente añadimos un paso a nuestro job, posterior al análisis de SonarQube (sustituyendo al de email si queremos que ya no se envíen correos), indicando lo siguiente:

De esta manera recibiremos notificaciones tanto en el caso de que el análisis falle como si resulta exitoso. Dichas notificaciones son ampliamente configurables pulsando sobre el botón Avanzado que se ve en la imagen anterior, donde podremos indicar los mensajes a visualizar. Además, desde Slack podemos configurar el nombre y la imagen de las notificaciones, obteniendo al final en nuestro canal notificaciones tan visuales y claras como las siguientes:

¿Qué hemos conseguido en este paso?
Conseguir notificaciones abiertas a todo nuestro equipo de trabajo en el momento en el que realiza el análisis, favoreciendo la transparencia y la visualización inmediata de los resultados y ayudando al control de la deuda técnica.

¿Pero qué limitaciones tenemos?
Estamos obteniendo el feedback sobre la deuda técnica en el momento en el que integramos nuestro código, de una manera automática y colaborativa, pero... ¿Se podría ir un paso más allá y acortar el ciclo de feedback a su mínima expresión, conociendo los defectos que introducimos en el mismo momento en el que escribimos el código?

Acelerando el ciclo: plugin SonarLint

Para obtener el feedback de manera inmediata (en el mismo momento en el que escribimos el código), disponemos del plugin SonarLint. Instalando SonarLint en nuestro IDE (Eclipse en nuestro caso), y configurándolo para que se conecte a nuestro servidor SonarQube y se sincronice con las reglas del perfil que consideremos oportuno, tendremos en el momento de escribir el código la información relevante acerca de la deuda técnica que estamos introduciendo, al menos en gran parte de los defectos, favoreciendo su corrección inmediata y aportando un mayor control sobre nuestra deuda técnica.

Para configurar SonarLint en nuestro IDE simplemente debemos instalar el plugin para Eclipse del mismo modo que se busca e instala cualquier otro plugin. Una vez instalado, configuramos los datos de conexión a nuestro servidor, seleccionando el submenú Window > Show view > Other... Y en la ventana que sale, elegimos SonarQube Servers dentro de la carpeta SonarLint y pulsamos Ok. En ese momento se nos muestra la vista de configuración de la conexión de SonarLint a nuestro servidor SonarQube, en la cual debemos pulsar Connect to a SonarQube Server... y configurar los datos de nuestro servidor:

Los datos de usuario y password sólo son necesarios si nuestro servidor SonarQube no tiene el permiso de realización de análisis activado para usuarios anónimos, que es como debe venir por defecto.

Por último, para conectar nuestro proyecto a un proyecto determinado de SonarQube, dando click derecho sobre el proyecto y elegiendo SonarLint > Bind to a SonarQube Project nos saldrá la lista de proyectos del servidor que hemos conectado, para elegir aquel proyecto de SonarQube al que queremos asociar nuestro proyecto local de código:

A partir de ese momento podremos ver en el propio Eclipse los defectos de deuda técnica en el código en el mismo momento en el que los vamos introduciendo:

Conclusiones

La deuda técnica es un aspecto del desarrollo de software al que debemos otorgar la máxima importancia. No se tratará tanto de eliminarla por completo como de mantenerla bajo control y asegurar que todo el equipo conoce el riesgo en el que estamos incurriendo cada vez que añadimos nuevas modificaciones a nuestro código.

En un equipo Agile de desarrollo de software prima la transparencia y la visualización temprana del trabajo y el conocimiento de los problemas, de cara a afrontarlos lo antes posible. Este Ciclo Automatizado de Control de la Deuda Técnica busca precisamente favorecer esa colaboración, de cara a tener siempre bajo control nuestros desarrollos.

Si te ha gustado este post, ¡síguenos en Twitter!

Autor

Eduardo Riol

Software Engineer in knowmad mood 💻 | Data-intensive distributed systems | Rich experience in high performance engineering teams