Coupling and Cohesion
- Coupling - the relationship between modules in a software system.
- Cohesion - the relationships within a module
- Module - single subprogram, single class, single file, etc. Note that
modules can be "parts" of other modules.
- Good programs try to reduce the interconnectedness between modules
meaning reduce coupling and increase cohesion.
Varieties of Coupling (from bad to "good")
- Internal Data Coupling - one module (class) modifies the local
data values in another class
- Using extern for accessing variables in other files/program parts
is a form of internal data coupling.
- Friend classes have internal data coupling.
- Global Data Coupling - two or modules (classes) are bound together
by their reliance on common global data structures and/or variables.
- In the oop world, you could create a manager class to "handle" the data
that needs to be accessed. The manager class defines how that
"global" data is accessed using methods - this reduces global data
coupling to parameter coupling which is completely acceptable.
- Global Variables with file scope - can only be used within
file. These can be accessed by all the subprograms and classes
within a file but can't be accessed outside the file unless using
an extern modifier
- Global Variables with program scope - can be used by the entire
program and any modules within the program.
- With 1-d arrays, it isn't a problem to define the array within a
module and simply use general array subprograms to manipulate the
array. As long as the subprograms themselves are able to "do their
job" without knowing anything about the array other than what is
passed to them by parameters.
- With multi-dimensional arrays, this coupling is unavoidable since
all the subprograms manipulating the array require all the dimension
sizes to be hard-coded into each subprogram that receives it. The
only way to avoid this is to put the array into a structure and go
from there. The artificiality of this solutions is probably harder
to read and maintain than using global data coupling. It is still
reasonable to restrict the global data coupling to the dimensions.
- Define a struct then have all subprograms able to access the
fields within the structure however they want. If using C, there
really isn't any way to get around this problem. The closest you
can come is to create a file for the struct and the functions to
use it correctly so that any programmer using your struct has a
harder time writting poor code. If using C++ (or any other language
that has a true Abstract Data Type (ADT), the solution is to simply
create an ADT for the structure that needs to be shared.
- Control (or sequence) Coupling - One module must perform operations
in some fixed order but the order is controlled by another module.
This indicates that the designer of the module was using too low a level
of abstraction in the design. The module needing sequencing needs to
make sure itself that the sequencing is correct rather than relying
on other modules to do it.
- Parameter Coupling - one module must invoke the services and
routines of another BUT the only relationship between the two is
the number and type of parameters supplied and the type of value
returned. Very common, easy to understand, easy to see, easy
to verify statically (compile time), very useful.
- Every good subprogram uses parameter coupling. In fact, the
definition of a good subprogram is that it does its job without
any information other that what is gets through the parameter
list and what it has itself (or in some instances what the user
MUST input).
- Subclass Coupling - inheritance demands dependency so unavoidable
if using it. Again, another "good" coupling. However, only good
if inheritance is appropriate.
Varieties of Cohesion - (bad to good)
- Coincidental Cohesion - elements of a module are grouped for no
apparent reason. - usually programmer just dumps a bunch of stuff
in a module for no good reason other than to have a module. Sign
of a poor design. Objects have unrelated methods.
- Having a single subprogram calculate the area of a rectangle and
output the area to the screen. No reason to have the output in the
subprogram other than whim.
- Having files that contain things like get_int(), calc_area_rect(),
print_menu(). Again, these subprograms have nothing in common and
should not be in the same file.
- Logical Cohesion - there is a logical connection between the
elements but no actual connections based on data or control. -
This is typical of libraries. They do make sense.
- Temporal Cohesion - the elements are bound together simply because
they all do "something" at the same time. Initialization of
all the data for example. Better to have the modules deal with
their own initialization.
- Communication Cohesion - elements are grouped together because
they must all use the same input/output data or devices. Usually,
this ends up being a manager and should be designed as such. In actuality,
the stdio.h and iostream.h libraries both communicate with the same
device so could be considered to exhibit communication cohesion as
well as logical cohesion.
- Sequential Cohesion - usually a result of trying to get rid of
sequential coupling. Still indicates a design based on too low a
level of design.
- Functional Cohesion - desirable since all the functions are grouped
because they all work together to produce a "single function".
- Data Cohesion - a module internally defines a set of data values
and exports (makes visible) a set of methods to manipulate that
data - every good ADT should exhibit data cohesion.
- Every good ADT should exhibit data cohesion.
- In languages that don't have a true ADT, like C, you can only get
something kinda like data cohesion using files to simulate
the class idea. Not great but at least better than nothing.