ConstructiCat Logo
CodeBust.
Browse section ▾

Acoplamiento (programación).

Grado de interdependencia entre módulos de software

En la ingeniería de software, el acoplamiento es el grado de interdependencia entre los módulos de software, una medida de cuán estrechamente conectadas están dos rutinas o módulos, y la fuerza de las relaciones entre módulos. El acoplamiento no es binario, sino multidimensional.

El acoplamiento suele contrastarse con la cohesión. Un acoplamiento bajo con frecuencia se correlaciona con una cohesión alta, y viceversa. A menudo se considera que un acoplamiento bajo es señal de un sistema informático bien estructurado y de un buen diseño y, combinado con una cohesión alta, favorece los objetivos generales de una alta legibilidad y mantenibilidad.

Historia

Las métricas de calidad de software de acoplamiento y cohesión fueron inventadas por Larry Constantine a finales de la década de 1960 como parte de un diseño estructurado, basándose en características de las «buenas» prácticas de programación que reducían los costes de mantenimiento y modificación. El diseño estructurado, incluyendo la cohesión y el acoplamiento, se publicó en el artículo Stevens, Myers & Constantine (1974) y en el libro Yourdon & Constantine (1979), y este último convirtió posteriormente estos términos en estándar.

Acoplamiento frente a cohesión

El acoplamiento y la cohesión son términos que aparecen juntos con mucha frecuencia. El acoplamiento se refiere a las interdependencias entre módulos, mientras que la cohesión describe cuán relacionadas están las funciones dentro de un mismo módulo. Una cohesión baja implica que un módulo determinado realiza tareas que no están muy relacionadas entre sí y, por tanto, puede crear problemas a medida que el módulo crece.

Grado

El acoplamiento puede ser «bajo» (también «flojo» y «débil») o «alto» (también «estrecho» y «fuerte»). Algunos tipos de acoplamiento, ordenados de mayor a menor acoplamiento, son los siguientes:

Programación procedimental

Aquí un módulo se refiere a una subrutina de cualquier tipo, es decir, un conjunto de una o más instrucciones que tiene un nombre y, preferiblemente, su propio conjunto de nombres de variables.

Acoplamiento de contenido (alto)
Se dice que el acoplamiento de contenido ocurre cuando un módulo utiliza el código de otro módulo, por ejemplo una bifurcación. Esto viola el ocultamiento de información, un concepto básico del diseño de software.
Acoplamiento común
Se dice que el acoplamiento común ocurre cuando varios módulos tienen acceso a los mismos datos globales. Pero puede dar lugar a una propagación incontrolada de errores y a efectos secundarios imprevistos cuando se realizan cambios.
Acoplamiento externo
El acoplamiento externo ocurre cuando dos módulos comparten un formato de datos impuesto externamente, un protocolo de comunicación o una interfaz de dispositivo. Esto está básicamente relacionado con la comunicación con herramientas y dispositivos externos.
Acoplamiento de control
El acoplamiento de control se produce cuando un módulo controla el flujo de otro pasándole información sobre qué hacer (por ejemplo, pasando un indicador de qué hacer).
Acoplamiento por estampado (acoplamiento por estructura de datos)
El acoplamiento por estampado ocurre cuando los módulos comparten una estructura de datos compuesta y utilizan solo partes de ella, posiblemente partes diferentes (por ejemplo, pasar un registro completo a una función que solo necesita uno de sus campos).
En esta situación, una modificación en un campo que un módulo no necesita puede llevar a cambiar la forma en que el módulo lee el registro. Para ilustrar el concepto de acoplamiento por estampado, considere un escenario que involucra un componente UserProfile. Este componente está diseñado para devolver toda la información del perfil de usuario en respuesta a las solicitudes, incluso cuando los consumidores solo requieren un atributo específico. Esta práctica ejemplifica el acoplamiento por estampado, que puede provocar importantes problemas de ancho de banda, especialmente a gran escala. Cuando cualquier atributo del componente UserProfile cambia, todos los consumidores que interactúan con él pueden necesitar someterse a pruebas, aunque no utilicen el atributo modificado.
Acoplamiento de datos
El acoplamiento de datos ocurre cuando los módulos comparten datos a través de, por ejemplo, parámetros. Cada dato es una pieza elemental, y estos son los únicos datos compartidos (por ejemplo, pasar un entero a una función que calcula una raíz cuadrada).

Programación orientada a objetos

Acoplamiento de subclase
Describe la relación entre un hijo y su padre. El hijo está conectado a su padre, pero el padre no está conectado al hijo.
Acoplamiento temporal
Ocurre cuando dos acciones se agrupan en un mismo módulo solo porque suceden al mismo tiempo.

En trabajos recientes se han investigado otros conceptos de acoplamiento y se han utilizado como indicadores de diferentes principios de modularización empleados en la práctica.

