archivo

Archivo de la etiqueta: análisis estático

¿Cuánto tiempo dedica tu equipo de proyecto a realizar testing?, ¿cuál es la proporción respecto al esfuerzo dedicado netamente a desarrollar?, ¿se utilizan estrategias que automaticen determinados tipos de test como por ejemplo las pruebas unitarias?, ¿vas más allá y aplicas TDD?, ¿usas integración continua?, ¿en qué etapas realizas pruebas?, ¿comienzan desde el mismo proceso de análisis?, ¿cuál es la participación del usuario (o el cliente en general) en las mismas?, ¿en qué proporción es explotaratoria y en qué proporción se basa estrictamente en casos de prueba?, ¿participan personas distintas al equipo de proyecto en pruebas de tipo funcional?, ¿se realiza testing de seguridad, usabilidad, rendimiento?, dicho testing, ¿cuánto es manual y cuánto está asistido por herramientas?, ¿no se realizan pruebas de la aplicación en un entorno de integración del cliente?, ¿realizas análisis estático de código?, en dicho análisis, ¿tienes definidos unos umbrales mínimos de calidad exigibles a las distintas métricas?, cuando vas a entregar una nueva versión de un producto software, ¿haces pruebas de regresión?.

Aunque tal vez todo lo anterior se pueda resumir en par de preguntas, ¿qué nivel de importancia le das al testing en las aplicaciones que desarrollas?, ¿tienes mecanismos para comprobar si se realiza testing y para evaluar la efectividad del mismo?.

El testing se infravalora de manera muy injusta. Bien realizado ahorra muchos problemas y por encima de eso, permite conservar tu imagen y tu dinero.

Hay muchos que piensan que el testing no es ágil y yo respeto las opiniones de cada uno, independientemente de que las comparta o no. Como he dicho muchas veces, lo que no es ágil es tener que repetir trabajo no por evolucionar una funcionalidad o un componente software, sino para corregir errores que perfectamente detectables en etapas anteriores.

Es más ágil (y menos arriesgado) prevenir un incendio que intentar sofocarlo después.

Me gusta Sonar y creo que a mis compañeros también. Para ser justo, hay que mencionar también a PMD, Checkstyle y FindBugs porque Sonar debe mucho a esos proyectos.

Las métricas de Sonar asustan porque son muchas y algunas son complicadas de entender tanto en su significado como en su cálculo. Entenderlas es importante, pero tratar de interpretar a corto plazo el significado de todas puede llegar a hacer que sea algo tan abrumador que haga que se pierda el interés en todo lo que te puede proporcionar el producto.

Siguiendo este punto de vista, yo entiendo que la integración de Sonar dentro de nuestros procedimientos de certificación de la calidad del software resulta muy importante, pero también que su incorporación debe ser gradual, consolidando diversas métricas y mediante diferentes iteraciones y con tiempo, definir lo que serán nuestros márgenes de tolerancia, una vez que consigamos esto, ya será mucho más fácil ir incorporando en nuestros análisis nuevas métricas, sin olvidar de la mejora continua de los umbrales que se definan, porque sólo el tiempo y nuestra experiencia nos permitirá definir unos límites acordes a tener una deuda técnica baja, sin que suponga necesariamente un sobrecoste no asumible en los desarrollos, porque los presupuestos que tenemos son los que son y las aplicaciones, sobre todos aquellas que llevan en producción más tiempo, están como están.

Por ese motivo, probablemente nos centremos inicialmente en las siguientes métricas: Cobertura del código por pruebas unitarias, duplicidad de código, complejidad ciclomática y los comentarios, ya que son las más fáciles de interpretar y tienen repercusión directa en la deuda técnica.

Nos tocará definir, como he comentado anteriormente, cuáles serán los umbrales a partir del cual aceptaremos un software entregado, al principio nos equivocaremos y seremos o muy injustos con el proveedor o demasiado blandos, pero eso no me preocupa porque realmente lo importante es consolidar unos umbrales cada vez más acordes con la realidad y que también los proveedores entiendan que para nosotros no sólo es importante que el producto funcione, sino que también que los costes de mantenimiento se vean afectados lo menos posible por esos intereses que genera la existencia de deuda técnica en nuestras aplicaciones.

Probablemente definamos para cada métrica diferentes umbrales, ya que como he comentado en otros artículos, en el nuevo enfoque que tenemos pensado darle en las revisiones de la calidad del software y de su proceso de desarrollo y mantenimiento, vamos a definir diferentes itinerarios de validación en función de las características de la aplicación, ya que no es lo mismo un mantenimiento que un nuevo desarrollo y además todas las aplicaciones no tienen el mismo nivel de criticidad, complejidad, etc…

Soy consciente de que cada itinerario que definamos complicará un poco todo, ya que serán más umbrales los que tenemos que ajustar, pero entiendo que este incremento de complejidad es necesaria, porque umbrales generales no darán buenos resultados porque son precisamente eso, demasiado generales.

