archivo

Archivo de la etiqueta: Sonar

Interesante la reflexión que Martin Fowler realiza en su libro “Refactoring: Improving the Design of Existing Code” (traducción libre): “Al compilador no le preocupa que el código sea feo o limpio. Pero cuando cambiamos el sistema, hay una persona involucrada y ahí sí que importa. Un sistema mal diseñado es complicado de modificar”.

En última instancia somos las personas las que tenemos responsabilidad sobre la deuda técnica no hay nadie más entre nosotros y el código. Es cierto que podemos apoyarnos en generadores de código y en frameworks pero es decisión de la organización, del departamento o nuestra elegirlos y en muchos casos de su evolución. Son importantes en cuanto a que te evitan la realización de tareas mecánicas y en cuanto a que marcan un camino común en el desarrollo pero hay que tener en cuenta que es importante que el código generado sea de calidad porque es posible que en un futuro el equipo que se vaya a encargar de seguir evolucionando el producto no disponga de ese generador (desgraciadamente es algo que casi nunca se tiene en cuenta).

Hay software como Sonar que utilizado de manera conjunto con un software de integración continua nos permite conocer al día el estado de la deuda técnica pero se trata solo de métricas que nos pueden alertar de situaciones anómalas (o potencialmente anómalas) al final habrá una persona (no necesariamente un gestor ya que el programador también tiene mucho que ver en esto) que tomará la decisión de refactorizar o no determinadas partes de la aplicación.

Lo más recomendable es que la propia refactorización sea parte del proceso de desarrollo que surja como algo natural y que nos apoyemos en software para conocer si hay módulos en donde el trabajo de refactorizar no ha sido suficiente o no ha sido bueno.

En mi organización vamos a realizar un estudio de una serie de sistemas de información (entre el 50 y el 75% aproximadamente de los mismos) con el objeto de detectar en ellos una serie de clases que pueden resultar conflictivas desde el punto de vista de la mantenibilidad.

Cualquier clase que cumpla alguna de las siguientes condiciones la consideraremos sospechosa (son solo métricas, que pueden encender determinadas alarmas, pero después resulta aconsejable revisar si existe justificación o no en que tomen esos valores) y será objeto de estudio con la finalidad de tomar una decisión sobre la necesidad de su refactorización:

1) Acoplamiento. Utilizaremos como base la métrica RFC de Chidamber y Kemerer.

RFC(clase)>=50 y RFC(clase)/Nº Métodos(clase)>=10

2) Cohesión. Utilizaremos como base la métrica LCOM4 de Chidamber y Kemerer.

LCOM4(clase)>=2

3) Complejidad Ciclomática de Thomas J. McCabe.

Complejidad Ciclomática(clase)/Nº Métodos(clase)>=10

Los valores anteriores por cada clase se obtendrán utilizando las métricas obtenidas a partir de Sonar.

Además de la separación entre el mundo físico y el lógico, el hecho de que el software no se desgaste es a mi juicio una de las dos principales diferencias que tiene con el hardware, sobre todo teniendo en cuenta las tendencias actuales en el mundo del desarrollo orientadas a su industrialización, la reutilización de componentes, la delegación de funcionalidades en otros sistemas, etc… Si bien es cierto que el software tiene un componente de desarrollo a medida que es inherente a él mismo, ocurriendo esto incluso en la orientación al producto, donde en muchos casos hay que hacer adaptaciones para clientes concretos.

La otra diferencia es el propio proceso de obtención de un nuevo componente físico donde no es posible conseguir nada si no se disponen de los materiales necesarios, si se dispone de la materia prima la cadena de montaje empieza a funcionar hasta que se obtiene el producto. Es decir, la obtención de un nuevo producto idéntico a otro tiene un coste. Con el software no pasa eso, una vez construido obtener una copia es algo inmediato y sin coste. Lo mismo pasa con otros productos lógicos digitales como la música o el vídeo.

El software una vez desarrollado no se desgasta, no se estropea. Puedes dejar un programa diez mil años en un dispositivo y sobrevivirá tanto tiempo como el dispositivo que lo contiene y si antes lo has copiado garantizará su continuidad en otro (otra cosa distinta es que se pueda ejecutar o interpretar, este tema lo trato en el artículo: “La oscura era digital”).

