Coupling And Cohesion

Given two lines of code, A and B, they are coupled when B must change behavior only because A changed.

They are cohesive when a change to A allows B to change so that both add new value.

The difference between CouplingAndCohesion is a distinction on a process of change, not a static analysis of code's quality. But there are plenty of indicators and BestPractices...

It's my summary judgement that "change" is too open-ended to make this a rigorous concept, a discussed below. There's an effectively infinite way any given module can "change". One has to first "tame" and classify "change" as a prerequisite to rigor-tizing C-and-C if it's tied to the term "change". --top


It would be difficult to escape the notion of probability here. There are often myriad potential changes and related cross-influenced, but each change path is rarely equal. In practice, we are often weighing probabilities of different kinds of changes, sort of a cost/benefit/probability analysis of each potential change. Most authors who talk about C&C seem to bypass the issue of probability, making questionable or untested assumptions in the process as a substitute. Related: ChangePattern. --top

Probability of change is a non-issue for CouplingAndCohesion, but is important for ChangePatterns. Consider: two units may be tightly coupled even if the probability of change (and consequential breakage) is very low. Because of this, you must distinguish between the coupling and the probability of change.

Almost everything is "coupled" at least by the fact that the names must match.

Uh... unless you mean to say "Almost everything that is 'coupled' via a shared name dependency is 'coupled' by the fact that the names must match" (which is trivially true) you are very much incorrect. For example, the code I'm (supposed to be) working on right now certainly isn't coupled to the code you're working on, and there is no need at all for names to match.

Thus, "coupling" is a matter of degree.

''While it is true that coupling is a matter of degree. I can make no sense at all of the main statement just above. Does any one have any idea what it might mean?' I am thinking that it might be equivalent to the claim that programs that have no dependency at all are not coupled-- have zero coupling, but I can not figure out how that leads to "coupling is a matter of degree" unless 0 is a degree, but then I am not sure what the point was. HELP wanted here I think others may also be confused. - ANNON

While your logic leading to it is baffling, I agree with this conclusion. That is why we discuss the desire for "low" external coupling and "high" internal cohesion.

And to calculate a "coupling" score, it would make sense to consider probability of change rather than just the existence of a potential breakage due to change.

Incorrect. It would not make sense to consider the probability of change. But it wouldn't be a bad idea to consider the probability of breakage given a change. Mathematically, that is P(BREAK|CHANGE) = P(BREAK AND CHANGE) / P(CHANGE). In layman terms, this (loosely) is the probability that code unit 'B' will 'break' after an unknown change to code unit 'A'. The closer this probability is to 100%, the higher the coupling from 'B' to 'A'.

We may find that things A and B have coupling points C,D,E; and things J and K have coupling points L,M,N. If we merely count the quantity of coupling points, then the coupling between A-B and J-K would be considered the same. However, in practice, changes to L,M,N may be much less likely than C,D,E. Thus, the utility of measuring coupling is greatly enhanced by considering probability of occurrence. Otherwise, we'd optimize our code for what could be very infrequent events over frequent ones. --top

We should optimize our code for ChangePatterns that have been anticipated based on past experience. But coupling is not the same thing as change patterns. Distinguishing between them is useful for providing or understanding advice such as: "Reduce coupling to details or features that are subject to frequent change." Indeed, the utility of 'measuring coupling' is enhanced by such distinction. If we don't distinguish between 'coupling' and 'frequency of change', then there is little purpose in having both phrases.

The distinction between practical couplings and theoretically couplings can make a huge practical difference. For example, a medical application may be coupled to the assumption that a typical human has two arms because it asks the doc to inspect both arms of patient. In theory if an alien race with 3+ arms immigrated to Earth, the application could break or become useless. But in practice you'd be labeled silly to dwell on such. However, there are plenty of "anal" or GoldPlating developers out there who take some advice too literally and may build a convoluted indirection layer to reduce the impact of more arms. To avoid getting tangled in our own underwear, we have to know where the draw the line, and change probability is a key tool for that.


These are some of the better-defined qualities that separate good software from bad software. Although they were formalized during the invention of StructuredProgramming, they apply exactly as well to ObjectOrientedProgramming as to any other kind.

Cohesion of a single module/component is the degree to which its responsibilities form a meaningful unit; higher cohesion is better. Coupling between modules/components is their degree of mutual interdependence; lower coupling is better. A first-order principle of software architecture is to increase cohesion and reduce coupling.

