Cohesion Coupling
Cohesion Coupling
As applied to object-oriented programming, if the methods that serve the given class tend to be similar in many aspects, then the class is said to have high cohesion. In a highly-cohesive system, code readability and the likelihood of reuse is increased, while complexity is kept manageable. Cohesion is decreased if:
The functionalities embedded in a class, accessed through its methods, have little in common. Methods carry out many varied activities, often using coarsely-grained or unrelated sets of data.
Increased difficulty in understanding modules. Increased difficulty in maintaining a system, because logical changes in the domain affect multiple modules, and because changes in one module require changes in related modules. Increased difficulty in reusing a module because most applications wont need the random set of operations provided by a module.
[edit]Types
of cohesion
Cohesion is a qualitative measure meaning that the source code text to be measured is examined using a rubric to determine a cohesion classification. The types of cohesion, in order of the worst to the best type, are as follows: Coincidental cohesion (worst) Coincidental cohesion is when parts of a module are grouped arbitrarily; the only relationship between the parts is that they have been grouped together (e.g. a Utilities class). Logical cohesion Logical cohesion is when parts of a module are grouped because they logically are categorized to do the same thing, even if they are different by nature (e.g. grouping all mouse and keyboard input handling routines). Temporal cohesion Temporal cohesion is when parts of a module are grouped by when they are processed - the parts are processed at a particular time in program execution (e.g. a function which is called after catching an exception which closes open files, creates an error log, and notifies the user). Procedural cohesion Procedural cohesion is when parts of a module are grouped because they always follow a certain sequence of execution (e.g. a function which checks file permissions and then opens the file). Communicational cohesion Communicational cohesion is when parts of a module are grouped because they operate on the same data (e.g. a module which operates on the same record of information). Sequential cohesion Sequential cohesion is when parts of a module are grouped because the output from one part is the input to another part like an assembly line (e.g. a function which reads data from a file and processes the data). Functional cohesion (best) Functional cohesion is when parts of a module are grouped because they all contribute to a single well-defined task of the module (e.g. tokenizing a string of XML). Although cohesion is a ranking type of scale, the ranks do not indicate a steady progression of improved cohesion. Studies by various people including Larry Constantine, Edward Yourdon,
and Steve McConnell [3] indicate that the first two types of cohesion are inferior; communicational and sequential cohesion are very good; and functional cohesion is superior. While functional cohesion is considered the most desirable type of cohesion for a software module, it may not be achievable. There are cases where communicational cohesion is the highest level of cohesion that can be attained under the circumstances. [citation needed]
Low Cohesion (Highly Undesirable) Modules with ``low'' levels of cohesion are highly undesirable and should be modified or replaced. Strategies for doing this will be given on a separate page. Coincidental Cohesion A module that only has coincidental cohesion is one supporting tasks that have no meaningful relationship to one another. Page-Jones gives, as an example, a module (not necessarily one that can be implemented using software!) supporting the following tasks. a. b. c. d. e. f. g. Fix Car Bake Cake Walk Dog Fill our Astronaut-Application Form Have a Beer Get out of Bed Go the the Movies
The legendary - and, one hopes, mythical- FORTRAN or COBOL programmer who, after being told to use subroutines and being told of an ``ideal'' length for these, drew a horizontal line after every twenty lines of code and put each block into a module, was no doubt creating modules with ``coincidental cohesion'' (and breaking one or two other rules along the way). If you discover that the best name you can find for a module is, ``Miscellaneous Functions,'' then this a sign that your module has this undesirably low level of cohesion. There is, pretty much, no excuse for inclusion of modules whose level of cohesion is this low, in a design for a system that's to be implemented using any high level programming language.
Logical Cohesion Again, quoting Page-Jones: ``A logically cohesive module is one whose elements contribute to activities of the same general category in which the activity or activities to be executed are selected from outside the module.'' Keeping this definition in mind, consider the following example. Someone contemplating a journey might compile the following list: a. b. c. d. Go by Car Go by Train Go by Boat Go by Plane
What relates these activities? They're all means of transport, of course. But a crucial point is that for any journey, a person must choose a specific subset of these modes of transport. It's unlikely anyone would use them all on any particular journey. A logically cohesive module contains a number of activities of the same general kind. To use the module, we pick out just the piece(s) we need. Thus, a logically cohesive module is a grab bag of activities. The activities, although different, are forced to share the one and only interface to the module. The meaning of each parameter depends on which activity is being used; for certain activities, some of the parameters will even be left blank (although the calling module still needs to use them and to know their specific types)." As Page-Jones notes later on his description, a module with a name like ``Do all System I/O'' is probably a module that is only ``logically cohesive.'' Again, a module whose level of cohesion is low as this will be extremely difficult to effectively implement, test, and maintain - so it should be avoided. Temporal Cohesion A temporally cohesive module is one supporting tasks that are all related in time. Page-Jones' (somewhat dated) example is a module supporting the tasks a. b. c. d. Put out Milk Bottles Put out Cat Turn off TV Brush Teeth
and argues that these activities are (only) related by the fact that you do them all late at night, just before you go to bed. A module whose name is ``Do All Startup Activities,'' or ``Do All Shutdown Activities,'' might only have "temporal cohesion." On the other hand, it might have the higher level of cohesion that is described next. Moderate Cohesion (Acceptable)
Modules with ``moderate'' cohesion are acceptable, but not ideal. Consider modifying them, but note that changes might introduce other design problems, so that you might best leave these as they are. Procedural Cohesion A module with (only) procedural cohesion is one supporting different and possibly unrelated activities, in which control passes from one activity to the next. Page-Jones gives an example of a module (whose name might be something like, ``Prepare for Holiday Meal:'' a. b. c. d. e. f. Clean Utensils from Previous Meal Prepare Turkey for Roasting Make Phone Call Take Shower Chop Vegetables Set Table
This is a bit better than ``temporal cohesion,'' since we know that there's a fixed ``linear ordering'' of the activities. However, there's still not much reason for putting all these activities together into one module. Communicational Cohesion A module exhibits communicational cohesion if all the activities it supports use the same input or output data - or access and modify the same part of a data structure. Page-Jones gives, as an example, a module supporting the activities a. b. c. d. Find Title of Book Find Price of Book Find Publisher of Book Find Author of Book
(again, presumably, with a user to specify one, or a set, of these activities that will occur when the module is called). Another example would be a module providing the entire interface to a stack - supporting activities ``Push,'' ``Pop,'' an ``Empty?'' test, initialization of a new (empty) stack - and, possibly, operations for initialization by reading the contents from a file, and that perform a ``save'' by writing contents to a file. (Note that we've now left the kind of ``linear ordering'', or ``containment relationships,'' that we've had for levels of cohesion until now: I can imagine a module that would seem to have ``procedural cohesion" but not ``communicational cohesion'', and another module that has ``communicational cohesion'' but not ``procedural cohesion.'' For most of the kinds of cohesion defined up until this point, if a module had the kind of cohesion that had just been defined, then
it could be argued that it also had all the other kinds of cohesion that had been defined before that.) Sequential Cohesion Again, quoting Page-Jones: ``A sequentially cohesive module is one whose elements are involved in activities such that output data from one activity serves as input data to the next.'' Page-Jones gives an example of a module supporting the following activities. a. b. c. d. Clean Car Body Fill in Holes in Car Sand Car Body Apply Primer
...presumably, with the ``car'' being the input that is being ``passed'' as a parameter from task to task. High Cohesion (Desirable) Modules with high cohesion are extremely desirable, and don't need to be changed (except to correct other kinds of design problems). Functional Cohesion A module exhibits ``functional cohesion'' if it supports activities needed for the execution for one and only one problem-related task. Page-Jones gives several examples - modules with names 1. 2. 3. 4. 5. 6. 7. Compute Cosine of Angle Verify Alphabetic Syntax Read Transaction Record Determine Customer Mortgage Repayment Compute Point of Impact of Missile Calculate Net Employee Salary Assign Seat to Airline Customer
COUPLING
Page-Jones cites a set of ``principles'' that he adapts from Yourdon and Constantine's work on structured design. These principles refer to the kind of connections between modules that are desirable: 1. 2. 3. 4. 5. Create narrow (as opposed to broad) connections. Create direct (as opposed to indirect) connections. Create local (as opposed to remote) connections. Create obvious (as opposed to obscure) connections. Create flexible (as opposed to rigid) connections.
Sets (usually, pairs) of modules have connections that follow these principles if their level of coupling is low, and violate these principles if their level of coupling is high. As for levels of cohesion, you can estimate the level of coupling for a set of modules by considering each of the ``kinds'' of coupling listed below, one at a time. It's not important that you determine the precise level of coupling for a given set of modules - but it is important to decide whether this is ``unnacceptably high,'' ``high but unavoidable,'' ``acceptable,'' or ``ideal.'' Highest Coupling The following extremely high level of coupling should not be allowed (at least, not at this stage in software development) under any circumstances. Content Coupling Two (or more) modules exhibit content coupling if one refers to the ``inside'' - the ``internal'' or ``private'' part - of the other in some way. Pages-Jones gives the following examples:
Module A ``branches'' or ``falls through'' into Module B (by containing a GOTO statement that transfers control somewhere into the middle of Module B); Module A refers to, or changes, Module B's internal (and, again, ``private'') data Module A changes one of the statements in Module B's object code.
Page-Jones also calls this ``Pathological Coupling'' - and it could said with some justification that the above examples do involve ``sick programming practices.'' Fortunately, high level programming languages make these difficult - though you can certainly do these things using assembly languages (or C). ``Optimization'' is sometimes cited as an excuse for these. This is the only plausible excuse for these I can think of - you might consider resorting to some of these only after every other sensible strategy has failed to produce a program that meets the system's performance
requirements (long after you've reimplemented critical sections, used hardware components instead of software where possible, etc.) However, optimization is often unnecessary, and there are less troublesome things you can to do to improve program efficiency. Since the above practices make proper testing difficult, and program maintenance almost impossible, programming practices that introduce ``content coupling'' should be regarded as a last resort (and ideally, never be used). High Coupling These levels of coupling are undesirable, but may also be unavoidable. You should try to minimize the use of these, and use ``information hiding'' - developing and using well-defined interfaces - to limit the effects of these. Common Coupling Two or more modules exhibit common coupling if they refer to the same global data area - that is, to something that corresponds to a data store on a DFD or a ``register'' that must be shared by several processes. External Coupling Two or more modules exhibit external coupling if they share direct access to the same I/O device or are ``tied to the same part of the environment external to software'' in some other way. Moderate Coupling This level of coupling is perfectly acceptable. Control Coupling Two modules exhibit control coupling if one (``module A'') passes to the other (``module B'') a piece of information that is intended to control the internal logic of the other. This will often be a value used in a test for a case statement, if-then statement, or while loop, in module B's source code. This is perfectly acceptable. However, the program architecture (as shown by the structure chart) should make it clear that module A does control module B in this way - preferably by having module A call module B directly, or vice-versa. Then, when the system is combined together (``integrated'') and tested, the two modules will be combined together, and tested as one unit, relatively early in the process - so that any problems arising from this ``control coupling'' will be detected early on. Low Coupling
Page-Jones calls this ``Normal Coupling,'' and it's the most desirable kind of ``coupling'' of modules, if they're to be connected at all. Stamp Coupling This is a special case (or extension) of data coupling, so you may want to skip down and read about that first. Two modules (``A'' and ``B'') exhibit stamp coupling if one passes directly to the other a ``composite'' piece of data - that is, a piece of data with meaningful internal structure - such as a record (orstructure), array, or (pointer to) a list or tree. Data Coupling Two modules exhibit data coupling if one calls the other directly and they communicate using ``parameters'' - a simple list of inputs and outputs (and inputs that are modified) --- with each parameter being an ``elementary'' piece of data, such as an integer, floating point number, boolean value, member of an enumerated set, character, or (maybe) character string. The modules exhibit stamp coupling if ``composite'' data types are used for parameters as well. Ideally, this (``data coupling'') is the usual type of interaction between modules that need to communicate at all: Modules with higher levels of coupling this are only used ``when necessary.'' Lowest Level of Coupling Modules A and B have the lowest possible level of coupling - no coupling at all - if they have no direct communication and are also not ``tied together'' by shared access to the same global data area or external device. This is the ideal situation, because it implies that A and B be implemented, tested, and maintained (almost) completely independently; neither will affect the behaviour of the other Of course, it is necessary to have some communication among modules in any nontrivial system.
Types of coupling
Coupling can be "low" (also "loose" and "weak") or "high" (also "tight" and "strong"). Some types of coupling, in order of highest to lowest coupling, are as follows: Content coupling (high) Content coupling (also known as Pathological coupling) is when one module modifies or relies on the internal workings of another module (e.g., accessing local data of another module). Therefore changing the way the second module produces data (location, type, timing) will lead to changing the dependent module. Common coupling Common coupling (also known as Global coupling) is when two modules share the same global data (e.g., a global variable). Changing the shared resource implies changing all the modules using it. External coupling External coupling occurs when two modules share an externally imposed data format, communication protocol, or device interface. This is basically related to the communication to external tools and devices. Control coupling Control coupling is one module controlling the flow of another, by passing it information on what to do (e.g., passing a what-to-do flag). Stamp coupling (Data-structured coupling) Stamp coupling is when modules share a composite data structure and use only a part of it, possibly a different part (e.g., passing a whole record to a function that only needs one field of it). This may lead to changing the way a module reads a record because a field that the module doesn't need has been modified. Data coupling
Data coupling is when modules share data through, for example, parameters. Each datum is an elementary piece, and these are the only data shared (e.g., passing an integer to a function that computes a square root). Message coupling (low) This is the loosest type of coupling. It can be achieved by state decentralization (as in objects) and component communication is done via parameters or message passing (seeMessage passing). No coupling Modules do not communicate at all with one another. [edit]Object-oriented Subclass Coupling Describes the relationship between a child and its parent. The child is connected to its parent, but the parent isn't connected to the child. Temporal coupling When two actions are bundled together into one module just because they happen to occur at the same time. In recent work various other coupling concepts have been investigated and used as indicators for different modularization principles used in practice[2]. [edit]Disadvantages Tightly coupled systems tend to exhibit the following developmental characteristics, which are often seen as disadvantages: 1. 2. A change in one module usually forces a ripple effect of changes in other modules. Assembly of modules might require more effort and/or time due to the increased inter-module dependency. A particular module might be harder to reuse and/or test because dependent modules must be included.
programming
3.