Pero el software sí se deteriora, sufre mucho con los mantenimientos, ya sean correctivos, evolutivos, adaptativos o perfectivos (depende de lo que se quiera perfeccionar). El deterioro no tiene por qué ser idéntico en todos los sistemas. Dependerá de muchos factores: la calidad del producto final (a nivel de arquitectura y codificación), su tamaño, de si el equipo de mantenimiento es distinto del de desarrollo y ha existido un período de transición suficiente para poder hacerse cargo de la herramienta, de la urgencia con que sea necesario realizar los mantenimientos y de la cantidad de los mismos (si todo es prioritario y para ya, hay un problema) y de la metodología utilizada (si la misma hace hincapié en la refactorización del código con el objeto de controlar su nivel de calidad y simplicidad el deterioro será sensiblemente menor).

De manera objetiva pudimos comprobar esto en mi organización tras los primeros meses de implantación de Sonar.

Para este año que comienza, en mi departamento deberíamos plantearnos seriamente un par de objetivos (entre otros muchos). Uno de ellos ya se ha puesto en marcha, aunque todavía no está ejecutado y es la automatización de los despliegues en el entorno de desarrollo y otro que deberá venir después de este que son las entregas en el entorno de pruebas.

En ambos casos la idea es sencilla, situando los fuentes en la rama correspondiente del SVN y teniendo alojadas las librerías dependientes en Artifactory, el proveedor a través de Hudson solicitaría el proceso de compilación y despliegue. En ese proceso un Sonar que tendríamos habilitado en cada entorno (hasta ahora solo lo tenemos en pruebas) recogería las métricas fruto del análisis estático de código y un plugin para Hudson que se está terminando de implementar instalaría la aplicación en el Tomcat adecuado.

Puede parecer que es poco, pero cumpliendo ambos objetivos estoy seguro que mejoraremos en productividad. En el caso del entorno de desarrollo porque daremos a los proveedores la posibilidad de probar el producto en nuestro entorno independientemente de la fase de construcción en la que se encuentre (algo importante porque así se reducirá el número de entregas rechazadas por causas dependientes del entorno) y en el caso del entorno de pruebas porque ahorraremos tareas a nuestro equipo de calidad y a nuestros compañeros del departamento de producción.

En el caso del entorno de pruebas, el problema inicialmente estaba en que los proveedores no debían conocer determinadas claves de acceso (por ejemplo la contraseña del usuario de conexión en base de datos), pero eso queda resuelto ya que las claves se pueden alojar en un fichero independiente y los proveedores simplemente apuntar a él.

Todavía quedaría otros aspectos en los que trabajar, como por ejemplo intentar automatizar la ejecución de determinados scripts en base de datos, el alta o modificaciones en la configuración en terceros entornos, como por ejemplo, Alfresco, etc…, pero independientemente de que trabajemos en esto, si conseguimos realizar de manera adecuada los dos objetivos planteados, notaremos sin duda, los resultados.

La implantación de procedimientos dentro de un departamento de desarrollo de software produce beneficios y por tanto un retorno de la inversión.

El principal inconveniente que encuentra es la reticencia del personal a cumplirlos ya que en su mayoría piensan que toda esa burocracia es una pérdida de tiempo.

El primer error es pensar que se trata de burocracia o por lo menos en el sentido negativo en el que se suele entender ese término, obligarte a seguir una serie de pasos para realizar determinadas acciones no es burocracia, son procedimientos. Esto no quita que el diseño de los procedimientos deba ir acorde con las posibilidades que tiene el departamento, si se va más allá de lo que se puede abarcar, estamos ante una situación contraproducente (no se terminarán por seguir los procedimientos y además se producirá una reducción de la eficiencia).

No es necesario empezar a procedimentarlo todo de la noche a la mañana. Lo mejor es ir poco a poco, que el personal se vaya acostumbrando a esta otra forma de trabajar, más ordenada, que permite, por todos, una mayor control de las acciones que se realizan.

