Thoughts on coupling in software design

0


Coupling is a software metric that describes how closely two routines or modules are related. It is a guarantee of quality. The concept was introduced by Larry Constantine in the 1960s and was formulated in a 1974 article for the IBM Systems Journal, Structured Design, and in the 1979 delivered of the same name.

Having modules A and B, the more knowledge about B is required to understand A, the more closely A and B are linked. The fact that one module must be inspected in order to understand the operation of another is an indication of a degree of interconnection, although the degree of interconnection is not known.

Coupling is a measure of the strength of this interconnection. Coupling is affected by the type of connections between modules, the complexity of the interface, the flow of information between the module connections, and the bonding time of the module connections. Coupling is generally opposed to cohesion, for example, low coupling results in high cohesion and vice versa.

Coupling levels

The coupling can be weak / loose / weak or high / tight / strong.

Tight coupling results in ripple effects when modifying, as well as code that is difficult to understand. It tends to propagate errors between modules, when a module behaves incorrectly. This tends to make debugging and fixing bugs difficult.

In loosely coupled systems, on the other hand, individual modules can be studied and modified without the need to consider a lot of information from other modules. Errors can be reported much more easily. Debugging takes less time, while fixing faults is usually easier. The risks of error propagation between modules tend to be reduced.

The coupling levels below are ordered from top to bottom:

  • Content coupling: Content coupling, or pathological coupling, occurs when a module modifies or relies on the internal workings of another module. Changing the internal operation will lead to the need to change the dependent module. An example would be a search method that adds an object that is not found to the internal structure of the data structure used to hold the information.
  • Common coupling: Global coupling, or common coupling, occurs when two or more functions share global data. Any change to these has a ripple effect. An example of global coupling would be the state of global information about an operation, with the multiple modules reading and writing to that location.
  • Control coupling: Control coupling occurs when one module controls the flow of another by passing control information, for example, a control flag, a comparison function passed to a sorting algorithm.
  • Timbre coupling: Buffer coupling, or data structure coupling, occurs when modules share a composite data structure and use only part of it, possibly different parts. An example is that of a printing module which accepts an entity and retrieves its information to construct a message.
  • Data linkage: Data linkage occurs when methods share data, regularly through parameters. Data coupling is better than buffer coupling because the module takes exactly what it needs, without it needing to know the structure of a particular data structure.
  • Message coupling: Message coupling is the lowest form of coupling, achieved with decentralization and messaging. Examples include dependency injection and observables.

Coupling metrics

Class level

Coupling at the class level results from implementation dependencies in a system. In general, the more one class makes assumptions about another, the tighter the linkage.

The strength of the coupling is given by the stability of a class, i.e. the amount of changes in dependent classes that must be made if a class changes, and the scope of the access, i.e. that is, the scope in which a class is accessed, with the higher scope introducing tighter coupling. At the class level, the degree of coupling is measured as the ratio between the number of messages transmitted and the number of messages received, i.e.

DC = MRC / MPC

or MRC is the coupling of received messages (the number of messages received by a class from other classes), and MPC is the coupling of past messages (the number of messages sent by a class to other classes).

The class level is a special case of the module level metric.

Module level

A more general metric, this metric tracks other modules, global data and the external environment. The formula calculates a modulus indicator mc, or

mc = k / M

With k a constant of proportionality and M a value calculated by the following formula:

M = di + (a * ci) + d0 + (b * c0) + gd + c * gc) + w + r

In the above formula:

  • a, b, and c are defined empirically
  • w – the number of modules called (fan out) – and r – the number of modules calling the considered module (fan-in) is environmental coupling settings
  • gd and gc, describing the number of global variables used as data and as control, are global coupling settings
  • di, do, ci, and co, describing the number of data input and output and control parameters, are data flow and control parameters

An important note to make is that since the value of mc increases, the overall coupling decreases. In order for the coupling to increase as the degree of coupling increases, a revised coupling metric, C, can be defined as:

C = 1 – sl st

Decoupling

The introduction of coupling increases the instability of a system. Decoupling is the systematic reduction of the coupling between the modules with the explicit aim of making them more independent, that is to say of minimizing the value of C, as defined in the previous section.

Content coupling can be eliminated by following encapsulation.

The common coupling can be solved by introducing abstractions. Design patterns could be helpful in achieving good architecture.

External coupling can be solved by eliminating knowledge of domain formats, and operating on concepts.

Control coupling can be eliminated using strategies or states.

Buffer coupling can be eliminated by transmitting actual data.

Data linkage can be eliminated by using messaging.

A very important principle to guide to reduce coupling is the Demeter’s Law, shown below.

Demeter’s Law

Also called the principle of least knowledge, the Demeter’s Law is a special case of loose coupling. The principle states that a unit should only know and speak to closely related units, assuming as little as possible the structures and properties of whatever it interacts with, including its own subcomponents. For example, an object A could call a feature on object B, but should not go through B to access an object C for its functionality. Instead, object B should facilitate access through its own interface, propagating the request to its subcomponents. Alternatively, A could have a direct reference to C.

A more formal definition states that a method M on an object O can invoke the methods of the following objects:

  • O
  • the parameters of M
  • All objects created / instantiated in M
  • The direct subcomponents of O
  • A global variable, accessible by O, within the framework of M

In particular, an object must not call a method on a returned object, that is, there must be at most one point in the code, for example, a.Method (), and not aBMethod ( ).

Conclusion

Coupling is inevitable; otherwise, each module would be its own program. However, achieving low coupling should be one of the main goals of system design, so that individual modules can be studied and modified without needing to take into account a lot of information from other modules, errors can. be reported much more easily, and debugging takes less time, while fixing faults is generally easier.

Loose coupling leads to high cohesion and together they lead to maintainable systems.

The references

This article first appeared on the Codurance Blog.


Share.

Comments are closed.