Acoplamiento dinámico

El objetivo de definir y medir este tipo de acoplamiento es proporcionar una evaluación en tiempo de ejecución de un sistema de software. Se ha argumentado que las métricas de acoplamiento estático pierden precisión cuando se trata de un uso intensivo de enlace dinámico o herencia. En el intento de resolver este problema, se han tenido en cuenta medidas de acoplamiento dinámico.

Acoplamiento semántico

Este tipo de métrica de acoplamiento considera las similitudes conceptuales entre entidades de software utilizando, por ejemplo, comentarios e identificadores, y apoyándose en técnicas como la indexación semántica latente (LSI).

Acoplamiento lógico

El análisis de acoplamiento lógico (o acoplamiento evolutivo o acoplamiento de cambio) aprovecha el historial de versiones de un sistema de software para encontrar patrones de cambio entre módulos o clases: por ejemplo, entidades que probablemente se cambien juntas o secuencias de cambios (un cambio en una clase A va siempre seguido de un cambio en una clase B).

Dimensiones del acoplamiento

Según Gregor Hohpe, el acoplamiento es multidimensional:

  • Dependencia de tecnología
  • Dependencia de ubicación
  • Dependencia de topología
  • Dependencia de formato y tipo de datos
  • Dependencia semántica
  • Dependencia de conversación
  • Dependencia de orden
  • Dependencia temporal

Desventajas del acoplamiento fuerte

Los sistemas fuertemente acoplados tienden a presentar las siguientes características de desarrollo, que a menudo se consideran desventajas:

  1. Un cambio en un módulo suele forzar un efecto dominó de cambios en otros módulos.
  2. El ensamblaje de los módulos puede requerir más esfuerzo o tiempo debido a la mayor dependencia entre módulos.
  3. Un módulo concreto puede ser más difícil de reutilizar o probar porque deben incluirse los módulos dependientes.

Problemas de rendimiento

Ya sea débil o fuertemente acoplado, el rendimiento de un sistema suele verse reducido por la creación, transmisión, traducción (por ejemplo, marshaling) e interpretación de mensajes y parámetros (que pueden ser una referencia a una cadena, un arreglo o una estructura de datos), lo que requiere menos sobrecarga que crear un mensaje complicado como un mensaje SOAP. Los mensajes más largos requieren más CPU y memoria para producirse. Para optimizar el rendimiento en tiempo de ejecución, la longitud del mensaje debe minimizarse y el significado del mensaje debe maximizarse.

Sobrecarga de transmisión de mensajes y rendimiento
Dado que un mensaje debe transmitirse íntegramente para conservar todo su significado, la transmisión de mensajes debe optimizarse. Los mensajes más largos requieren más CPU y memoria para transmitirse y recibirse. Además, cuando es necesario, los receptores deben reensamblar un mensaje a su estado original para recibirlo por completo. Por tanto, para optimizar el rendimiento en tiempo de ejecución, la longitud del mensaje debe minimizarse y el significado del mensaje debe maximizarse.
Sobrecarga de traducción de mensajes y rendimiento
Los protocolos de mensajes y los propios mensajes a menudo contienen información adicional (es decir, información de paquete, estructura, definición y lenguaje). Por tanto, el receptor a menudo necesita traducir un mensaje a una forma más refinada eliminando caracteres adicionales e información de estructura o convirtiendo valores de un tipo a otro. Cualquier tipo de traducción aumenta la sobrecarga de CPU o memoria. Para optimizar el rendimiento en tiempo de ejecución, la forma y el contenido del mensaje deben reducirse y refinarse para maximizar su significado y reducir la traducción.
Sobrecarga de interpretación de mensajes y rendimiento
Todos los mensajes deben ser interpretados por el receptor. Los mensajes simples, como los enteros, pueden no requerir procesamiento adicional para ser interpretados. Sin embargo, los mensajes complejos, como los mensajes SOAP, requieren un analizador y un transformador de cadenas para que muestren los significados previstos. Para optimizar el rendimiento en tiempo de ejecución, los mensajes deben refinarse y reducirse para minimizar la sobrecarga de interpretación.

Soluciones

Un enfoque para reducir el acoplamiento es el diseño funcional, que busca limitar las responsabilidades de los módulos según la funcionalidad. El acoplamiento aumenta entre dos clases A y B si:

  • A tiene un atributo que hace referencia a (es del tipo) B.
  • A invoca servicios de un objeto B.
  • A tiene un método que hace referencia a B (mediante el tipo de retorno o un parámetro).
  • A es una subclase de (o implementa) la clase B.

El acoplamiento bajo se refiere a una relación en la que un módulo interactúa con otro a través de una interfaz simple y estable y no necesita preocuparse por la implementación interna del otro módulo (véase el ocultamiento de información).