Los procedimientos irán acompañados de herramientas (o por lo menos es aconsejable). En mi organización los procedimientos internos del departamento de desarrollo y nuestra interacción con el resto de departamentos del área TIC se realizan básicamente con 5 herramientas:

– Un Service Desk como componente que integra todo el conjunto de incidencias y peticiones en producción.
– Redmine como sistema de gestión de proyectos: planificación de tareas e interfaz con el repositorio documental (en nuestro caso Alfresco, aunque perfectamente se podría haber utilizado la propia herramienta como gestor documental).
– Alfresco, como repositorio documental.
– Mantis para el reporte de incidencias en la fase de pruebas de la aplicación.
– Una software de agenda compartida, para la gestión de nuestras citas y reuniones.

Como comenté antes, no se trató de implantar un conjunto de procedimientos de la noche a la mañana, sino que se hizo paulatinamente, asimismo no todas las herramientas se implantaron a la vez, ni el grado de uso de las mismas fue intenso desde el primer momento. Ha sido el tiempo y también determinadas decisiones de los responsables de informática los que han consolidado los procedimientos y las herramientas.

No son las únicas herramientas que utilizamos en el departamento de desarrollo ya que la realización de determinados procesos, requieren de otras herramientas complementarias que nos aportan, además una serie de ventajas:

– Subversion: Como sistema de gestión de fuentes y sus versiones.
– Artifactory: Como repositorio de librerías dependientes.
– Hudson: Para la automatización del proceso de compilación, generación del desplegable e interacción con Sonar (tenemos previsto próximamente el uso de Hudson para realizar el despliegue completo de una aplicación).
Sonar: Para el análisis estático de código.
– Enterprise Architect: Diseño de modelos (requisitos, casos de uso, etc…) y de documentación a partir de los mismos.

Como he comentado antes, los procedimientos requieren herramientas y las herramientas procedimientos, los unos sin los otros no terminan por producir buenos resultados.

Los procedimientos deben estar por escrito y ser dados a conocer por quienes los tienen que cumplir y se debe hacer un seguimiento de su implantación, por lo menos hasta que se consiga que la organización asimile la nueva dinámica de funcionamiento.

