COHESION AND COUPLING
We have so far discussed that effective problem decomposition is an important characteristic of a good design.
Good module decomposition is indicated through high cohesion of the individual modules and low coupling of the modules with each other.
Let us now define what is meant by cohesion and coupling.
Cohesion is a measure of the functional strength of a module, whereas the coupling between two modules is a measure of the degree of interaction (or interdependence) between the two modules.
Two modules are said to be highly coupled, if either of the following two situations arise:
- If the function calls between two modules involve passing large chunks of shared data, the modules are tightly coupled.
- If the interactions occur through some shared data, then also we say that they are highly coupled.
If two modules either do not interact with each other at all or at best interact by passing no data or only a few primitive data items, they are said to have low coupling.
Suppose you listened to a talk by some speaker. You would call the speech to be cohesive, if all the sentences of the speech played some role in giving the talk a single and focused theme.
When the functions of the module co-operate with each other for performing a single objective, then the module has good cohesion.
If the functions of the module do very different things and do not cooperate with each other to perform a single piece of work, then the module has very poor cohesion.
Functional independence means a module performs a single task and needs very little interaction with other modules.
A module that is highly cohesive and also has low coupling with other modules is said to be functionally independent of the other modules.
Functional independence is a key to any good design primarily due to the following advantages it offers:
Whenever an error exists in a module, functional independence reduces the chances of the error propagating to the other modules.
The reason behind this is that if a module is functionally independent, its interaction with other modules is low. Therefore, an error existing in the module is very unlikely to affect the functioning of other modules.
Further, once a failure is detected, error isolation makes it very easy to locate the error.
On the other hand, when a module is not functionally independent, once a failure is detected in a functionality provided by the module, the error can be potentially in any of the large number of modules and propagated to the functioning of the module.
Scope of reuse:
Reuse of a module for the development of other applications becomes easier. The reasons for this is as follows.
A functionally independent module performs some well-defined and precise task and the interfaces of the module with other modules are very few and simple.
A functionally independent module can therefore be easily taken out and reused in a different program.
On the other hand, if a module interacts with several other modules or the functions of a module perform very different tasks, then it would be difficult to reuse it.
This is especially so, if the module accesses the data (or code) internal to other modules.
When modules are functionally independent, complexity of the design is greatly reduced.
This is because of the fact that different modules can be understood in isolation, since the modules are independent of each other.
Classification of Cohesiveness
Cohesiveness of a module is the degree to which the different functions of the module co-operate to work towards a single objective.
The different modules of a design can possess different degrees of freedom.
The different classes of cohesion that modules can possess are depicted in the following figure.
The cohesiveness increases from coincidental to functional cohesion. That is, coincidental is the worst type of cohesion and functional is the best cohesion possible. These different classes of cohesion are elaborated below.
A module is said to have coincidental cohesion, if it performs a set of tasks that relate to each other very loosely, if at all.
In this case, we can say that the module contains a random collection of functions.
It is likely that the functions have been placed in the module out of pure coincidence rather than through some thought or design.
The designs made by novice programmers often possess this category of cohesion, since they often bundle functions to modules rather arbitrarily.
An example of a module with coincidental cohesion has been shown in Figure 5.4(a).
Observe that the different functions of the module carry out very different and unrelated activities starting from issuing of library books to creating library member records on one hand, and handling librarian leave request on the other.
A module is said to be logically cohesive, if all elements of the module perform similar operations, such as error handling, data input, data output, etc.
As an example of logical cohesion, consider a module that contains a set of print functions to generate various types of output reports such as grade sheets, salary slips, annual reports, etc.
When a module contains functions that are related by the fact that these functions are executed in the same time span, then the module is said to possess temporal cohesion.
Example, consider the following situation. When a computer is booted, several functions need to be performed. These include initialisation of memory and devices, loading the operating system, etc. When a single module performs all these tasks, then the module can be said to exhibit temporal cohesion.
Other examples of modules having temporal cohesion are the following. Similarly, a module would exhibit temporal cohesion, if it comprises functions for performing initialisation, start-up, or shut-down of some process.
A module is said to possess procedural cohesion, if the set of functions of the module are executed one after the other, though these functions may work towards entirely different purposes and operate on very different data.
Consider the activities associated with order processing in a trading house. The functions login(), place-order(), check-order(), printbill(), place-order-on-vendor(), update-inventory(), and logout() all do different thing and operate on different data.
However, they are normally
executed one after the other during typical order processing by a sales clerk.
A module is said to have communicational cohesion, if all functions of the module refer to or update the same data structure.
As an example of procedural cohesion, consider a module named student in which the different functions in the module such as admitStudent, enterMarks, printGradeSheet, etc. access and manipulate data stored in an array named studentRecords defined within the module.
A module is said to possess sequential cohesion, if the different functions of the module execute in a sequence, and the output from one function is input to the next in the sequence.
Example, consider the following situation. In an on-line store consider that after a customer requests for some item, it is first determined if the item is in stock. In this case, if the functions create-order(), check-item-availability(), placeorder-on-vendor() are placed in a single module, then the module would exhibit sequential cohesion.
Observe that the function create-order() creates an order that is processed by the function check-item-availability() (whether the items are available in the required quantities in the inventory) is input to place-order-on-vendor().
A module is said to possess functional cohesion, if different functions of the module co-operate to complete a single task.
For example, a module containing all the functions required to manage employees’ pay-roll displays functional cohesion. In this case, all the functions of the module (e.g., computeOvertime(), computeWorkHours(), computeDeductions(), etc.) work together to generate the payslips of the employees.
Another example of a module possessing functional cohesion has been shown in Figure 5.4(b).
In this example, the functions issue-book(), return-book(), query-book(), and find-borrower(), together manage all activities concerned with book lending.
When a module possesses functional cohesion, then we should be able to describe what the module does using only one simple sentence.
For example, for the module of Figure 5.4(a), we can describe the overall responsibility of the module by saying “It manages the book lending procedure of the library.”
A simple way to determine the cohesiveness of any given module is as follows.
First examine what do the functions of the module perform. Then, try to write down a sentence to describe the overall work performed by the module.
If you need a compound sentence to describe the functionality of the module, then it has sequential or communicational cohesion.
If you need words such as “first”, “next”, “after”, “then”, etc., then it possesses sequential
or temporal cohesion.
If it needs words such as “initialise”, “setup”, “shut down”, etc., to define its functionality, then it has temporal cohesion.
A cohesive module is one in which the functions interact among themselves heavily to achieve a single goal.
As a result, if any of these functions is removed to a different module, the coupling would increase as the functions would now interact across two different modules. 5.3.2
Classification of Coupling
The coupling between two modules indicates the degree of interdependence between them.
Intuitively, if two modules interchange large amounts of data, then they are highly interdependent or coupled.
We can alternately state this concept as follows.
The degree of coupling between two modules depends on their interface complexity.
The interface complexity is determined based on the number of parameters and the complexity of the parameters that are interchanged while one module invokes the functions of the other module.
The different types of coupling, in increasing order of their severities have also been shown in Figure 5.5.
Two modules are data coupled, if they communicate using an elementary data item that is passed as a parameter between the two,
e.g. an integer, a float, a character, etc.
Two modules are stamp coupled, if they communicate using a composite data item such as a record in PASCAL or a structure in C.
Control coupling exists between two modules, if data from one module is used to direct the order of instruction execution in another.
An example of control coupling is a flag set in one module and tested in another module.
Two modules are common coupled, if they share some global data items.
Content coupling exists between two modules, if they share code.
That is, a jump from one module into the code of another module can occur.
Modern high-level programming languages such as C do not support such jumps across modules.
The different types of coupling are shown schematically in Figure 5.5.
The degree of coupling increases from data coupling to content coupling.
High coupling among modules not only makes a design solution difficult to understand and maintain, but it also increases development effort and also makes it very difficult to get these modules developed independently by different team members.