Cohesion vs Coupling
- Summary
-
Discussion
- Could you explain cohesion and coupling with an example?
- How should I balance cohesion and coupling when designing software systems?
- Why should I care about cohesion and coupling when my code works?
- How are cohesion and coupling relevant to microservices?
- Which are the different types of software cohesion?
- Which are the different types of software coupling?
- Are there quantitative measures to evaluate software cohesion and coupling?
- Milestones
- Sample Code
- References
- Further Reading
- Article Stats
- Cite As
When a large software is decomposed into smaller modules, it's inevitable that these modules will interact with one another. If the boundaries of these modules have been poorly identified, then the modules will heavily depend and frequently interact with one another. In a poor design, it might also happen that classes and methods within a module perform diverse tasks and therefore don't seem to belong together.
Cohesion is about how well elements within a module belong together and serve a common purpose. Coupling is about how much one module depends or interacts with other modules. Thus, cohesion is an intra-module concern whereas coupling cuts across modules.
To manage the complexity of an application, a software designer must find the right balance of cohesion and coupling. This is relevant to object-oriented design, the design of APIs and microservices.
Discussion
-
Could you explain cohesion and coupling with an example? Consider a software project with folders containing associated files. In one approach, folders
Entities
,Factories
,Repositories
andServices
are created. This seems like a good organization but from a functional perspective there's tight coupling across folders. The boundaries don't reflect the semantics. For example, product management would involveProduct
entity,ProductFactory
,ProductRepository
andProductService
across all folders. Moreover, folders have logical cohesion but poor functional cohesion. For example, each factory deals with a different entity type and have little in common functionally.A better way to organize would be to have folders
Orders
,Products
andUsers
. This organization is based on purpose and functionality. This is better because any change to product management would impact only files co-located in a single folder. Code is more readable and maintainable. Teams would be more independent, each working on its own folder. Each folder could also be versioned and released independently of others.In short, low cohesion means the module is trying to do too many things. High coupling means modules are tightly interconnected via many complex interfaces and information flows.
-
How should I balance cohesion and coupling when designing software systems? Ideally, we should aim for high cohesion and low coupling. Related parts of code should be in the same module. Each module should be independent of others. Modules should interact in a minimal way. In modular programming, we use the term 'module' in a general sense. In practice, a module could be any of these, at different levels of abstraction: folder, JavaScript file, C++ class, C# assembly, Java package, Python module, REST endpoint, microservice, etc.
Apply the Single Responsibility Principle (SRP) for high cohesion. Use well-defined interfaces and inversion of control for low coupling.
An anti-pattern is when a piece of code does all the work. This is a monolith that some call a God Object or a Big Ball of Mud. There's also code that exhibits low cohesion and high coupling, when module boundaries are poorly defined. A developer might try to solve this via decoupling. But decoupling without cohesion will make the code even more difficult to follow. Using interfaces that don't represent an abstraction is an indication of destructive decoupling.
-
Why should I care about cohesion and coupling when my code works? In any complex software, code is written once and maintained regularly. Those who maintain it are not necessarily those who originally wrote it. Therefore, the goal is to write code that's easy to maintain and evolve.
Cohesion makes it easier to understand code. If each module's purpose is clear, we can think at higher levels of abstraction without getting into detailed implementation of modules. For deployment, fewer modules are impacted.
Low coupling means fewer interconnections across modules. It means one module can be changed or even replaced without impacting other modules. It means modules are isolated from the implementation details of others. Low coupling aids simulation and testing.
-
How are cohesion and coupling relevant to microservices? If improperly architected, an application based on microservices might end up being a distributed monolith. In such an application, microservices are chatty, calling one another often. Changes to one microservice requires changes to others. Same developers work on the codebases of many microservices. Microservices share the same database or even code.
To solve these problems, one approach is to adopt domain-driven design. Restrict access using scoping rules. Use public APIs to encourage loose coupling. REST APIs shouldn't be tightly coupled to specific applications or services. Effectively, the idea is to get the boundaries right towards high cohesion and low coupling.
If a microservice relies on the physical address of another service, then there's tight location coupling. Service discovery tools can solve this. If a microservice needs to wait for another's response, there's temporal coupling. A message bus or event stream can solve this.
For testing, unit tests created for a microservice shouldn't impact integration or end-to-end tests. To verify interfaces across services, gRPC and Avro can help. Test coupling can be minimized by mocking APIs and dependent services.
-
Which are the different types of software cohesion? Parts of a module that collectively perform a single well-defined function is the strongest type of cohesion. There are however many other types of cohesion, some more desirable than others:
- Coincidental cohesion: Parts are not related and just happen to be in the same module. Such a module is hard to understand, maintain or reuse.
- Logical cohesion: Parts relate to different entities though they perform similar logical functions. For example, mouse inputs and keyboard inputs are handled in the same class.
- Temporal cohesion: Parts that are executed when something happens, such as start-up or clean-up routines. Code changes may affect many modules.
- Procedural cohesion: Code that's called one after another.
- Sequential cohesion: Similar to procedural cohesion with the additional constraint that the execution sequence is important. For example, call
readFile()
before callingprocessData()
. - Communicational cohesion: Also called information cohesion. Parts that share or operate on the same data.
- Functional cohesion: The most desirable type of cohesion. Parts work together in fulfilling a single function or purpose.
-
Which are the different types of software coupling? Data and control are two types of information flow across modules. If only some data is exchanged, the amount of coupling is probably acceptable. Exchanging lots of data and control results in a high degree of coupling.
Here are a few types of coupling:
- Content coupling: One module modifies local variables of another module or branches execution into another module. Violates the principle of information hiding.
- Control coupling: Using control flags, one module controls the execution path in another module. Makes code hard to understand.
- Common coupling: Modules access global variables. Modules are bound together via shared data structures. Leads to unexpected side effects and error propagation.
- Stamp coupling: A module passes an entire data structure to another when only some data members are needed.
- External coupling: When interfacing with external tools, devices or libraries, module is coupled to the external device interface, communication protocol or data format.
- Data coupling: Use of parameter lists to pass data from one module to another.
-
Are there quantitative measures to evaluate software cohesion and coupling? Relation Cohesion (H) measures average number of internal relationships per type. Given N types and R internal relationships,
H=(R+1)/N
. A suitable range is 1.5-4.0. Higher values may indicate over-coupling internally. Another measure of cohesion is Lack of Cohesion Of Methods (LCOM). LCOM has range 0-1. Zero is ideal. It's variant LCOM Henderson-Sellers (LCOM HS) has range 0-2. An LCOM HS value exceeding one is bad.Afferent coupling (Ca) measures the number of types in other modules that depend on elements of this module. A high value implies a module with many responsibilities. Efferent coupling (Ce) measures the number of types from outside the module used in this module. A high value implies a module highly dependent on others. These metrics could be applied to types, fields, methods, namespaces, etc. The ratio
Ce/(Ce+Ca)
is called Instability, which measures a module's resilience to change. A value of 0 is ideal.Class inheritance in OOP is a form of tight coupling. Some relevant metrics include weighted methods per class, depth of inheritance tree, number of children and count of base classes.
Milestones
1974
Stevens et al. propose a method to reduce complexity. They call it Structured Design or Composite Design. A system can be divided and simplified into smaller pieces. This improves and speeds up the writing, debugging and modifying of code. This is because each part can be considered separately. However, identifying suitable "modules" of code is not trivial. They therefore introduce the concepts of cohesion and coupling.
1994
Chidamber and Kemerer propose six design metrics to evaluate object-oriented design. They evaluate and interpret them on two real-world projects that use C++ and Smalltalk. The degree of similarity among methods is a measure of class cohesion. Class complexity can be measured by the number of methods and instance variables it contains, depth of inheritance and number of immediate descendants. Methods are a of measure communication complexity among classes.
Craig Larman in his book Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process (2nd edition) calls cohesion and coupling "the yin and yang of software engineering." Bad cohesion usually results in bad coupling, and vice versa. He also notes that,
The level of coupling alone can't be considered in isolation from other principles such as expert and high cohesion.
Eric Evans publishes a book titled Domain-Driven Design: Tackling Complexity in the Heart of Software. He notes that as humans and designers, it's hard for us to think or reason about many concepts at a time (high coupling). We also find it hard to understand logically unrelated ideas (low cohesion). It therefore makes sense to recognize these limitations as we design software systems.
2014
Software architect/designer Kirwan explains why the mantra of "loose coupling and high cohesion" may not work in practice. He points out flaws in the paper by Stevens et al. (1994). For example, maximizing cohesion is neither a clear concept nor desirable. Too many dependencies within a module gives no structural benefit. When change happens, its effect within the module could be as bad as across modules in a tightly coupled system. Thus, it's only a matter of perspective: are we looking at classes in a package or across packages?
Sample Code
References
- Bryant, Daniel. 2018. "Microservice Testing: Coupling and Cohesion (All the Way Down)." Medium, March 12. Accessed 2020-03-27.
- Carlson, Adam. 1996. "Coupling and Cohesion." CSE403, Computer Science and Engineering, Univ. of Washington, Spring. Accessed 2020-03-27.
- Chidamber, Shyam R., and Chris F. Kemerer. 1994. "A Metrics Suite for Object Oriented Design." IEEE Trans. on Software Engineering, vol. 20, no. 6, pp. 476-493, June. Accessed 2020-03-27.
- Chowdhury, Istehad. 2009. "Using Complexity, Coupling, and Cohesion Metrics as Early Indicators of Vulnerabilities." MSc. Thesis, Department of Electrical and Computer Engineering, Queen’s University Kingston, Ontario, Canada, September. Accessed 2020-03-27.
- Costa, Bruno. 2017. "Microservices, bounded context, cohesion. What do they have in common?" Hackernoon, April 6. Accessed 2020-03-27.
- Etheredge, Justin. 2018. "You’re Not Actually Building Microservices." Simple Thread, February 26. Accessed 2020-03-27.
- Evans, Eric. 2003. "Domain-Driven Design: Tackling Complexity in the Heart of Software." Final Manuscript, April 15. Published by Addison-Wesley Professional, August. Accessed 2020-02-06.
- Gilmore, Jason. 2019. "What is Loose Coupling in REST APIs?" Blog, DreamFactory, December 19. Accessed 2020-03-27.
- Higginbotham, James. 2016. "Applying Domain Driven Design to APIs and Microservices." LaunchAny, on SlideShare, May 25. Accessed 2020-03-27.
- JavaTpoint. 2020. "Coupling and Cohesion." JavaTpoint. Accessed 2020-03-27.
- Khorikov, Vladimir. 2015. "Cohesion and Coupling: the difference." Enterprise Craftsmanship, September 2. Accessed 2020-03-27.
- Kirwan, Edmund. 2014. "Coupling and Cohesion: Failed Concepts." DZone, January 14. Accessed 2020-03-27.
- Larman, Craig. 2001. "Applying UML and Patterns: Introduction to Object-Oriented Analysis and Design and the Unified Process." Second Edition, Prentice Hall. Accessed 2020-03-27.
- Lust, Jurgen. 2017. "Loose coupling: why you want to avoid REST communication between microservices." BeeWorks, September 20. Accessed 2020-03-27.
- Ma, Xiao. 2018. "Microservice Architecture at Medium." Medium Engineering, October 18. Accessed 2020-03-27.
- Microsoft Azure Docs. 2018. "Design for evolution." Application Architecture Guide, Azure, Microsoft Docs, August 30. Accessed 2020-03-27.
- NDepend Docs. 2020. "Code Metrics Definitions." NDepend. Accessed 2020-03-27.
- Stevens, W. P., G. J. Myers, and L. L. Constantine. 1974. "Structured Design." IBM Systems Journal, vol. 13, no. 2, pp. 115-139, June. doi: 10.1147/sj.132.0115. Accessed 2020-03-27.
- Stolarczyk, Tomek. 2019a. "A brief history of coupling and cohesion." Mr. Picky, August 5. Updated 2019-08-09. Accessed 2020-03-27.
- University of Alberta. 2020. "1.3.1 – Coupling and Cohesion." Object-Oriented Design, Univ. of Alberta, on Coursera. Accessed 2020-03-27.
- Viva Differences. 2019. "Difference Between Coupling And Cohesion In Software Engineering (With Examples)." Viva Differences, October 15. Updated 2019-10-18. Accessed 2020-03-27.
- Wikipedia. 2019. "Cohesion (computer science)." Wikipedia, December 18. Accessed 2020-03-27.
- Wikipedia. 2020. "Coupling (computer programming)." Wikipedia, March 21. Accessed 2020-03-27.
Further Reading
- Stolarczyk, Tomek. 2019. "The forgotten realm of Cohesion." Mr. Picky, August 5. Updated 2019-08-09. Accessed 2020-03-27.
- Stolarczyk, Tomek. 2019. "Six Shades of Coupling." Mr. Picky, August 5. Updated 2020-01-25. Accessed 2020-03-27.
- Chidamber, Shyam R., and Chris F. Kemerer. 1994. "A Metrics Suite for Object Oriented Design." IEEE Trans. on Software Engineering, vol. 20, no. 6, pp. 476-493, June. Accessed 2020-03-27.
- Xiang, Yiming, Weifeng Pan, Haibo Jiang, Yunfang Zhu, and Hao Li. 2019. "Measuring Software Modularity Based on Software Networks." Entropy, vo. 21, no. 4, March. Accessed 2020-03-27.
- Bliss, Andrew. 2020. "How to implement loose coupling, high cohesion in JavaScript." JS in Plain English, on Medium, March 29. Accessed 2020-03-29.
- Nguyen, Thanh Tung. 2016. "Cohesion, Coupling and Abstraction." Medium, September 22. Accessed 2020-03-27.
Article Stats
Cite As
See Also
- Modular Programming
- Dependency Hell
- SOLID Design Principles
- Conway's Law
- Object-Oriented Programming
- Domain-Driven Design