archivo

Archivo de la etiqueta: método

Hace poco un programador me comentó que una tarea de mantenimiento le estaba llevando más tiempo del previsto debido a que la mayoría de los métodos de las clases que estaba tocando tenían un nombre que daba lugar a una mala interpretación con respecto a su función real y que en otros casos no tenía absolutamente nada que ver (algo así como si en lugar de crear un método nuevo se hubiera reutilizado otro ya obsoleto y no se hubiera cambiado su nombre).

Pueden parecer detalles pequeños, sin importancia, pero la realidad es que cuestan dinero no solo porque se requiera más tiempo para realizar un mantenimiento sino porque la probabilidad de que se produzcan errores en el mismo se multiplica.

La programación no es solo crear y encajar piezas. Es muy importante tener en cuenta que otras personas después tendrán que trabajar con él y no solo eso, escribir código de forma clara e inteligible es una señal de calidad que puede marcar la diferencia entre un tipo de programadores y otros o entre una empresa y otra.

Este antipatrón es una mala práctica de programación y se llega a él a través de la implementación de métodos que intentan ser lo suficientemente flexibles como para ser adaptado su comportamiento a multitud de circunstancias, sobrepasando el umbral de una mantenibilidad adecuada del mismo (elevado número de parámetros donde la mayoría de ellos a veces se usan y otras no, alta complejidad ciclomática, etc…).

Presenta una analogía con el antipatrón “objeto todopoderoso“, pero teniendo como protagonista a un método y no a una clase.

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.

En Sonar, a la hora de revisar el cumplimiento de reglas, una de las que aparece muy frecuentemente en el software que nos entregan es la regla PMD “Security – Array is stored directly” que se produce cuando uno de los parámetros que aparece en la definición de un método, de un constructor o de un setter (es bastante frecuente que cuando los accesores son autogenerados por el IDE o por generador de código se produzca este tipo de incumplimientos, salvo que se haya tenido en cuenta previamente) es un array y en el interior del método se realiza una asignación de dicho objeto a otro (que no es local) sin realizarse previamente una clonación (se tendría lo que algunos denominan acoplamiento entre objetos por compartir direcciones de memoria).

Si no clona el objeto resulta muy peligroso, ya que el número de objetos que apuntan a las mismas direcciones de memoria aumenta y en consecuencia se incrementa la posibilidad de errores colaterales, los cuales además en estos casos no son siempre triviales de localizar.

La métrica RFC (Response for class) forma parte, como sucede con el caso de LCOM4 del conjunto de métricas enunciadas por Chidamber y Kemerer y que tienen como objeto obtener valores de referencia sobre el diseño orientado a objetos de una determinada aplicación.

En el caso de RFC lo que se mide es el acoplamiento entre clases, ya que su valor se obtiene a partir del número total de métodos que pueden potencialmente invocados en respuesta a un mensaje enviado a un objeto de la clase, es decir, el número de métodos que pueden ser ejecutados, cuando un método de la clase es invocado.

Dicho de otra manera, vendría a ser el número de métodos de una clase más el número de métodos de otras clases que son invocados por métodos de la clase (no contando más de una vez cada método, es decir si un método de una clase Y puede ser invocado por tres métodos de una clase X sólo se suma una unidad).

¿Qué es el acoplamiento? Es el grado de dependencia entre clases, por lo que cuando nos encontramos con situaciones donde el acoplamiento es alto crecerán las posibilidades de que el mantenimiento de las clases sea más complejo, ya que un cambio en el comportamiento de un método puede afectar a todos los que lo llaman y un cambio de interfaz del método puede provocar la necesidad de modificar el código de los métodos que lo llaman. También se considera que clases con un acoplamiento alto son más complicadas de entender y dificultan las tareas de testeo.

Un ejemplo de acoplamiento, fuera del mundo de la orientación a objetos, lo tenemos por ejemplo en la dependencia entre una aplicación y una serie de objetos (por ejemplo tablas o vistas) de un esquema de base de datos de otra, en este caso, sobre todo si las aplicaciones son gestionadas por equipos distintos y todavía no están lo suficientemente maduras, se correrá el riesgo permanente de que un cambio en el modelado de datos provoque que la aplicación que hace uso de ellos deje de funcionar adecuadamente. Además se podrá ver afectada por otros factores (cambio de instancia del esquema, cambio de sistema de gestión de base de datos, etc…).

El acoplamiento entre clases es inevitable, ya que los objetos cooperan y precisamente ofrecen servicios a través de sus APIs públicas para poder ser utilizados por otros. No se trata por tanto de eliminar el acoplamiento ya que eso no será posible, sino de intentar conseguir niveles de acoplamiento entre clases bajos, ya que permitirán reducir el número de efectos colaterales en el mantenimiento del sistema, haciendo más sencillas estas tareas y reduciendo las tasas de errores en tiempo de compilación y en tiempo de ejecución (cuando se cambian comportamientos a los métodos). Además de tener en cuenta en el diseño de las clases la existencia de un bajo acoplamiento, se pueden utilizar diferentes estrategias, como por ejemplo la creación de clases donde se centralice ese acoplamiento e incluso se implementen en las mismas fachadas que orquesten llamadas a métodos, de manera que tengamos algunas clases que sí tendrán valores altos o muy altos de RFC, pero que a cambio permitirá que se reduzcan el RFC de un buen número de clases.

A través de Sonar se puede obtener la media de RFC de la aplicación, de cada paquete de la misma y del conjunto de clases que la conforman. Se trata de medias aritméticas puras, sin aplicar ningún tipo de ponderación o umbral de valor de RFC de una clase.

Ahora viene la pregunta de siempre en este tipo de métricas, ¿a partir de qué valor se puede considerar que un RFC es demasiado alto?. Como sucede en el resto de métricas (salvo algunas excepciones como LCOM4) hay interpretaciones para todos los gustos, también como sucede con las otras, queda bastante claro cuando un RFC es muy alto y un RFC es muy bajo, por lo que “desde lejos” se pueden apreciar valores que pueden recomendar el estudio del nivel de acoplamiento de determinadas clases. Se pueden considerar aceptables valores de RFC <= 50.

También es posible obtener valores relacionando el RFC de una clase y su número de métodos (NOM). En programas realizados en Java Se pueden considerar aceptables valores de RFC/NOM <= 10.