Sistemas como CORBA o COM permiten que los objetos se comuniquen entre sí sin tener que saber nada sobre la implementación del otro objeto. Ambos sistemas permiten incluso que los objetos se comuniquen con objetos escritos en otros lenguajes.

Acoplamiento frente a connascencia

El acoplamiento describe el grado y la naturaleza de la dependencia entre componentes de software, centrándose en lo que comparten (por ejemplo, datos, flujo de control, tecnología) y en cuán estrechamente están ligados. Evalúa dos dimensiones clave: la fuerza, que mide cuán difícil es cambiar la dependencia, y el alcance (o visibilidad), que indica cuán ampliamente se expone la dependencia a través de los módulos o las fronteras. Los tipos de acoplamiento tradicionales suelen incluir el acoplamiento de contenido, el acoplamiento común, el acoplamiento de control, el acoplamiento por estampado, el acoplamiento externo y el acoplamiento de datos.

La connascencia, introducida por Meilir Page-Jones, proporciona un marco sistemático para analizar y medir las dependencias de acoplamiento. Evalúa las dependencias en función de tres dimensiones: la fuerza, que mide el esfuerzo necesario para refactorizar o modificar la dependencia; la localidad, que considera cuán física o lógicamente cercanos están los componentes dependientes en el código base; y el grado, que mide cuántos componentes se ven afectados por la dependencia. La connascencia puede clasificarse en formas estáticas (detectables en tiempo de compilación) y dinámicas (detectables en tiempo de ejecución). La connascencia estática se refiere a dependencias en tiempo de compilación, como las firmas de métodos, mientras que la connascencia dinámica se refiere a dependencias en tiempo de ejecución, que pueden manifestarse en formas como la connascencia de temporización, de valores o de algoritmo.

Cada variante de acoplamiento puede presentar varios tipos de connascencia, un tipo específico o, en raros casos, ninguno en absoluto, según cómo se implemente la dependencia. Los tipos comunes de connascencia incluyen la connascencia de nombre, de tipo, de posición y de significado. Ciertos tipos de acoplamiento se alinean de forma natural con tipos específicos de connascencia; por ejemplo, el acoplamiento de datos a menudo implica connascencia de nombre o de tipo. Sin embargo, no toda combinación de acoplamiento y connascencia es prácticamente significativa. Las dependencias que se basan en el orden de los parámetros en la firma de un método demuestran connascencia de posición, que es frágil y difícil de refactorizar porque reordenar los parámetros rompe la interfaz. En cambio, la connascencia de nombre, que se basa en los nombres de los campos o parámetros, es generalmente más resistente al cambio. Los propios tipos de connascencia presentan una jerarquía natural de fuerza, considerándose normalmente la connascencia de nombre más débil que la connascencia de significado.

Las dependencias que cruzan las fronteras de los módulos o los sistemas distribuidos suelen tener mayores costes de coordinación, lo que aumenta la dificultad de refactorizar y propagar cambios a través de fronteras distantes. A menudo se emplean prácticas modernas, como la inyección de dependencias y la programación basada en interfaces, para reducir la fuerza del acoplamiento y mejorar la mantenibilidad de las dependencias.

Mientras que el acoplamiento identifica lo que se comparte entre componentes, la connascencia evalúa cómo se comportan esas dependencias, cómo se propagan los cambios y cuán difíciles son de refactorizar. La fuerza, la localidad y el grado están interrelacionados; las dependencias con alta fuerza, amplio alcance y que abarcan fronteras distantes son considerablemente más difíciles de refactorizar y mantener. En conjunto, el acoplamiento proporciona una visión de alto nivel de las relaciones de dependencia, mientras que la connascencia ofrece un marco granular para analizar la fuerza, la localidad, el grado y la resistencia al cambio de las dependencias, apoyando el diseño de sistemas mantenibles y robustos.

Acoplamiento de módulos

El acoplamiento en la ingeniería de software describe una versión de las métricas asociadas a este concepto.

Para el acoplamiento de flujo de datos y de control:

  • : número de parámetros de datos de entrada
  • : número de parámetros de control de entrada
  • : número de parámetros de datos de salida
  • : número de parámetros de control de salida

Para el acoplamiento global:

  • : número de variables globales usadas como datos
  • : número de variables globales usadas como control

Para el acoplamiento ambiental:

  • : número de módulos llamados (fan-out)
  • : número de módulos que llaman al módulo considerado (fan-in)

Coupling(C) hace que el valor sea mayor cuanto más acoplado está el módulo. Este número varía aproximadamente de 0,67 (acoplamiento bajo) a 1,0 (muy acoplado)

Por ejemplo, si un módulo tiene un único parámetro de datos de entrada y de salida

Si un módulo tiene 5 parámetros de datos de entrada y de salida, un número igual de parámetros de control y accede a 10 elementos de datos globales, con un fan-in de 3 y un fan-out de 4,