Cohesion and Coupling in Module Design
In software design, a module is a logically bounded unit such as a function, class, package, service, or subsystem. Two complementary properties help evaluate its design:
- Cohesion
- Coupling
- Module
- Interface
Cohesion examines relationships inside a module. Coupling examines dependencies between modules. A commonly preferred design target is high cohesion and low coupling, because focused modules are generally easier to understand, test, reuse, and modify.2
The following sections enumerate the traditional types of cohesion and coupling, with examples and design implications.
Footnotes
-
Coupling and Cohesion - GeeksforGeeks - Definitions and traditional classifications of cohesion and coupling, including examples. ↩
-
Coupling (computer programming) - Wikipedia - Overview of coupling as the degree of interdependence between software modules and common module-coupling categories. ↩
Design Heuristic
Aim for the strongest practical cohesion within each module and the weakest practical coupling between modules. Do not apply the rule mechanically: performance, transaction boundaries, deployment needs, and external protocols may justify exceptions.
1. Types of Cohesion
Cohesion is commonly described from weakest to strongest. The sequence is a design spectrum rather than an absolute measurement: a real module may exhibit more than one kind of cohesion.
| Type | Basis for grouping | Relative quality |
|---|---|---|
| Coincidental | Elements are placed together without a meaningful relationship | Weakest |
| Logical | Similar categories of activity are grouped; one is selected by a flag | Weak |
| Temporal | Activities occur during the same phase or time | Low to moderate |
| Procedural | Activities must follow a particular execution order | Moderate |
| Communicational | Activities operate on the same data or contribute to the same output | Moderate to strong |
| Sequential | One activity’s output becomes another activity’s input | Strong |
| Functional | Every element contributes to one well-defined task | Strongest |
This traditional ordering is reported in software-engineering treatments of cohesion, although some modern design approaches also discuss informational cohesion and object cohesion.2
Footnotes
-
Coupling and Cohesion - GeeksforGeeks - Definitions and traditional classifications of cohesion and coupling, including examples. ↩
-
Understanding Cohesion, Coupling and Connascence in Software - Examples and qualitative ordering of cohesion types. ↩
2. Coincidental Cohesion
Coincidental cohesion occurs when unrelated functions happen to share a module. The grouping may result from convenience, historical growth, or a vague name such as Utilities.
Example
1module MiscellaneousUtilities 2 calculateTax() 3 resizeImage() 4 sendEmail() 5 parseConfigurationFile() 6 generateRandomPassword()
These operations have no single conceptual responsibility. A change to image processing should not require understanding email delivery or tax calculation.
Consequences
- Difficult to name the module precisely
- High risk of unrelated changes affecting one another
- Poor discoverability and reuse
- Tests become broad and difficult to isolate
Better design
Split the module into focused units:
1TaxCalculator 2ImageResizer 3EmailSender 4ConfigurationParser 5PasswordGenerator
3. Logical Cohesion
Logical cohesion exists when a module contains several operations that belong to the same broad category, but only one operation executes for a particular call.
Example
1module InputHandler 2 handleInput(input, inputType): 3 if inputType == "keyboard": 4 processKeyboardInput(input) 5 else if inputType == "mouse": 6 processMouseInput(input) 7 else if inputType == "touch": 8 processTouchInput(input)
The operations are logically related because they handle input. However, the control parameter determines which distinct behavior occurs.
Why it is weaker than functional cohesion
The module does not perform one operation. Instead, it acts as a dispatcher for several alternatives. Each branch may have different data, validation, and failure behavior.
Better design
Use polymorphism or separate handlers:
1InputHandler 2KeyboardInputHandler 3MouseInputHandler 4TouchInputHandler
A common interface can preserve substitutability without placing all implementation branches in one module.
4. Temporal Cohesion
Temporal cohesion occurs when operations are related mainly by time.
Example
1module ApplicationStartup 2 readEnvironmentVariables() 3 initializeLogging() 4 openDatabaseConnection() 5 loadConfiguration() 6 registerShutdownHook()
These activities execute during application startup, but they may have little functional relationship beyond that shared phase.
Another example is a shutdown module:
1module ApplicationShutdown 2 flushLogs() 3 closeDatabaseConnection() 4 releaseCache() 5 stopBackgroundWorkers()
Appropriate use
Temporal cohesion can be reasonable for lifecycle modules, initialization routines, and cleanup procedures. It becomes problematic when the module grows into a general-purpose container for all operations that happen at a particular time.
Design question
Ask whether each operation belongs to the same lifecycle responsibility or merely happens to run in the same phase.
5. Procedural Cohesion
Procedural cohesion occurs when activities are connected by their control-flow sequence.
Example
1module ProcessStudentRecord 2 readStudentRecord() 3 validateRecord() 4 printRecord() 5 writeAuditEntry()
The operations must occur in a particular order, but the relationship between them may be primarily procedural. Printing a record and writing an audit entry are not necessarily part of one conceptual computation.
Distinction from sequential cohesion
In procedural cohesion, the important relationship is the order of execution. In sequential cohesion, data produced by one operation becomes the meaningful input to the next.
1Procedural: 2 authenticateUser() 3 displayDashboard()
The first operation may establish permission, but it does not necessarily produce the dashboard data consumed by the second.
1Sequential: 2 parseRequest() -> validateRequest() -> createCommand()
Here, each stage transforms data for the next stage.
6. Communicational Cohesion
Communicational cohesion occurs when several operations are related through a common data set.
Example
1module CustomerRecordProcessor 2 updateCustomerAddress(customerRecord) 3 calculateCustomerRisk(customerRecord) 4 writeCustomerAuditEntry(customerRecord)
All operations use the same customer record. They are related by the data on which they operate, although each operation may represent a different business purpose.
Another example:
1module OrderReport 2 readOrder(order) 3 calculateOrderTotal(order) 4 formatOrderSummary(order) 5 printOrderSummary(order)
Strengths
- Data locality can simplify reasoning
- Related transformations may be easier to coordinate
- Shared invariants can be maintained in one place
Risks
Communicational cohesion can become a disguised “record-processing” module containing many unrelated actions. If the operations change for different business reasons, they may belong in separate modules even when they use the same data.
7. Sequential Cohesion
Sequential cohesion exists when a module implements a meaningful data pipeline.
Example
1module ImportCustomerFile 2 rawText = readFile(filePath) 3 records = parseCsv(rawText) 4 validRecords = validateRecords(records) 5 customers = mapToCustomers(validRecords) 6 saveCustomers(customers)
The stages are connected by data flow:
Sequential cohesion is often stronger than procedural cohesion because the steps are not merely ordered; each step contributes data required by the next step.
Design consideration
A long pipeline may still be difficult to maintain if it combines multiple business policies. In such cases, retain the pipeline orchestration in one module and extract each transformation into a focused component.
8. Functional Cohesion
Functional cohesion is generally regarded as the strongest traditional form of cohesion.
Example
1module CalculateInvoiceTotal 2 calculateSubtotal(lineItems) 3 calculateDiscount(subtotal, customerType) 4 calculateTax(taxableAmount, taxRate) 5 calculateTotal(subtotal, discount, tax)
Every operation contributes directly to calculating one invoice total.
A smaller example is:
1function hashPassword(password, salt): 2 normalized = normalizePassword(password) 3 derivedKey = deriveKey(normalized, salt) 4 return encode(derivedKey)
The internal steps all support one externally visible purpose.
Characteristics
- One clear responsibility
- A precise, meaningful name
- Small and understandable interface
- Easier unit testing
- Greater potential for reuse
- Changes are localized to one purpose
Microsoft describes strong module cohesion as a module representing exactly one task, and relates cohesion to maintainability, reusability, and changeability.
Footnotes
-
Code metrics: Class coupling - Microsoft Learn - Discussion of module cohesion, class coupling, and the relationship to maintainability and reuse. ↩
Cohesion: Common Classification Questions
9. Types of Coupling
Coupling describes how one module depends on another. Traditional classifications commonly include:
| Type | Dependency mechanism | Relative risk |
|---|---|---|
| Content | One module reaches into or changes another’s internals | Highest |
| Common | Modules share global data | Very high |
| External | Modules depend on an externally imposed format, protocol, or device | High |
| Control | One module passes information that directs another’s behavior | Moderate to high |
| Stamp | A composite structure is passed, although only part is used | Moderate |
| Data | Modules communicate through required data parameters | Low |
| Message | Modules communicate through messages or stable contracts without shared representation | Lowest in many object/service designs |
The exact ordering can vary by textbook and context. The central principle is that coupling increases when modules share implementation details, mutable state, control decisions, or unstable representations.2
Footnotes
-
Coupling (computer programming) - Wikipedia - Overview of coupling as the degree of interdependence between software modules and common module-coupling categories. ↩
-
Cohesion and Coupling in Software with Examples - Discussion of cohesion and coupling as complementary design properties and examples of weak cohesion. ↩
10. Content Coupling
Content coupling is traditionally considered the most undesirable form.
Example
1module ReportGenerator 2 directly modifies DatabaseManager.connectionPool 3 jumps into Parser.internalBuffer 4 changes Cache.privateEntries
In pseudocode:
1module A: 2 B.internalCounter = 0 3 B.privateBuffer.append(data)
Module A depends on the internal representation of B, not merely on its public interface.
Why it is dangerous
- Internal changes in
Bcan breakA - Encapsulation is violated
- Testing becomes difficult
- Ownership of state becomes unclear
- Reuse and independent deployment are impaired
Better design
Expose behavior through a stable interface:
1cache.clear() 2parser.parse(input) 3databaseManager.resetConnectionPool()
The caller requests an operation without manipulating internal data structures.
11. Common Coupling
Common coupling occurs when modules communicate through common state rather than explicit interfaces.
Example
1global currentUser 2global systemMode 3global taxRate 4 5module Checkout: 6 total = subtotal * taxRate 7 8module Administration: 9 taxRate = newRate
Checkout silently depends on the value and lifetime of a global variable that Administration can change.
Consequences
- Hidden dependencies
- Difficult order-of-execution reasoning
- Unpredictable tests
- Risk of accidental modification
- Poor support for concurrency and parallel execution
Better design
Pass dependencies explicitly:
1calculateTotal(subtotal, taxRate)
Or encapsulate shared state behind a carefully designed service whose ownership and update rules are explicit.
12. External Coupling
External coupling occurs when modules are connected through an external environment.
Example
1module Billing: 2 writes records using a legacy fixed-width file format 3 4module Reporting: 5 reads the same fixed-width format
Both modules depend on the external file layout:
1positions 1-10 customer identifier 2positions 11-20 invoice number 3positions 21-30 amount
Other examples include:
- Two modules depending on a vendor-specific database schema
- Components sharing an operating-system device protocol
- Services depending on a particular wire format
- Modules relying on a third-party API’s exact error codes
Management technique
Isolate external coupling behind an adapter:
This confines changes to the boundary and protects the core design from external representation details.
13. Control Coupling
Control coupling occurs when a caller tells a callee how to perform its work.
Example
1module ReportController: 2 generateReport(data, format="PDF") 3 4module ReportGenerator: 5 if format == "PDF": 6 generatePdf(data) 7 else if format == "CSV": 8 generateCsv(data)
The format parameter is not ordinary business data; it controls the callee’s algorithmic path.
Problems
- The caller knows about alternatives inside the callee
- Adding a new mode may require changes in several modules
- Branches make testing more complex
- The callee has multiple responsibilities
Better design
Use separate strategy objects or polymorphic implementations:
1ReportGenerator(pdfFormatter).generate(data) 2ReportGenerator(csvFormatter).generate(data)
The caller selects an implementation while each formatter remains focused.
14. Stamp Coupling
Stamp coupling occurs when a whole record, object, or data structure crosses a module boundary even though the callee needs only some fields.
Example
1module Shipping: 2 calculateShipping(customerOrder)
The customerOrder object may contain:
1orderId 2customerName 3billingAddress 4shippingAddress 5paymentDetails 6marketingPreferences 7lineItems
If Shipping uses only shippingAddress and lineItems, passing the entire object creates stamp coupling.
Risks
- The callee becomes dependent on an oversized structure
- Unrelated changes to the structure can affect the callee
- The interface hides the true data requirements
- Sensitive data may cross boundaries unnecessarily
Better design
Pass a focused value object:
1calculateShipping(shippingAddress, lineItems)
However, passing a composite object can be justified when the object is the genuine abstraction being operated on or when preserving an invariant is important.
Footnotes
-
Coupling (computer programming) - Wikipedia - Overview of coupling as the degree of interdependence between software modules and common module-coupling categories. ↩
15. Data Coupling
Data coupling occurs when modules exchange only the data required to perform their responsibilities.
Example
1module OrderService: 2 total = PricingService.calculateTotal(lineItems, taxRate)
PricingService receives the values it needs and returns a result. It does not access the caller’s variables, alter global state, or receive a control flag describing its internal algorithm.
Characteristics
- Dependencies are visible in the interface
- Modules can be tested with ordinary inputs
- Internal implementation can change independently
- Data flow is easier to trace
Caution
Data coupling is not automatically good if the interface contains too many parameters, leaks internal structures, or transfers mutable objects whose invariants are unclear. A small, stable abstraction is preferable to a long parameter list.
16. Message Coupling
Message coupling is common in object-oriented, event-driven, and distributed systems.
Example
1OrderService publishes: 2 OrderPlaced { orderId, customerId } 3 4InventoryService subscribes to: 5 OrderPlaced
The publisher does not call the inventory implementation directly or access its state. It sends a message conforming to a contract.
Another example is an object invoking a public operation:
1paymentGateway.authorize(paymentRequest)
The caller depends on the operation contract, not on the gateway’s internal fields.
Benefits
- Reduced knowledge of implementation details
- Easier substitution and independent testing
- Better support for asynchronous processing
- Clearer architectural boundaries
Trade-offs
Message coupling can introduce operational complexity, including message versioning, delivery failures, retries, ordering, and eventual consistency. Loose coupling does not eliminate dependencies; it changes their form.
Do Not Confuse Low Coupling with No Coupling
A useful module must depend on something: an interface, data contract, database, message schema, or domain rule. The goal is explicit, stable, and minimal dependency—not the impossible removal of every dependency.
17. Cohesion and Coupling Compared
| Question | Cohesion | Coupling |
|---|---|---|
| Scope | Inside one module | Between modules |
| Main concern | Whether responsibilities belong together | Whether dependencies are excessive |
| Preferred direction | High | Low |
| Typical symptom of poor design | “God module” with unrelated behavior | Ripple effects across many modules |
| Improvement technique | Split responsibilities by purpose | Hide details and narrow interfaces |
A module can have high cohesion but still be highly coupled. For example, a focused PaymentProcessor may directly depend on five concrete payment providers and several global configuration objects. Conversely, a module may have low coupling but poor cohesion if it is isolated yet contains unrelated utilities.
The desirable quadrant is therefore:
Relative Design Preference
Traditional classifications are qualitative; the values illustrate relative preference, not a universal metric.
How to Diagnose a Module
- 1Step 1
Write a one-sentence responsibility statement. If the sentence contains several unrelated verbs joined by 'and', the module may have low cohesion.
- 2Step 2
Record functions, classes, state, and branches. Group them by the business or technical reason they exist.
- 3Step 3
Determine whether elements are related by chance, category, time, order, shared data, data flow, or one unified function.
- 4Step 4
Include parameters, return types, method calls, shared state, files, databases, protocols, flags, and message schemas.
- 5Step 5
Check for content, common, external, control, stamp, data, or message coupling. Use the most restrictive dependency as the warning signal.
- 6Step 6
Extract unrelated responsibilities, replace global state with explicit dependencies, pass only required data, and hide external formats behind adapters.
- 7Step 7
Verify that the refactoring did not create excessive fragmentation, duplicated logic, performance problems, or an interface that is harder to use.
18. Worked Example
Consider this initial module:
1module UserOperations 2 createUser(userRecord, sendWelcomeEmail) 3 exportUsersToCsv() 4 resetPassword(userId) 5 updateGlobalUserCount() 6 loadUsersFromLegacyFile()
Cohesion diagnosis
The module contains:
- User creation
- Email notification
- CSV export
- Password management
- Global-state maintenance
- Legacy-file integration
These responsibilities are related only broadly to users. The module likely exhibits logical, temporal, and possibly coincidental cohesion, rather than functional cohesion.
Coupling diagnosis
It may exhibit:
- Control coupling through
sendWelcomeEmail - Common coupling through
globalUserCount - External coupling through the legacy file
- Stamp coupling through
userRecordif only selected fields are used
Refactored design
1UserRegistrationService 2PasswordResetService 3UserExportService 4UserCountRepository 5LegacyUserFileAdapter
A focused registration service might use:
1UserRegistrationService.register( 2 username, 3 email, 4 password 5)
The email decision can be delegated to a notification policy, and the legacy file format can be isolated in LegacyUserFileAdapter.
Result
The refactored design increases cohesion by assigning one purpose to each module and reduces coupling by:
- Removing global state
- Narrowing parameters
- Replacing control flags with abstractions
- Isolating external formats
- Exposing behavior through interfaces
Cohesion and Coupling Review
Exam and Design Checklist
Knowledge Check
Which type of cohesion exists when every element of a module contributes to one well-defined task?
References
Explore Related Topics
Data Communication Components: Various Connection Topology, Protocols and Standards
Data communication fundamentals are presented, detailing the five essential components, common physical and logical topologies, protocol layering (OSI and TCP/IP), and the standards bodies that ensure interoperability.
- Core components: message, sender, receiver, transmission medium, protocol; transmission modes include simplex, half‑duplex, and full‑duplex.
- Topologies: bus, star, ring, mesh, tree, hybrid—each balancing cost, fault tolerance, scalability, and complexity.
- Protocols define syntax, semantics, and timing; OSI (7 layers) and TCP/IP (4 layers) use key protocols such as IP, TCP, UDP, HTTP.
- Standards from ISO, ITU‑T, IEEE (e.g., 802.3 Ethernet, 802.11 Wi‑Fi) and IETF guarantee vendor‑independent communication.
- Design guidance: align requirements with appropriate topology, media, protocol stack, and verify compliance with relevant standards.
Software Engineering: Foundations, Processes, Requirements, Design, Testing, and Maintenance
Database Views and the Concept of a Subschema