Cohesion (interdependency within module) strength/level names : (from worse to better, high cohesion is good) Coupling (interdependence between modules) level names: (from worse to better, high coupling is bad) As usual with software source code metrics, these qualities are difficult (but not necessarily impossible) to reduce to quantitative data that can be meaningfully compared across different projects or organizations, despite their value as qualitative measures.

These measures of quality arose in the context of structured procedural programming, but also apply to other paradigms, including OO; the best OO practices can be seen in these same principles. This should not be surprising; OO did not evolve in a vacuum.


Can coupling be summed up as as answering to three questions "yes" or "no"? Thus having 8 possible outcomes. Questions are "share meaning (are related)?", "share (similar) algorithm?" X "share data?" - Mila

No, coupling cannot be summed up as answering those three questions. Sharing data is, however, one form of coupling.


Quoted from "BoulderPatternsGroupMinutesOld?" (not otherwise a page to inspire browsing):

the correct terminology is "tight internal cohesion" and "loose external coupling". This basically means that each method in a class should have one task and the class as a whole should have one major responsibility (tight internal cohesion) and that other classes should not depend on the inner workings of this class but should be designed to the "interface" of the class (loose external coupling). See a recent post by AlanShalloway on this: http://groups.yahoo.com/group/dpexplained/message/108


[The following question in DecouplingObjects inspired the creation of this page.]

I am somewhat surprised to find little in-depth discussion of CouplingAndCohesion on the Wiki - that is, to be honest, nothing I can readily identify as in-depth discussion of the two measures per se as opposed to second-order principles of design that are asserted to be beneficial "because they reduce coupling" or "because they promote cohesion". I have an "intuitive" understanding of the notions, gained mainly by osmosis and reading texts which refer to them, but I have a feeling that my knowledge might be incomplete. Or are the concepts so straightforward that no such discussion is warranted? Or did I miss some obvious pointers? -- LaurentBossavit


Someone in TheStructureOfScientificRevolutions claimed that knowledge of these concepts has largely been forgotten in OOP. That is most unfortunate, if true.

As an experienced programmer facile with OO and structured methods, I think that concepts of cohesion and coupling absolutely have their place in OOP/OOD. There are many chunks of OO and/or XP wisdom that fundamentally boil down to those two concepts, appropriately framed.

A class is a coupled blob. The methods and properties must agree with each other on how the class is put together, or else there's little purpose in your class. That is, the internal interface of the class is what couples the implementation to it.

A wise OO practitioner wants that internal interface to be as small as reasonable. When a class gets large or complex, it's a center of coupling and begs to be refactored.

Cohesion represents unity of purpose. We have long ago learned that the most internally unified unit of work is to formally accept inputs and compute outputs. This is the practice espoused by FunctionalProgramming, which takes FunctionalCohesion? to the limits of reasonability - and beyond!

We also know that internal unity is not the same goal as global unity. We object-users (Classists?) want to express unity on as many levels as possible. Zillions of disorganized but simple functions do not express that unity. A well-designed OO program expresses the unity of purpose for groups of related methods by stuffing them in a class together. That cohesion is not about behavior in the atomic sense. It does apply to the boundaries of the interface which the class implements. Large classes or hierarchies can endanger that quality at their respective levels of abstraction.

Perhaps the great thing about OO technology is that it makes design problems so clear. Still we must learn to read the writing on the wall. When you have a solid grounding in phonics, you can learn to read English with far less trouble than without, and you can do so on your own from reading books. CouplingAndCohesion are like the phonics of CodeSmells. By analogy, perhaps books on OO Design focus on the shape of whole words without teaching the letters first. This yields learning if and only if the prerequisites are met.

-- IanKjos


In modular and functional programming coupling is the level of "dependency" between functions. And cohesion is a measure of how closely lines or groups of lines within a given function relate to each other: are they all "doing the same thing" or "contributing to a single goal?" One generally frowns upon global variables and parameters which are flags or codes.

In OO programming, I think we've created hierarchy of encapsulation, each level of which can be subjected to CouplingAndCohesion measures: I recall, as a modular programmer learning OO, that I was very impressed that practically every Smalltalk article I saw had discussions of how they improved methods in classes - in ways that improved cohesion within the resulting methods and reduced coupling between methods. Smalltalk culture clearly promoted appropriate CouplingAndCohesion, far more than even the most ardent modular programming texts, and the OO developers didn't even talk about it; it was just "the way things are done." -- JeffGrigg


