archivo

Archivo de la etiqueta: acoplamiento

Sistemas altamente acoplados, con clases y métodos kilométricos, con código que resulta complicado de entender son ejemplos en donde realmente se programa con miedo una vez que se comprueba que tocarlo supone implicaciones hasta en las partes más insospechadas de la aplicación.

Si el sistema además es crítico el miedo pasa a convertirse en pánico.

Tal vez las palabras miedo o pánico sean demasiado exageradas (y no es nada positivo trabajar de esa manera) pero por lo menos el programador debe sentir respeto y estar alerta cuando realiza modificaciones en un sistema de este tipo. El exceso de confianza no es bueno y más en un caso como este.

Hay que evaluar si el cambio que se va a hacer en el sistema es algo puntual o si se sabe que van a existir una serie de cambios a corto y medio plazo, así como la magnitud de los mismos y la magnitud del sistema. El esfuerzo que supone realizar estos cambios (mucho mayor que en un sistema con una deuda técnica ajustada a sus características), el esfuerzo en testing y el riesgo que tiene liberar nuevas versiones de estos sistemas debe ser analizado antes de afrontar la mejor estrategia para el cambio.

En condiciones como esta, cambios que sean fruto de un capricho no deben ser contemplados y cambios muy relevantes que supongan una modificación sustancial del sistema podrían dar lugar a que se tome la decisión de desarrollar una nueva aplicación.

El programador por su parte puede tomar sus precauciones: testing unitario, automatización de determinado testing de mayor nivel, etc…

Por otro lado, el paso a producción de nuevas versiones de sistemas de estas características no debe tratarse a la ligera y esperar cruzando los dedos a que no pase nada.

El testing debe ser realizado en profundidad y desde el punto de vista funcional debería ser la combinación de casos de prueba y testing exploratorio.

Para Bob C. Martin un software que presenta algunos de los siguientes defectos tiene un mal diseño:

1) Rigidez: Es complicado realizar cambios porque cada cambio afecta a otras partes del sistema.
2) Fragilidad: Cuando realizas un cambio, partes insospechadas del sistema empiezan a fallar.
3) Inmovilidad: Es difícil reutilizar código en otra aplicación porque no puede ser separado de la aplicación en la que se está usando.

Es importante incidir en que Martin se está centrando en aspectos de diseño y de arquitectura y no en aspectos de programación (pese a que al final estos problemas se hagan evidentes en el proceso de desarrollo y en las actividades de mantenimiento o evolución del sistema), por ese motivo los defectos que plantea están relacionados con factores como la modularidad, el alto acoplamiento, la baja cohesión y la alta complejidad ciclomática (entre otros).

Un buen diseño se valora cuando has trabajado con sistemas que no lo tienen, en los cuales realizar cualquier tarea de mantenimiento se encuentra con una resistencia que hace que los costes se disparen, sin que por ello se garantice que el producto va a pasar a producción con menos errores que los que tenía antes.

Entregar por entregar una versión de un producto es algo que desgraciadamente estamos muy habituados a ver.

La entrega de software de baja calidad tiene consecuencias negativas, muchas más que si no hubieras entregado el producto a tiempo (por regla general):

– Cuando se entrega un software y se rechaza no solo estás perdiendo tiempo y dinero tú, sino también el cliente.

– Cuando se entrega un software con un elevado número de errores se incrementa la probabilidad de que alguno de ellos y de importancia llegue a producción, lo que puede provocar la liberación de un nuevo parche o de una serie de parches. Con eso también pierde dinero el cliente (mucho más ya que ha podido dejar bloqueado total o parcialmente un proceso, lo que ha provocado que una serie de trabajadores estén por debajo de su rendimiento habitual) y también lo perderás tú.

– Cuando se entrega un software con una deuda técnica alta estás condicionando su evolución, aquí también pierde dinero el cliente por el coste extra que tendrán las tareas de mantenimiento y por los posibles efectos colaterales que provoquen las nuevas versiones (si el software se encuentra muy acoplado y el testing no es suficiente) y también lo perderás tú, sobre todo si trabajas en proyectos a coste fijo.

Entregar software a la ligera por el simple hecho de cumplir una fecha o por pensar que no pasa nada, que ya se corregirán los defectos hace mucho daño, no solo al proyecto, ya que cuando se generalizan esas prácticas también se hace mucho daño a la profesión. Si queremos mejorar nuestras condiciones y la percepción que terceros tienen de nosotros necesitamos que no se nos vea como chapuceros.

Este antipatrón se basa en la utilización dentro de un mismo sistema de diferentes “clases de propósito general”, “clases hombre-orquesta” o “clases multicasuística” en las cuales están definidos una amplia gama de comportamientos con el objeto de poder ser utilizados por otras.

También es frecuente encontrarlo en implementaciones de componentes en los que se delegan funcionalidades de otros, con el objeto de dar un amplio rango de alternativas posibles al cliente.

El problema no es dar esas facilidades, sino que el problema se encuentra en la complejidad que se le añade al código como consecuencia de las mismas (generalmente alto acoplamiento, baja cohesión, alta complejidad ciclomática, etc…).

En el antipatrón “objeto todopoderoso“, la funcionalidad de la aplicación pivota generalmente sobre una de estas clases, mientras que en la navaja suiza se trata de diferentes clases (generalmente, de utilidad) que contiene el sistema.

Un claro síntoma de que un código ha sido desarrollado por personal que todavía necesita más experiencia y cualificación es la existencia de clases que concentran gran parte de funcionalidad del sistema, de manera que el sistema pivota alrededor de las mismas (generalmente una de ellas).

Estas clases presentarán como mínimo una baja cohesión, tendrán una complejidad ciclomática superior a la media del resto de clases y probablemente mostrarán también un alto acoplamiento.

Boris Beizer es un autor e ingeniero de software americano (aunque nacido en Bélgica) especializado en el campo de la calidad del software y del testing. Sus primeras publicaciones datan de finales de la década de los cincuenta, aunque su etapa más prolífica fue en las décadas de los setenta y de los ochenta.

El testing es un campo dentro de la ingeniería del software un tanto controvertido. La mayoría de los profesionales consideramos necesarias las pruebas en el proyecto de desarrollo de software, si bien no hay coincidencia en cuanto a la intensidad, los momentos y la metodología.

Soy de la opinión de que no todos los proyectos y sistemas de información deben tener un mismo tratamiento y que independientemente de que exista una cierta metodología en las pruebas, estas deben girar alrededor del testing ágil y del exploratorio.

También soy partidario de que las clases con mayor acoplamiento sean cubiertas mediante pruebas unitarias (no necesariamente desarrollando según técnicas de desarrollo guiadas por las pruebas (TDD)) y que se deben minimizar los efectos colaterales a través de las pruebas de regresión.

En cuanto a los momentos, el testing debe aplicarse desde las etapas más tempranas del software, si bien los actores pueden ser distintos a las pruebas realizadas sobre el producto.

Y como estrategia, la utilización de integración continua permite detectar problemas de carácter unitario y de integración lo antes posible y a reducir los problemas en la fase de implantación.

Boris Beizer realiza la siguiente reflexión (traducción libre): “Una amenaza bien vale mil pruebas”.

Desgraciadamente nos acordamos de un proceso de testing bien realizado cuando ya los errores han salido a la luz y lo peor de eso, cuando su corrección requiere de un esfuerzo considerable, cuando ha impactado gravemente en el negocio o cuando nos crea un problema.

Cuando mayor sea la criticidad del sistema más peso debe tener el proceso de testing y más peso debe cobrar la metodología y sistematización.

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.