Por tanto, tenemos que ser coherentes con el número de itinerarios ya que tampoco es cuestión de tener itinerarios a la carta (para sistemas especialmente críticos sí que puede tener justificación, pero serían excepciones), para de esta forma tanto el ajuste de los umbrales no se nos escape de las manos y para tener en general, en los procesos de verificación del software y del desarrollo una visión de lo que se hace (demasiados caminos o formas de hacer las cosas, hace que la idea de conjunto se difumine y se requiera estar muy encima de todo para saber realmente qué se está haciendo y supondrá un esfuerzo que realmente no creo que merezca la pena).

En paralelo debemos empezar a trabajar con la definición de las reglas, ya que si bien son de utilidad las que Sonar trae de serie, necesitamos algo más, ya que nos gustaría que se verificase hasta donde sea posible el cumplimiento de las directrices de nuestro libro blanco de desarrollo, creado en su día y actualizado desde entonces con el objetivo de dar uniformidad a todos los nuevos desarrollos y mantenimientos evolutivos importantes, para de esta manera acotar su diversidad tecnológica y de arquitectura, facilitando de esta forma futuros mantenimientos y simplificando, hasta donde es posible, las tareas de administración del software que sirve las mismas.

Para ello, tendremos que utilizar los mecanismos de extensión de PMD. Este tema está todavía bastante verde y tocará madurar, ya que será necesario realizar ese desarrollo, pero teniendo claro qué reglas queremos que se verifiquen, además, tenemos que elegir dentro del conjunto de reglas de PMD, Checkstyle y FindBugs con cuáles nos quedamos.

Una vez realizada la extensión, tocará definir los umbrales para las reglas, que también serán variables en función de los itinerarios que se definan. Como podéis ver, si todavía nos queda camino por recorrer con las primeras métricas, no quiero decir nada lo que nos queda por andar en lo que a las reglas se refiere. En cualquier caso es cuestión de ir avanzando, aunque sea lentamente, pero avanzando.

Sonar es un producto bastante interesante y que desde mi punto de vista, debería ser tenido en cuenta en los ecosistemas de verificación de la calidad del software. Cierto es que no te dice si un producto funciona o no (cierto es que están las pruebas unitarias, pero para ello éstas deben estar desarrolladas), ya que para eso están las pruebas funcionales y no el análisis estático de código, pero sí que es bastante útil para poder evaluar la calidad de desarrollo de las aplicaciones, su mantenibilidad y su grado de adecuación a las directrices de desarrollo que se marquen.

También Sonar debería ser un referente para los proveedores de servicios de desarrollo de software, ya que la calidad de lo que se entrega puede ser un aspecto diferencial respecto a la competencia.

Si los proyectos no varían de proveedor de servicios de desarrollo de software o de responsable del proyecto, la importancia de las métricas y de la documentación pueden pasar a un segundo plano, ya que de una u otra forma el sistema de información seguirá adelante. Es cierto que las métricas y la documentación pueden resultar también de gran utilidad en estos casos, sobre todo si se quiere ver cómo evoluciona la calidad de la herramienta y las incidencias que están teniendo los usuarios en el uso cotidiano de la aplicación.

En cualquier caso el problema está en que generalmente nos solemos acordar de la documentación y de conocer métricas cuando las necesitamos y precisamente por eso, cuando tenemos que echar mano de ellas no las tenemos.

Como es lógico, esa no son las únicas circunstancias que aconsejan que se documenten los proyectos y se obtengan métricas, ya que por encima de eso está la persistencia del conocimiento de la aplicación lo que permite que la adaptación a cambios en la gestión y en los proveedores resulte menos traumática. También permitirá tener un punto de referencia para evaluar la evolución del producto en las nuevas condiciones de explotación o mantenimiento.

Por ejemplo, si se fueran a externalizar en bloque el mantenimiento de una serie de aplicaciones de una organización probablemente lo primero que querrían conocer los posibles proveedores de ese servicio sería información general de las aplicaciones: tecnologías, arquitecturas, fecha de puesta en producción, etc… y métricas: número de incidencias de relacionadas con correctivos, frecuencia de mantenimientos evolutivos, volumen, calidad y formato de la documentación, etc… Si eso se adobara con informes Sonar que indiquen la evolución del análisis estático de código de las mismas, les permitiría todavía más ser más precisos en la estimación del esfuerzo que se requeriría para realizar el servicio en función del número de aplicaciones a mantener, las características del servicio y del acuerdo de nivel de servicio. Además de todo lo anterior, les sería interesante conocer las reglas de desarrollo y de calidad del software de la organización, el ecosistema de desarrollo, las características del entorno de producción, preproducción y desarrollo: sistemas físicos, software de base y servidores de aplicaciones, la estructura organizativa del departamento de informática, el proceso de paso a producción, etc…

La complejidad ciclomática es una métrica a tener en cuenta para evaluar la mantenibilidad, comprensión, testeabilidad y probabilidad de errores de una determinada aplicación.