I am finding in my current project that there is a tendency if one is not careful to swing the pendulum too much one way or the other. When they are too coupled, logic and functionality may be dispersed across several components. Both of these lead to a proto AntiPattern: how does PendulumOfCouplingAndCohesion? sound?

I think that the main issue is that what is "intuitive" to one person is not the same as what is to another. Also, it is difficult to correctly break up the functionalities of a system without error. This is why we RefactorMercilessly right? I sometimes find myself feeling dirty when I'm coding. To me this is a clear indication that this CodeSmells. I am not enamoured of using scents to describe code but my colleagues understood immediately what I was saying when I told them "I feel dirty."

Does this make sense or am I just rambling? -- IainLowe

What I find interesting is that I don't see coupling and cohesion as opposite quantities, such that decreasing the one automatically increases the other. What kind of coding tactics do you find yourself switching between as "the pendulum swings", as you put it?

I think I was a bit DazedAndConfused? when I spoke about cohesion up there. There is a relationship between the two, though: when modules are very de-coupled it stands to reason that they are cohesive. If they were not cohesive, they would require greater insight into the inner workings of the other modules in the system. So there is a pendulum effect but probably something more like HalfPendulumOfCouplingAndCohesion? since you are correct in stating that cohesion will reach a "sweet-spot" beyond which you cannot make a module more cohesive. I need to think about this a bit more... I still haven't pin-pointed the tactic-switching you mention above. -- IainLowe

It seems to me that the case is that a module which is cohesive is necessarily de-coupled. It cannot have unity of purpose if other classes accomplish half of that purpose. That is, while the module may be focused on one task it would not cover all of that task. However, being de-coupled does not imply cohesion. One module which manages three entirely distinct tasks can still be de-coupled from all others. -- James Ferguson

Look at it from a different perspective: Increasing coupling increases dependence (thus increasing future instability) and Increasing cohesion increases stability. The Holy Grail of CouplingAndCohesion is the BlackBox which offers The minimum dependence for the maximum stability for its user. -- WyattMatthews


I smell a false dichotomy. Maybe. Coupling is connection crossing a boundary. Cohesion is connection which doesn't cross a boundary. This suggests that the ideal system is a single global space, and the worst is a highly modular space. Then there's geometric complexity which is a measure of dependency range (How many elements are involved in any one transaction). It is all rather more complicated than a single 'rule of thumb'. I suspect we are applying aesthetic judgement as much as any analytical principle. -- RichardHenderson

My comment was not intended to imply a single global space as the ideal, but to imply individual spaces should have a minimum of dependence upon another individual space that it was not derived from. Patterns such as AbstractInteractions increase coupling at one level (the interactions are now required maintenance for the dependent class), but expose less dependence upon other spaces because they deliberately allow the substitution of the object previously required for its execution.

I know . The global thing is the implication of the definitions of coupling and cohesion with a rule to maximize one and minimize the other. I'm not trying to contradict the thesis of the page. I am a great believer in the basic principle. I just think that there is a whole load of expert intuition involved in applying this HeuristicRule, suggesting additional factors are involved.

Perhaps we can identify these forces more appropriately. For example, I would think that Coupling is necessary between parent and child classes, but only cohesion is necessary for siblings.

Any thoughts on my breakdown of these two forces?

-- WyattMatthews


It took me a long time to make sense of this word cohesion which I kept hearing. There seem to be many people who use this word without being able to tell me what it means, or show me code examples of cohesion. I have finally come to some level of understanding. First, if a class has a lot of different behaviour which doesn't naturally go together, it lacks a sense of cohesion. Similarly, if in order to alter some behaviour, one must go fiddle with many different classes, this might be a hint that the behaviour is spread out, rather than being in one cohesive unit. Second, if you look at a class, and everything you need to know about some behaviour is right there, and there isn't any thing else there to clutter up what that class does, then that class has a high sense of cohesion.

Not just cohesion means, but also coupling. At the top, it says: Coupling applies to any relationship between software components. Perhaps it should say: Coupling is the amount of relationship between software components.? (Improvements welcome.) -- ChrisDailey?

