Hello Folks, I have a couple of concerns on "Coupling and Cohesion" that I would like help to figure out and understand. Software that has LOW coupling and HIGH cohesion is easier to maintain. We all understand and agree on that. But HOW MUCH coupling would be considered a low coupling that is ideal and desirable? and so is the cohesion? So i am looking for a way that would aid us to measure how much is low and how much is high.I would appreicate if you could give me your thoughts and experience on it. also I would appreciate if you could links to literature or books on this topic. thanks. [ November 26, 2004: Message edited by: Carn Melon ]
Great topic! I'll give my intuitive 2 cents worth, hope others chime in perhaps with more book learnin.
We often turn these concepts a bit and talk about dependency for coupling and responsibility for cohesion.
Robert Martin has written extensively on dependencies, making the concrete and volitile parts of your code depend on the abstract and stable parts and not the other way around. His guidelines help understand where coupling is necessary and where it can be avoided by abstractions.
Cohesion is nicely expressed in the single responsibility principle. If you find a class doing two things ask yourself if those two things belong together and if they wouldn't be better separated. Frinstance, students given an assignment to read some numbers, do some calculation and present the results will often write a single class (or a single method) to do the job. But there were three pretty clear parts to the job just in a one-sentence description. One giant class is not very cohesive; three with narrower responsibilities probably would be.
So how much coupling and cohesion is good or bad, like everything else, depends on the situation. Martin has some interesting metrics to measure dependencies between packages, but otherwise it's hard to say something definitive like "Ooo, your cohesion dropped below .8 there!".
Any time you see coupling - class A depends on class B - ask what could go wrong here? What if B changes? Can I afford to fix A, too, or should I introduce some abstractions to decouple them?
Any time you see a class doing two things ask what could go wrong? Should I change this class just because part A or part B changes, or should I separate those parts so I can change them independently? Another good hint to examine cohesion is duplicate code. If I have file reading in three classes, should I pull it out to its own class?
Oh, links. Google for "Robert Martin package dependency" - you'll probably find a bunch of articles. The JDepends tool does his package metrics and has some good doc with it. And Martin's book "Agile Software Development" covers it all if you have a few bucks to invest.
Try "Single responsibility" in Google, too. That ought to hit some good stuff.
Here's sometehing I did, just for grins: The DIP [ November 27, 2004: Message edited by: Stan James ]
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
One issue that has never been address for me is , what kind of coupling is best. Should objects be connected by use of other classes or by primative types. I have always thought that using connecting object was a good thing, I think the oop term for these object is Value Objects they are stateless and is uses as pass-by-value. Object that use primate types for method parameters have a much better chance of reuse, no? It is a bad thing when you want to reuse one class only to find its connected to another so you have to bring that one with you also.
Classes are the grouping of irresponsibilities, that might or might not belong together and it takes a smart cookie work that out. I only have an IQ of 82% I know I cannot do it best.
I believe most classes are too big, and just to use one of their methods you have to use all the object; it is synonymous voting for a senator at an election because you believe in one or two of his values. How many Americans voted for Gorge W Bushes because his of good Christian, and family values but didn't like his attitude towards the environment and not protecting gods precious planet.
Wouldn't it be nice if you could voted for only values at an election, instead of seniors. The same, wouldn't it be nice if you could choose the methods to use in you application without bringing along classes with methods you don't need. There was a time then I wanted to use the one method from the JavaString class so I was forced to use the whole class and bring along the 30 odd methods that belong to it. A Java application can become bloated in next to notime, just like the language itself.
I will never forget the time I purchased Sonic the Hedgehog for the PC. It ran slowly on my 486 and it used so much memory and hard-drive space, and I remembered it needed to load between each level. Then I found a genesis emulate kgen or something. I didn't have the internet at home so I downloaded the emulate and 5 games (I was pissed of that I didn't have space for 6) onto a floppy and when I played sonic though the emulator it very good no loading or jerkyness and it had turbo mode to boot. It goes to show how good programming without object can do without object getting in the way.
Originally posted by Carn Melon: Hello Folks, I have a couple of concerns on "Coupling and Cohesion" that I would like help to figure out and understand. Software that has LOW coupling and HIGH cohesion is easier to maintain. We all understand and agree on that. But HOW MUCH coupling would be considered a low coupling that is ideal and desirable? and so is the cohesion? So i am looking for a way that would aid us to measure how much is low and how much is high.I would appreicate if you could give me your thoughts and experience on it. also I would appreciate if you could links to literature or books on this topic. thanks.
[ November 26, 2004: Message edited by: Carn Melon ]
Great thinking guys I have always thought coupling and cohesion were tricky issues because there is no definitive measurement available for them. But one thing comes to my mind: excessive decoupling can happen, and it hurts. I have seen design where the stacking of abstraction layers was simply beyond reason. Imagine a system where there are more lines of code for method calls than for actual information processing. Another symptom of over-decoupling is the number of interfaces and abstract classes (i.e. types) being much higher than the number of concrete classes (i.e. implementations). This leads to confusion instead of increased maintainability. In other words, one might say that there is a level of decoupling beneficial for every application, but that going beyond this level should be expressed by specific technical requirements. Example of these requirements are the ability of switching component implementations in run-time or according to dynamic rules. This kind of requirement has a significant implementation cost, and should not be implemented just for the sake of decoupling. Keep it simple.
Bruno Collet<br /><a href="http://www.practicalsoftwarearchitect.com" target="_blank" rel="nofollow">www.practicalsoftwarearchitect.com</a><br />- The Paradox of Software Architecture: It is easy to make a complex architecture, but it is difficult to make a simple architecture.
Joined: Oct 26, 2002
Thanks Stan, Gerald, Udaya and Bruno for providing great input on this topic.Like Bruno indictaed, this's always been a tricky issue at least for me. Reading a arctile Single Responsibility pointed by Stan about "Single Responsibility" which relates "Cohesion", a couple of concerns occured to me. Talking about "Cohesion" thereby "Single Responsibility", the articles says
THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.
What I don't quite understand here is "ONE REASON" for a class to change. What does it mean a ONE REASON as there could be several reason for a class to change. It says in page 3,
If you can think of more than one motive for changing a class, then that class has more than on resposibility.
Also,If you go to the 2nd page of the article, the class "RECTANGLE" is not cohesive (class level cohesion here) as indicated by the article, it does performance two responsibility. How does as indicated in the article, a change in Rectangle class caused by a Graphical Application cause a change in Computational Geometry Application as long as the interfaces(methods) name remains the same regardless of changes in underlying implementation? As a solution to that problem, a seperate class is created and assigned a responsibility. is too many classes not a problem?
Again, why the modem.java class is a problem. The article says
They'll certainly change for different reasons.
SO WHAT? What's the problem here? How does the suggested solution solves the problem? Guys, I found myself very ignorant on this topic after reading this article. could you please help me understand this concept? thanks. [ November 27, 2004: Message edited by: Carn Melon ]
Joined: May 15, 2002
Classes are a grouping of code together that is suppose to achieve one aim, so much etherises on is put on these groupings. How a method can be grouped can depend on the context it is used. They can be group for better reusability, business modal, behaviour or many other things. Getting these groupings wrong is ok so long as you came move these methods and make the corrections; developers need to design flexibility into there code.
But one thing comes to my mind: excessive decoupling can happen, and it hurts. I have seen design where the stacking of abstraction layers was simply beyond reason.
I've seen this too, and I agree it's a bad thing. I don't think those extra layers of abstraction necessarily reduce the coupling, though; often there's just as much coupling, but it's now exacerbated by extending through several layers rather than just one function call.
Imagine a system where there are more lines of code for method calls than for actual information processing.
Function calls aren't actual information processing? I'd agree that simple forwarding functions are not, but other kinds of functions often are.
My friend cited someone "you can always add another layer of indirection". I think this is to decide to programmer on each concrete case basis. Since I am XP worshipper (except for pair programming part, which I never tried), I add layers "as needed".
Joined: Jan 29, 2003
"As needed" is key and really hard to predict. There were some good posts recently on an article about creational patterns and decoupling from knowing what class you're creating. Event the experts were unsure how often you'll really need an abstraction, say a factory method.
XP has a couple ideas that go together well - "do the simplest thing that can possibly work (right now)" and "you ain't gonna need it". These are not quite as simple as they might appear, but they tell you not to over engineer before the need is proven. A rule like "always use factories" would be hard to justify. But it takes some experience and judgement to feel when some level of abstraction would be a good idea, and to make it easy to insert it if you need it later.
Back to "single motivation for change" ... maybe a real life example would help. I have an app that serves several user groups. One core class changes if we add new rules for processing referrals from one user to another. In a prior version of the app it also changed if we added a new user group. These two change vectors are not (necessarily) related so that seemed bad. I replaced several if-else tests for user groups with a set of strategy classes that capture the difference between user groups. The core class now gets the appropriate strategy for the user group from a map and executes it. I can add new user groups without touching the core code. This added complexity for sure - a new abstraction (interface) for group strategies, a new map, configuration at startup, etc. But it protects my core code from being opened, modified, tested, deployed etc for every new user group and we believe that will pay off in future releases. It also removed a type of complexity - many many if tests for user group - and it put all the unique code for each user group in a concise strategy class.