Este término fue propuesto por Thomas J. McCabe en 1976 y tiene como una de sus características principales su independencia respecto a los lenguajes de programación (por lo menos, de los más convencionales), por lo que teóricamente podrían ser comparables aplicaciones realizadas con tecnologías distintas en base a su complejidad ciclomática. Digo teóricamente, porque además de la algorítmica las características propias del lenguaje de programación pueden influir en que sean más sencillas o no su inteligibilidad, mantenibilidad, etc… No obstante y en cualquier caso, resulta una aproximación muy a tener en cuenta de esos factores.

¿Qué mide la complejidad ciclomática? Pues el número de posibles caminos lógicos que tiene una aplicación. ¿Quiénes crean esos posibles caminos lógicos? Los métodos, las sentencias selectivas (if, case), sentencias iterativas (while, for), lanzamiento y tratamiento de excepciones (throw, catch), devolución de resultados de un método cuando no es lá última línea del mismo (return), operadores lógicos en guardas, etc…

Cuanto más caminos lógicos tenga una aplicación, una clase o un método más complejo resulta y por tanto, requiere un mayor esfuerzo desde el punto de vista de las pruebas unitarias (el número de pruebas unitarias para recorrer todo el código crece linealmente con la complejidad ciclomática (además de cumplirse eso, se verifica que: 1) la complejidad ciclomática es menor o igual que el número de casos de pruebas que se requiere para hacer cobertura de todo el código de la aplicación (téngase en cuenta que los else no suman complejidad ciclomática), 2) la complejidad ciclomática es mayor o igual que el número de casos de prueba que se requieren para verificar que realmente se “abren” los distintos caminos físicos)).

Por tanto, una baja cobertura de una aplicación viene a decir que existe una gran cantidad de código que no se ha verificado (utilizando esta estrategia), que se recorra, por lo que probablemente si no se ha recurrido a pruebas intensivas de la aplicación, muy probablemente se traduzca en errores evitables que se detectan posteriormente, incluso en producción).

También se requiere un mayor esfuerzo para la mantenibilidad y comprensión del código (¿cuántas veces nos hemos perdido en un mar de sentencias if anidadas?) y por todo lo anterior se incrementan las posibilidades de que existan errores, porque ¿cuántas veces nos hemos encontrado con que un problema en un método era provocado porque no se metía por la guarda correspondiente de una condicional o porque no entraba en un determinado bucle?, por lo que simplemente la mera experiencia nos indica que debe existir una relación entre la complejidad ciclomática y el número de errores de una aplicación.

Como la complejidad ciclomática es el resultado de los diferentes caminos lógicos que puede tener una aplicación es lógico que esta crezca conforme más extensa (en líneas de código) es una aplicación y por regla general una aplicación con muchas funcionalidades, grande, etc…, es más compleja, requiere mayor codificación y tendrá como consecuencia una mayor complejidad ciclomática (de esta manera existirá prácticamente una relación entre una clasificación de las aplicaciones por líneas de código y una clasificación de las aplicaciones por complejidad ciclomática, es importante señalar que no tienen por qué conservar el mismo orden aunque sí más o menos estarán por el mismo entorno, es decir, la segunda aplicación con más líneas de código, puede ser la cuarta en complejidad ciclomática o la quinta aplicación con más código, la segunda en complejidad. Por tanto este tipo de complejidad es inherente a las aplicaciones y existe por el simple hecho de la existencia de las mismas y por tanto, aplicaciones con envergadura se traducen en aplicaciones complejas de mantener y eso es consecuencia de su complejidad ciclomática intrínseca.

Independientemente de que una codificación eficiente puede eliminar caminos lógicos innecesarios, existe un límite y es el que da la propia dinámica de funcionamiento de un sistema de información que provoca que se codifique su comportamiento en algoritmos que como se han comentado anteriormente pueden ser complejos. Cuando se aproxima a este límite, lo más que se puede hacer es utilizar la complejidad ciclomática para determinar si determinados métodos o clases son demasiado complejas y requerirían ser analizadas de cara a dividirlas en otras más simples, mejorando así la mantenibilidad de las mismas.

Existen algunas clasificaciones basadas en rangos de complejidad ciclomática que determinan cuando es recomendable hacer la simplificación de determinadas clases y métodos y también hay casos de éxito de la aplicación de los mismos en algunas compañías.

En muchas ocasiones a simple vista se puede determinar si un método o una clase tienen una complejidad ciclomática alta, no obstante, esta tarea puede ser agotadora si la aplicación a analizar es muy grande, por ese motivo, lo mejor es delegar esa función en analizadores estáticos de código, como es el caso de Sonar, que permite obtener métricas de la complejidad ciclomática tanto a nivel de aplicación, como de clases y de métodos y utilizando su implementación de funcionalidades de drill down ir de datos más generales a información más de detalle.

Como todas las métricas de ingeniería del software, no hay que tomarse los resultados de la complejidad ciclomática al pie de la letra, sino saber interpretar qué es lo que están diciendo y tomar medidas para reducir el impacto de dicha complejidad en la aplicación (mayor cobertura de pruebas unitarias) y para tomar decisiones de revisión de la codificación en métodos y clases complejos y su posible simplificación en otros más sencillos.