Oh. How about from http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?query=coupling&action=Search - "The degree to which components depend on one another." -- ChrisDailey?


Relationships are what makes software powerful. "Coupling" is not something to get rid of, but to manage. Encapsulation is a form of coupling, for example. If two things have NO relationship at the time of writing, then yes, perhaps they don't belong together nor connected (at the time).


Some references:

[Kudos for JeffGrigg for collecting a significant amount of relevant pointers.]

by Meilir Page-Jones Larry L. Constantine and Ed Yourdon. Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design. 1978.
Pre-OO. Essentially the origin of the those terms in software design, devoting a chapter to each.

[Yes, I did invent the concepts and the original metrics of coupling and cohesion, with first publication in 1968 ("Segmentation and Design Strategies for Modular Programming." In T. O. Barnett and L. L. Constantine,eds., Modular Programming: Proceedings of a National Symposium. Cambridge, Mass.: Information & Systems Press, 1968.) Glen Myers and Wayne Stevens were students and colleagues of mine at IBM's Systems Research Institute where I was on the faculty from 1968-1974. --Larry Constantine]

Links from Chris:

Most examples of CouplingAndCohesion seem to be device-driver-like examples. If one does not deal with device drivers, then those examples are not very good sales material. Some also depend on a pro-subtype viewpoint. Those of us who think ThereAreNoTypes would like to see something else. If the concept depends on subtyping-based ChangePerception?, that is fine by me. I just want to clarify if this is the case. -- top

Types in OO land aren't really all that much different from "domains" in relational-land. If you don't understand that, you need to go re-read ChrisDate.

Types maybe. But it is subtypes that are the issue.


A few of the places coupling and cohesion is discussed: NatureOfOrderDiscussion ExtractMethod CodeNormalization BenefitsOfOo SoftwareMetrics MaintainAbility GoodCode LargeExtremeProgramming RefactoringAndRewriting GradyBooch FundamentalFlawsInProceduralDesigns DontRefineExceptions CppUtxOverview (in regard to testing)


The basic idea is that stuff that works together, should be together.

It's all about how you cut up your program, into pieces called modules.

To think that you can win the game by putting everything into one module is just as silly as saying, "What, Global Variables are bad? Okay! I'll just put everything into one gigantic structure then, and pass it around. Yay me!" You have missed the point.

In ObjectOrientedProgramming, the main vehicle of Coupling is Polymorphism, and the main vehicle of Cohesion is Encapsulation.

Besides "stuff that works together" as a way to cut the pie might be "stuff that changes together" per the SingleResponsibilityPrinciple. Is that a useful way to find or measure cohesion? JLS


Because so much of programming now is basically drawing pipes between modules, it seems to me that StampCoupling has become more common and accepted. (...since, if you do StampCoupling, you don't have to draw in new pipes when you need something- it's just automatically available to you.)

If you do only DataCoupling?, then every time you need to get a new wire from module A to module D, then you need to massage A->B, B->C, and C->D. But if you're stamping it, you need far less massaging. You just pull what you need from the wire, no need to change a bunch of code.

Programs written in the "loose" languages, like Python and what not, seem to promote this sort of StampCoupling. Then, as things become formalized, efficient, rigid, and secure, a piece of software moves towards DataCoupling?, and is implemented in stricter languages.

Okay, so, I think the confusion rests in different understandings of the phrase "Stamp Coupling."

As such, it's probably best continued on that page: StampCoupling.


Re: "The basic idea is that stuff that works together, should be together."

This is often impossible. Factors often interweave such that there is no one perfect grouping. The real world is multi-dimensional but textual code is limited to 1 or 2 dimensions (2D on small scale). The best we can do is find the best compromise, and which is the best compromise is often a source of HolyWars (for example, grouping by nouns versus grouping by verbs). See GroupRelatedInformation.

True, but unhelpful. You're talking about problems that can arise even when some version of best practice is followed. CouplingAndCohesion primarily addresses problems that arise when best practice is not followed.

It's better for an attempt to have been made to group code based on it working together, than not to do so, even in cases where there is no single perfect answer to grouping.

Except maybe for newbies, almost everyone uses some kind of grouping approach beyond random.

Newer methodologies that attempt to address difficulties in grouping, such as GenericProgramming, AspectOrientedProgramming, and perhaps IntentionalProgramming, do not in any way contradict the principles of CouplingAndCohesion, so far as I am aware.

HolyWars over i.e. OO versus GenericProgramming, although the two methodologies can contradict each other, each individually are in alignment with CouplingAndCohesion.

[I agree with the person who said, "This is often impossible." However, just because some "theoretical purity" is unknowable or unattainable, doesn't mean that the theory's a bunch of bunk. The purpose of this idea isn't to give you a perfect algorithm to show you the one right way to do something. The purpose of the idea is to help you recognize patterns, and help you think about things. Breaking a problem down into smaller interconnected pieces is pretty universal.]

Because we have to as humans, not because it necessarily fits actual reality. Grouping stuff is an attempt to find the most UsefulLie. One often groups by their perceived probabilities of future changes, but it is often hard to agree on the most likely change patterns.

True, but it pays to keep trying to do better, and gradually over time computer science is learning more about what does and doesn't work well. CouplingAndCohesion is an example of something that was first invented a long time ago, back in the 1970s, but tends to be neglected, when it should be one of the tools in everyone's arsenal.

CouplingAndCohesion has been implemented as actual objective automated metrics quite a few times, but such things tend to suffer from problems of insufficiently powerful automated software analysis state of the art in general. Still, I expect this state of the art to continue to improve, and perhaps eventually the whole topic will become significantly less subjective.

Until then, one does the best one can.

I believe that SoftwareDevelopmentIsGambling. One evaluates the horses relative to each other and then picks the best guesses. There is not always one right answer for every circumstance. Saying "X is always bad" is always bad :-)

It's one thing to say that there isn't always one concrete correct answer, it's' another thing to claim that there isn't any objective means possible to measure the degree of correctness of answers in the abstract.

The latter would mean that software is of necessity doomed to forever be an art, not a branch of engineering and science. Some would agree, but this seems a risky proposition in an age where we are beginning to understand even the rules of aesthetics (via evolutionary psychology and via tentative systems like Alexander's).

It would also mean that these characteristics of software inherently cannot be correctly embedded in a mathematical metric space, even in principle, which seems exceedingly rash.

Back to brass tacks: name a situation where CouplingAndCohesion gives an incorrect answer to whether something is good or bad. (The issue of objectively measuring such was already addressed above your comments, not by your comments, so that's a different issue.) -- DougMerritt

Example? Indirection. Indirection reduces coupling, but can also complicate a given design. Having a complex design may make it harder to change because there is more code to read and more code to change. Also, how "bad" each form of coupling is, is subject to subjective rankings.


Analysis by reductio ad absurdum.

Coupling

It is my understanding that coupling can only be reduced, not eliminated. A program with zero coupling could have at most one machine instruction (not source statement). Any more than that and there would be dependencies between the action of one instruction and the action of the next.

So, by inference, coupling is indicated by the degree of dependency between the various components of a system. Of course, by their very nature, modules depend on one another to perform their respective functions properly, but we are concerned with how much one module depends on the implementation of another module. The ideal is not at all, and we can come very close, but never arrive.

Cohesion

By the same argument used above to show that coupling cannot be eliminated, a certain level of cohesion is also inherent in the sequential nature of electronic computer instructions. (All bets are off on quantum computing.) The goal is to maximize it.

I won't bother pontificating on this because an item above covered it very well:

Coupling is connection crossing a boundary. Cohesion is connection which doesn't cross a boundary.

The only addition I would make is to emphasize that the connection need not be explicit, it can be implicit. It could be knowledge as innocent as knowing that certain values passed are 'bit flags'.

Well I'm out of time. So long.

-- BobBockholt


Some examples would be nice. English is insufficient it seems. For example, "contributing toward the same goal" can get into some sticky philosophical discussions. It just seems another case where people end up modeling their own internal view of the world and thus nobody agrees. FuzzFlag??

This stuff was invented in 1974, but it's been partially forgotten, and seems to be taught at only, I dunno, 20% of colleges and universities these days, even though it is not obsolete; it's still quite important.

I took the trouble to add definitions for every single level of coupling and cohesion recently, which had never been on this page before, and I did this by doing a bunch of web searching and trying to pick out the pages that seemed to have more coherent definitions. Then I dug up the actual origin of the terms, since that was misquoted here.

I understand why you would say that the result is still insufficient, but you know what, I'm kind of tired...how about if now you do some similar searching and find some nice examples and add them to this page? Google is your friend, too, not just mine. :-)

I did not mean to have you carry the entire load.


I think there are (at least) two things to look at when investigating "links" between things:

-- top


How ResponsibilityDrivenDesign could help with CohesionAndCoupling ?

UseCases protect and give answers to the concerns and interests of all stakeholders of a given system.

All stakeholders of a given system are represented through the Actors in the interactions with a such system.

For every goal that a given Actor has with a given system, this system must answer every such goal through its responsibilities.

This system should become a catalyst for such business, because its purpose is to open new roads to facilitate this business. This catalyst metaphor fits perfectly with TheSimplestThingThatCouldPossiblyWork.

To design such a system, we must understand the business this system must service, with this catalyst idea in mind.

To start with, we look at the business terms or entities that are involved in the business. We are looking into the problem domain of the business. In this domain, all business entities involved are classes.

Only a group of all of the problem domain classes will show up in our system. That will depend on the scope of our system.

Besides, for the group of problem domain classes that will show up in our system, some of the business entities will turn into system classes, while others will become just properties of these classes. Whether a problem domain class becomes a system class or a property of another system class will also depend on the scope of our system.

For instance, let's take a look at the ZipCode? business entity (problem domain class). If we are designing a typical SalesOrderProcessing? system, in most cases the ZipCode? will become a property of some system class(es).

But what if we are designing a system for FedEx or UPS?. In such a case, the problem domain ZipCode? class might become a system class.

(YAGNI and NIAGNI help us define partial, temporal projections into the scope of a given system. We may start with a very narrow scope in the first iteration, like a WalkingSkeleton of a system, and gradually evolve into a wider scope, all the way down to the final scope of such a system).

So, for every problem domain class we must fully understand what it has to know and what it has to do in order for it to answer to all its responsibilities (the word responsibility comes from Latin and it means "to give answer to").

How do we do that? Simply by asking for the BusinessRules involved in the problem domain.

This is the real initial point in our problem domain exploration: BusinessRules will help us identify all business entities (problem domain classes), and also everything that a given class must know and must do.

BusinessRules are atomic and elementary always, if we state them in the proper way.

BusinessRules will also tell us how classes interact (collaborate) among themselves.

Through these collaborations among classes to fulfill business goals (UseCase goals), we could discover how to aggregate knowledge and behavior of every problem domain class to identify its responsibilities.

In such a manner, we can get highly cohesive problem domain classes. Cohesion is the middle ground between atomic BusinessRules and lumpier UseCase goals.

If we build a cross-collaboration matrix among all problem domain classes, we will find lumps or clusters of classes with stronger collaboration ties.

These clusters tell us what classes belong to a given logical (problem domain) package or component.

If we apply this very same grouping to our software components, we could have loosely coupled components.

Problem Domain Analysis helps us determine the classes involved in it, as well as the public interface of theses classes.

Since we are dealing with the what of a business and not the how of that business, this analysis helps us design for the public interface of classes, an not for any particular implementation ("Responsibilities = Public Interface").

This is consistent with the first principle of object-oriented design stated in the DesignPatternsBook (page 18):

"Program to an interface, not an implementation".

-- GastonNusimovich


"Fuzzy Metric" Complaint

In a usenet debate, RobertMartin suggested that separate case-statement lists are "coupled" because they are allegedly likely to change together.

   functionA(...) {
     ...
     select on x
     case 'aa': {asd()}
     case 'bb': {jgusss(...)}
     case 'cc': {j7()}
     otherwise...
   }
   functionB(...) {
     ...
     select on x
     case 'aa': {balasdf()}
     case 'bb': {nib()}
     case 'cc': {zork(...)}
     otherwise...
   }
Robert implies there is some kind of what comes across as existential coupling between these two lists because they may be affected by some changes, such as adding a new item to each list. It is not a "hard" coupling, because there are no existing references between the two lists (other than "x", which does not change in the scenarios usually used).

But the case lists might also drift apart. We may add a "dd" to one, but don't want it for the other, for example. There is no guarantee they will change in lock-step. Even if you feel they are likely to change together, the "coupling" still depends on probability. There are change probabilities that require polymorphic classes to change in lock-step also, the classic being adding a new method to every shape sub-class. (See SwitchStatementsSmell for discussion on change impact and case statements.)

Thus, "coupling" is drifting from what may have been a clear-cut metric to something that depends on probability estimates and personal judgment. It is not the "magic metric" that some paint it as.

An example of objective coupling is a method in a class:

  class foo {
    method bar{....}  // location A
    ...
  }
  .....
  x = new foo(...);
  x.bar(...)  // location B

Here, the method call in location B is "coupled" to location A because if we remove method "bar" at location A, then the method call at location B is no longer valid. (Changing parameter signatures can be a similar issue.) This kind of thing is where such a metric is useful. However, the link between two CASE lists that may or may not change in lock-stop is subjective, or at least dependent on PerceptionOfChange and SoftwareDevelopmentIsGambling.

The "bar" example does not assume any external knowledge or experience. One can look at the code and only the code. In fact, an algorithm could probably be written to draw lines between coupled portions of code. The two CASE list issue could not be done this way unless we make up-front assumptions about the likelyhood of change, but people (like me) can question such assumption, wanting more evidence beyond someone else's anecdotes.

-- top

That's true, but there is no truly magic metric, and IMHO, CouplingAndCohesion does better in that department that most suggested measures.

Similarly with the rest of your comments: perhaps true in the absolute, but replacing switch statements with class-based method dispatch typically produces real, tangible benefits.

The most common exception is probably your fond example of tables where neither rows nor columns have natural precedence over each other, so that neither is appropriate as the relative root. In pure OO realms people work around this with DoubleDispatch, which is often good enough if not perfect, and in impure realms, multi-methods/generic functions which choose a method based on multiple parameter types/classes simultaneously solves this very nicely.

On the other hand, I won't dispute that it can also be solved nicely without OO and without multimethods, using good old-fashioned data-driven programming, which pre-dates OO but has philosophical similarities with it. In this case, one might have e.g. a 2-D table indexed by appropriate manifest constants, retrieving the appropriate function pointer to use. This amounts to implementing multi-methods by hand.

       city.....pop_m..avg_humid...function or expr.
       ---------------------------------------------
       ST. LUIS...4.2.......50.....foo()
       SALK LAKE..3.1.......42.....bar()
       MAUI.......2.6.......65.....zaz() + foo()
       //Etc. (Simplified for illustration purposes. Joins may be used in practice to get average, etc.)
Even the latter is typically superior to just using switch statements, though. An example that I've frequently run across in my own work is in interpreters and compilers full of switch statements on the types of objects being manipulated. Some of them do a type-specific print of a value, some do type-specific code generation, etc, and in practice, not theory, these switch statements suck and suffer bit rot and get out of sync with changes, etc, and replacing them with any of the above approaches - including table-oriented methods - has always resulted in sharply better, more maintainable, more readable code.

I don't agree with everything RobertMartin says, but in this case, I believe he is right on target. Most of the time, switch statements have worse CouplingAndCohesion than OO/generic/data-driven approaches, and one aspect of this is not fuzzy: the switch statements are scattered all over the code, whereas the other approaches centralize things in such a way that lack of synchronized changes becomes less likely, and in fact the language can to some extent actually assist. -- DougMerritt

The issue at hand is whether similar case statements are "coupling", not whether they are "good". The goodness issue is taken up in SwitchStatementsSmell. Note that Polymorphism scatters the "method list" all over the place in a similar fashion. It is not a free lunch. It generally seems to boil down to a probability estimate, and OO fans see different change probability distributions than I do (PerceptionOfChange). It may be a domain-specific thing, or a personality thing. I have asked for an example of a biz domain case list that changes in lock-stop as claimed and have yet to receive one (other than something that should be a table instead). Thus, I have good reason to remain skeptical. I also find IF statements easier to adjust the GranularityOfVariation on than polymorphism. For example, it's not uncommon in the biz domain for the change request to ask for both features instead of an either/or choice. It's usually less re-coding to change a CASE block into an IF block than it is to de-mutually-exclusivize polymorphism.

Doug, would you agree that a switch statement in a class may be acceptable if all other dispatch systems were ruled out for some reason provided they did not exit that class?


Sticky problems in CouplingAndCohesion: CouplingAndCohesion, much like layers of abstraction, tends to be excellent for making the programming easier... and awful for optimizations. Many of the most powerful optimizations are those that cross boundaries that very clearly constitute 'unnecessary coupling' and might even be called 'utterly evil coupling'. Furthermore, many of these optimizations cannot be performed by modern optimizers (or even next-generation optimizers...). And these include real, algorithmic optimizations... not just coefficient cost reduction (though you get that, too).

I suggest that future research should consider the possibility of aspected-oriented coupling for optimization purposes. Until we have something that can cross boundaries for us, we'll be doing it by hand, BestPractices be damned.


Example of subjectivity in metrics:

 routineA(...) {
    x = routineB(a, b);
 }

routineB(x, y) { [...] }

Is routineA coupled to routineB and visa versa?

Note that if we change routineB to this:

 routineB(x, y, z) {  // add a new parameter
    [...]
 }

in many languages this would "break A" because A calls B with insufficient parameters now. In languages where different parameter counts are allowed such that "z" would return blank or Null, the affects are harder to determine. We'd have to dig around in the algorithm details.

What counts and what doesn't as "coupling", and if all instances are weighed equally is usually a subjective thing. Some situations are even non-deterministic, or at least very expensive to discern because all possible calculation paths can fan out approaching infinity.

It is possible to make it clean by ignoring certain relationships, but this gets back to objective metrics versus useful objective metrics (SovietShoeFactoryPrinciple). If we don't count stuff just because some of the metric calculations are too expensive, we may make a nearly useless metric, or at least diminish its practical utility.

--top

You could also break routineA by deleting routineB, or by making routineB return semantic garbage, or by making routineB return some type-unsafe value for routineA, et cetera. You'll just confuse yourself if you get hung up on petty details like whether the new 'z' parameter can possess a default. It is quite clear that there is a very 'hard' (measurable, provable, graphable) dependency from routineA to routineB, but it is not at all clear what your claim of 'subjectivity' happens to be in this example (are you making this another vector for your ObjectivityIsAnIllusion mantra?). As to the 'vice versa'? Dependencies aren't necessarily bi-directional. And coupling is about mutual interdependence - i.e. you need to demonstrate the 'vice versa' before you can show there is any coupling at all. Doing so would be impossible with the little information you've provided above.

Focusing on the motivation for your spiel:

There may be some sort of 'soft' coupling if routineB is being continuously modified to meet the needs of routineA, in much the same way that helper-routines are coupled to the procedures that need the help. This coupling wouldn't necessarily show up in a dependency graph of function calls; rather, it would show up in the commit history for the project. This is something you might call 'existential' coupling. It would be unreasonable to claim it doesn't exist (people can obviously point at examples of it, therefore it must exist). But one might question its ultimate relevance. Hard coupling causes hard problems like DllHell. This 'soft' or existential coupling does not. Thus, whether 'high existential coupling' is even a problem should be evaluated independently. I do not believe it would be a problem. Heck, you might as well claim that all domain-based classes and routines in a project are 'existentially coupled' in the form of RobertMartin's example - after all, they are all part of the same project, thus if the requirements of the project change they tend to change also. But it doesn't cause problems (or provide benefits), and therefore it isn't relevant. And, completely independent of whether they are easy or difficult to measure, irrelevant things simply don't need to be measured.

Is our goal to solve and prevent problems, or merely measure something? If the first, then why would "soft" and "existential" coupling be omitted? You seem to half-agree that soft/ext. coupling can cause problems. (Only insofar as need for change ever causes problems.) And Martin makes an issue of it. The opening definition seems to include soft coupling. Perhaps we just need a better classification system for "coupling" (or at least "dependency"). Here's a rough draft:

           foo(1, 2, 3);
           ....
           function foo(a, b, c) {.....}
           // We can see that the def of foo requires 3 parameters
           // (Assuming the target language does not auto-nil missing ones).

          function X() {
            fileName = "myfile.txt";
            a = foo(fileName, currentDateTime());
            if (a.length > 0) {
               fileName = alternativeName(a);
            }
            contents = readFileContents(fileName, settings);
            // Function X is coupled to existence of "myfile.txt" if "a" not blank.
            // (let's assume readFileContents() requires file existence.)
          }

Didactic examples would be welcome, top.

Added. See above examples. --top


External Links:

http://www.computing.dcu.ie/~renaat/ca421/LCOM.html


See also: DecisionMathAndYagni DecouplingOfObjectOrientedSystems
CategoryInfoPackaging, CategoryModelingLawsAndPrinciples

EditText of this page (last edited November 23, 2013) or FindPage with title or text search