lunes, febrero 13, 2017

Cohesión



La cohesión (en programación) se refiere a que tan bien están relacionados entre sí los elementos de un módulo. En el desarrollo orientado a objetos podría decirse que es el grado de relación que existe entre los métodos y variables de una clase. 

Conocer la cohesión te puede ayudar a saber si la clase cumple o no con el principio de responsabilidad única, el cual dice que una clase solo debe tener una razón para cambiar. A veces no se ve a simple vista si el diseño cumple con este principio. Midiendo la cohesion podría ayudarte a distinguir si realmente los métodos hacen cosas relacionadas entre sí.

He visto que hay más de una forma de medir la cohesión de una clase, hay herramientas que pueden auditar el código y decirte como está la cohesión en el proyecto. No he tenido oportunidad de jugar con esas herramientas, la verdad es que esta métrica no la aplico seguido; pero una forma sencilla de medirla es creando un diagrama donde a cada operación de la clase la representas con un rectángulo y cada variable como un circulo (o rectángulo con bordes redondeados). Después conectas los elementos relacionados con una línea. Una vez que se hacen todas la conexiones agrupas los elementos que tienen relación entre sí.

Si solo te sale un grupo entonces hay una alta cohesión y la clase tiene una sola responsabilidad. Si salen varios grupos entonces tiene una baja cohesión, significa que la clase tiene más de una responsabilidad  y quizás sea buena idea dividirla en otras clases, según los grupos resultantes en el diagrama.

Esto va a depender de lo que buscas con la clase, hay ocasiones en que la clase solo la quieres para tener datos relacionados entre sí, como una clase de tipo dirección sin operaciones, solo propiedades para cada parte del dato. Ahí tienes una baja cohesión; pero quizás quieras dejarlo todo en una sola clase. Esto dependerá de tu diseño, la métrica solo te da información, a ti te toca decidir que hacer con ella.

Haz un ejemplo, supón que estás trabajando en una aplicación que generará una factura electrónica, entonces creas una clase Factura con las siguientes operaciones y variables (omitiendo cosas porque esto es solo un ejemplo):

Ya que tienes las operaciones y variables dibuja unas flechas con las relaciones y reacomodas los elementos para que se vean mejor las relaciones:
Viendo las relaciones puedes identificar 4 grupos, eso te dice que la clase Factura tiene baja cohesión y que puede dividirse en varias clases. Puedes ver, también, que la clase tiene varias responsabilidades.

Separando las responsabilidades de la clase factura y buscando una alta cohesión puedes quedar con un diseño de 4 clases donde antes tenias solo una. Cada una con una única responsabilidad y "una sola razón para cambiar". 
Al final el objetivo es que el código sea fácil de entender y de mantener por ti o por alguien más. La meta no es lograr una alta cohesión, la meta es lograr un mejor diseño. Si después de separar en muchas clases, algo te dice que hubiera sido mejor dejar todo en una sola, no dudes mucho en hacer el cambio.  





3 comentarios:

  1. Buen post, "high cohesion, loose coupling" es una de esas frases que escuchas seguido en cuanto a diseño de software y tus diagramas ayudan a visualizar como podrías hacerlo.

    Un buen beneficio de separar tus clases en muchas otras es que de esa manera por lo regular es más fácil hacer tests de la lógica de cada una de las clases sin tener que modificar tanto el estado de un objeto.

    ResponderEliminar
    Respuestas
    1. El bajo acoplamiento entre esas clases es lo que ayuda a hacer fácil los test, más que la declaración de varias clases en lugar de una. Puedes tener muchas clases; pero si están altamente acopladas entonces tendrás que hacer mucho setup en cada prueba.

      Me alegra que te haya gustado el post (gracias por comentarlo). En este artículo me enfoqué en la cohesión, que como comentas, por lo general se busca alta y combinada con un bajo acoplamiento... posible tema para otro post :).

      Eliminar
    2. Nada nuevo bajo el sol.. tema relacionado a los SOLID principles..

      Single Responsabilty.. básicamente una clase debe tener una sola responsabilidad y no varias a la vez
      Open closed.. las clases deben estar abiertas para extension pero cerradas para modificación.. a excepción de los "POJOS".. jajaj
      Liskov substitution.. si tienes una clase base y una derivada.. debes poder sustituir la clase base por la derivada y no existir ningún problema
      Interface segregation.. una interfaz debe ser divida en varias interfaces especificas, es mejor que tener una de uso general (Los microservicios es una buena analogía de esto)
      Dependency inversion... básicamente te dice que debes desacoplar la clases no hacerlas dependientes si no a través de abstracciones y/o interfaces... el concepto de "inversion of control" y "dependency injection" son buenos ejemplos..

      Eliminar