¿Por dónde se empieza? Supongamos que ya tenemos definida una dinámica de trabajo en cuanto al propio proceso de codificación de software, si no es así, ese debe ser el inicio (es decir, habría que establecer un framework de desarrollo, la selección de un IDE, de un sistema de gestión de versiones, una herramienta de integración continua, etc…, unos entornos de preentrega, un sistema de atención interna de dudas, sugerencias, etc… en el proceso de desarrollo (así como la persistencia de aquellas que sean más interesantes, para permitir la consulta futura), etc…

A partir de ahí, el siguiente paso debe ser controlar hacia dónde se enfoca la dedicación de los empleados, lo que hace necesario la existencia de una herramienta de imputación horaria. Esta gestión de incurridos es fundamental si la función principal de tu organización es la prestación de servicios a terceros. En el caso de mi organización no tenemos ninguna herramienta de esas características porque somos principalmente clientes de los trabajos (lo que ha hecho que no sea algo prioritario).

A continuación se debe trabajar en la gestión de las entradas de incidencias y peticiones por parte de terceros, así como su planificación. De esta forma se consigue dar un orden al trabajo, saber qué esta haciendo cada cual en cada momento y poder planificar los recursos humanos en el tiempo, de manera que se reduzca el número de tiempos muertos y cada persona se utilice, en la medida que sea posible, en aquellos proyectos y actividades donde se pueda aprovechar de mejor manera su potencial.

Lo comentado en el párrafo anterior se puede hacer en paralelo, con la obligación de que cada reunión con un cliente tenga como resultado final un acta (siguiendo en la medida de lo posible un mismo formato y que se almacena de la misma forma para todos los proyectos), que además debe ser enviada a los mismos. Como podéis ver, estos procedimientos que no requieren gran esfuerzo implantarlos, producen beneficios innegables. Solo requiere pequeños cambios en algunas de las rutinas de los empleados (el desarrollo de software es mucho más que tener abierto Eclipse toda la jornada laboral).

Una vez llegado a este punto resulta recomendable integrar el sistema de imputación horaria con el sistema de planificación de proyectos para tener el tiempo real que se ha invertido en cada tarea.

Sabemos cuánto se ha presupuestado cada proyecto, cuánto se lleva invertido en cada uno y aproximadamente el grado de avance en los mismos. Con esas variables es posible conocer el estado de los costes de cada proyecto, algo fundamental para detectar desviaciones a tiempo y tomar medidas (de nada sirve detectar que hay problemas si no se toman decisiones al respecto).

¿Por dónde se sigue? A partir de aquí, entrarán en juego, las preferencias personales. En mi caso, yo potenciaría el establecimiento de una normativa documental en los desarrollos apoyada en una herramienta CASE. Los desarrolladores odian documentar, principalmente porque no se sabe documentar (duele, pero es la verdad) y porque no se tiene un procedimiento, técnica y mecánica para hacer que ese proceso “insufrible” sea menos doloroso, es decir, que haga que el proceso de documentación sea más eficiente y productivo. Si con documentación vas a tener problemas con el cliente de todas maneras, ya sabemos todos los problemas que se tiene cuando se carece de ella, donde al final el cliente meterá casi tantos goles por la escuadra como quiera, ya que él dispone de todas las cartas y tú de ninguna. Además, la documentación puede guiar el proceso de desarrollo, cuestión de acostumbrarse a trabajar con ella y además permite dar un acabado a los proyectos que puede dar lugar, en muchos casos, a marcar la diferencia entre un proveedor y otro.

¿No crees en los procedimientos? Prueba a implantar alguno, hazle un seguimiento y mide los resultados, lo mismo cambias de opinión.

El puglin de Sonar Quality Index proporciona otra métrica agregada (resultado de otras métricas) para obtener un valor que indique la calidad del software. En este caso lo que se pretende es obtener un valor entre 0 y 10.

Particularmente me gusta más SIG MM ya que se centra en la mantenibilidad que es lo que realmente me preocupa sobre el software que nos entregan, pero todo es cuestión de gustos y de lo que cada uno valore lo que te calcula la métrica y lo claro que te exprese los resultados. Desde mi punto de vista este indicador da demasiado peso a la verificación de reglas PMD y pone casi al mismo nivel la verificación de estilos que la complejidad ciclomática y no otorga ningún valor al acoplamiento o a la cohesión (algo de lo que también adolece SIG MM).

Para su cálculo se basa en la obtención previamente de cuatro métricas:

– Violaciones de código: basada en los resultados obtenidos mediante la aplicación de las reglas PMD y se calcula a partir de la siguiente fórmula:

Coding Violations = (Blocker * 10 + Critical * 5 + Major * 3 + Minor + Info) / validLines

donde validLines es el número total de líneas de código de la aplicación menos el código duplicado. Como puede darse el caso de que la métrica código duplicado supere al número de líneas de código cuando ocurre esto el valor de validLines es 1. Como casi todas las métricas de Quality Index se hacen en relación al número de líneas válidas la influencia de la duplicidad de código en los resultados finales es importante (como también lo es en el cálculo de otras métricas como Technical Debt o SIG MM, algo que me parece totalmente razonable. Esto va a provocar en consecuencia que soluciones basadas en generadores de código, salvo que éstos estén muy depurados van a verse muy perjudicadas por esta métrica.

– Complejidad: basada en los resultados obtenidos mediante la obtención de la complejidad ciclomática de los diferentes métodos y se calcula a partir de la siguiente fórmula:

Complexity = (Complexity>30 *10 + Complexity>20 * 5 + Complexity>10 * 3 + Complexity>1) / validLines

Como se puede apreciar se le da un peso importante a métodos con una complejidad ciclomática alta que son aquellos que al presentar un mayor número posible de caminos lógicos hace que sean más complicados de mantener

– Cobertura: Se obtiene directamente a partir de la cobertura de código por pruebas unitarias (mirando un comentario del código del plugin (clase CoverageDecorator.java) no tiene en cuenta para el cálculo de esta métrica las líneas duplicadas.

– Violaciones de estilo: basada en los resultados obtenidos mediante la aplicación de las reglas PMD y se calcula a partir de la siguiente fórmula:

Style = (Errors*10 + Warnings) / ValidLines * 10

Una vez calculadas las métricas ya se puede tener el valor de Quality Index:

QI = 10 – (4.5 * Coding – 2 * Complexity – 2 * Coverage -1.5 * Style)

El plugin además de calcularte el valor global, te indica el valor de las 4 métricas (ejes) llevados a la escala correspondiente en función de su peso en la fórmula del cálculo de la métrica, representando en rojo la proporción que incumple y en verde la proporción que cumple.

Se codifica, se construye la aplicación, pero en demasiadas ocasiones se tiene en cuenta como fin único la entrega del proyecto, dejando al margen o dedicándole menos importancia a una programación pensando en futuros mantenimientos.

La dificultad de los mantenimientos depende de muchos factores y algunos de ellos están por encima en importancia de una codificación clara y de calidad, como por ejemplo la búsqueda de una alta cohesión y un bajo acoplamiento, lo cual no debería ser una excusa para olvidarnos de este asunto ya que no se trata solo de que se pueda comprender lo que se ha programado (que no es poco) sino que un código poco cuidado probablemente influirá en una mayor complejidad ciclomática de la aplicación (además de a la mayoría de las variables que determinan la deuda técnica de la aplicación) dificultando, en consecuencia, a la mantenibilidad.

Generalmente nos solemos acordar de todo esto cuando toca realizar el mantenimiento del sistema de información y nos encontramos con que la forma en que se ha codificado hace que se requiera un mayor esfuerzo y en consecuencia coste. Por este motivo importa y mucho como se codifica.

El problema de todo esto es que resulta complicado detectar este tipo de problemas en tiempo de desarrollo ya que obliga a estar encima y revisar el código, lo que puede hacer que casi cueste más el collar que el perro. Por tanto, tenemos que utilizar otras estrategias que faciliten la localización de estos problemas, como es por ejemplo estudiar variables que se pueden incrementar indirectamente por una mala programación (se puede realizar una revisión periódica de las métricas que devuelve Sonar) y complementarlo, si es posible, con la revisión, también periódica, de una muestra de clases de la aplicación.

Siendo realista, veo complicado que una empresa de desarrollo, salvo que las deficiencias encontradas en el proceso de verificación interno sean serias, se pongan a rehacer a módulos ya codificados, pero por lo menos si se aplican estas políticas se puede reconducir la tendencia en el desarrollo y que el proyecto se encuentre dentro de unos umbrales de calidad aceptables (los cuales en algunos casos podrán ser exigidos y verificados por el cliente y provocar un rechazo en la entrega y la consiguiente necesidad de refactorizar partes de la aplicación lo cual se volverá en contra del proveedor ya que tendrá que sufrir en sus carnes las consecuencias de unas malas prácticas.

Martin Fowler es un importante y reconocido autor especialista en ingeniería del software y en el proceso de desarrollo (particularmente en el campo de la refactorización) el cual ya he tenido la oportunidad de citar en un artículo sobre una regla de CheckStyle que no comprendía su significado.

Steve C. McConnell es otro reputadísimo autor y especialista en ingeniería del software, tanto es así, que durante años fue considerado junto a Linus Torvalds y Bill Gates unas de las personas más influyentes en el negocio del desarrollo de software. En la actualidad posee una empresa llamada Construx Software que se dedica a consultoría y formación sobre buenas prácticas en desarrollo de software.

Ambos autores son responsables de las siguientes citas relacionadas con la comprensión del código:

Martin Fowler (traducción libre): “Cualquiera puede escribir código que un ordenador pueda entender. Los buenos programadores son aquellos que escriben código que los humanos puedan entender”.

Steve McConnell (traducción libre): “El buen código es su mejor documentación. Cuando vayas a escribir un comentario, pregúntate, ¿cómo puedo mejorar el código para que este comentario no sea necesario?”.

Sobre este tema ya publiqué una cita que se atribuye a Martin Golding en unos casos y a John F. Woods en otros que complementa perfectamente a éstas.

Como he comentado en otras ocasiones, hacer las cosas bien, tarde o temprano, marca la diferencia.