La idea de que un buen diseño debe estar basado en una alta cohesión y un bajo acoplamiento viene de los años 1980. Fue uno de los primeros principios proclamados del diseño estructurado, y pasó luego a la orientación a objetos.
¿Y a qué llamamos cohesión y acoplamiento? Tiene que ver con la modularidad, así que empecemos por ella.
Modularidad
El aporte más importante que hizo el diseño estructurado fue la idea de que, para resolver un problema complejo de desarrollo de software, conviene separarlo en partes más pequeñas, que se puedan diseñar, desarrollar, probar y modificar, de manera sencilla y lo más independientemente posible del resto de la aplicación.
Esas partes, cuando se quiere usar un nombre genérico, habitualmente se denominan módulos. De allí que otro nombre para la programación estructurada, luego caído en desuso, fue “programación modular”.
El diseño estructurado, al plantear la separación del sistema en módulos, se basó en las propias funciones del sistema. Esto es, los módulos de la programación estructurada serían los procedimientos y funciones. Por lo tanto, al modularizar, lo que hacíamos era tomar nuestra solución del problema, y separarla en partes. Deténgase aquí y asegúrese de que entiende lo que le digo: en programación estructurada modularizamos la solución, el “cómo” del desarrollo.
En el diseño orientado a objetos, en cambio, la modularización esencial se da a nivel de clases, que no son funciones del sistema, sino (al menos en una primera aproximación) entidades del dominio del problema. Por lo tanto (y asegúrese de entender también esto), en el análisis y diseño orientados a objetos, no modularizamos la solución, sino primero el problema (en el análisis) y luego, partiendo de esas clases conceptuales, del dominio del problema, modularizamos la solución (diseño). Bertrand Meyer tiene una frase bastante acertada al hablar de cómo obtener los módulos de la orientación a objetos: “no pregunte qué hace el sistema, sino a quién se lo hace”.
Por supuesto, la orientación a objetos también tiene módulos funcionales, que serían los métodos u operaciones de las clases, pero estos tienen una importancia menor respecto del módulo por excelencia, que es la clase.
Finalmente, en el diseño orientado a objetos, suele aparecer otro tipo de módulo más, el paquete, de escasa relevancia semántica, pero importante para agrupar clases en el diseño de aplicaciones medianas.
Cohesión
La cohesión tiene que ver con que cada módulo del sistema se refiera a un único proceso o entidad. A mayor cohesión, mejor: el módulo en cuestión será más sencillo de diseñar, programar, probar y mantener.
En el diseño estructurado, se logra alta cohesión cuando cada módulo (función o procedimiento) realiza una única tarea trabajando sobre una sola estructura de datos. Un test que se suele hacer a los módulos funcionales para ver si son cohesivos es analizar que puedan describirse con una oración simple, con un solo verbo activo. Si hay más de un verbo activo en la descripción del procedimiento o función, deberíamos analizar su partición en más de un módulo, y volver a hacer el test.
En el diseño orientado a objetos las cosas son más complejas. Como dijimos, hay tres tipos de módulos: clases, métodos y paquetes. Con los métodos, podemos adoptar las mismas definiciones y recetas que para los procedimientos y funciones del diseño estructurado. ¿Qué ocurriría con los otros dos?
Las clases tendrán alta cohesión cuando se refieran a una única entidad. Podemos garantizar una fuerte cohesión disminuyendo al mínimo las responsabilidades de una clase: si una clase tiene muchas responsabilidades probablemente haya que dividirla en dos o más. Y el test a aplicar sería ver si podemos describir a la clase con una oración simple que tenga un único sustantivo en el sujeto. Si la clase estuviera representando alguna operación (por la aplicación de algún patrón de diseño, por ejemplo), también habría que tratar de “sustantivarla” y aplicarle la prueba para ver si es cohesiva. Una clase con alta cohesión suele cumplir el principio de única responsabilidad.
En los paquetes no es usual analizar cohesión. Sin embargo, nadie nos impide aplicarle los mismos tests que a las clases. Sin embargo, lo crucial en los paquetes es el acoplamiento, que vamos a ver ahora.
Acoplamiento
El acoplamiento mide el grado de relacionamiento de un módulo con los demás. A menor acoplamiento, mejor: el módulo en cuestión será más sencillo de diseñar, programar, probar y mantener.
En el diseño estructurado, se logra bajo acoplamiento reduciendo las interacciones entre procedimientos y funciones, reduciendo la cantidad y complejidad de los parámetros y disminuyendo al mínimo los parámetros por referencia y los efectos colaterales.
De nuevo, el diseño orientado a objetos nos complica las cosas con sus tres tipos de módulos. A los métodos, como pasó con la cohesión, podemos analizarlos con los mismos criterios que a los módulos del diseño estructurado.
Una clase, en cambio, tendrá bajo acoplamiento cuando tenga la menor dependencia posible de otras clases. Esta dependencia significa que – si bien puede haber muchas clases que dependen de una – debería haber pocas dependencias hacia otras clases desde una sola. Las dependencias que importan son, de mayor a menor: generalización/herencia, composición, asociación y dependencia débil. Para visualizar estas cuestiones, los diagramas de clases son herramientas fundamentales.
¿Y los paquetes? Un paquete debe cumplir con estos mismos requisitos, en el sentido de que debe tener vinculaciones mínimas con otros paquetes. Decimos que hay dependencia entre paquetes cuando hay clases de un paquete que dependen de clases de otro paquete, sea por herencia, asociación o simple dependencia débil. En este caso, podemos ayudarnos con un diagrama de paquetes, que debido a que nos muestra dependencias entre conjuntos de clases, nos sirve para eliminar problemas de acoplamiento.
Etiquetas: Calidad, Diseño, Programación, pruebas unitarias
junio 30, 2009 a las 11:26 am |
[...] CyS Ingeniería de Software El blog del área de Ingeniería de Software de CyS informática s.a. « Modularidad, cohesión y acoplamiento (Carlos Fontela) [...]
agosto 22, 2011 a las 10:10 am |
Modularidad: La idea es resolver un problema complejo separándolo en partes más pequeñas, que se puedan diseñar, desarrollar, probar y modificar de manera sencilla y lo más independientemente posible. Al usar nombres genéricos estamos en presencia de módulos.
En el diseño orientado a objetos la modularización esencial se da a nivel de clases, que son entidades del dominio del problema. Por lo tanto no modularizamos la solución, sino primero el problema (en el análisis) y luego, partiendo de esas clases conceptuales, del dominio del problema, modularizamos la solución (diseño).
La POO tiene módulos funcionales, que serían los métodos u operaciones de las clases y también paquetes que son importantes para agrupar clases en el diseño de aplicaciones medianas.
Cohesión: Cada módulo del sistema debe referirse a un único proceso o entidad. A mayor cohesión el módulo en cuestión será más sencillo de diseñar, programar, probar y mantener.
Con los métodos se logra alta cohesión cuando cada módulo realiza una única tarea trabajando sobre una sola estructura de datos. Las clases tendrán alta cohesión cuando se refieran a una única entidad. Podemos garantizar una fuerte cohesión disminuyendo al mínimo las responsabilidades de una clase.
En los paquetes no es usual analizar cohesión, pero podemos aplicarle los mismos tests que a las clases. Lo crucial en los paquetes es el acoplamiento.
Acoplamiento: mide el grado de relacionamiento de un módulo con los demás. Para tener un mejor acoplamiento debemos lograr una independencia para que la relación entre los metodos, clases y paquetes sea minima.