Coupling and Cohesion in Software Engineering [with Examples]

Updated on July 9, 2024

Article Outline

System design and maintainability in software engineering is greatly influenced by cohesion and coupling. Cohesion refers to the relationship between modules, while coupling describes how closely knit a single module’s responsibilities are. For the purpose of creating modular software that is easy to maintain, we must understand these concepts well. Good software design minimises coupling and maximises cohesion in order to ensure adaptability and dependability.

 

This blog will explore definitions of these terms, types, benefits, and drawbacks. In addition, it shall also provide practical code examples showing how they differ from each other clearly.

 

What is Coupling?

 

Coupling in software engineering refers to the degree of direct interdependence between modules. When modules are highly dependent on each other, they are said to be tightly coupled. Conversely, if modules can function independently, they are considered loosely coupled. High coupling can make systems difficult to maintain and evolve because changes in one module may require changes in another. Low coupling, on the other hand, enhances modularity and allows for easier updates and maintenance.

 

Types of Coupling With Examples

 

There are a few types of coupling, and we have covered some of them here.

 

Content Coupling

 

Content coupling occurs when one module directly modifies or relies on the internal workings of another module. This type of coupling is the most restrictive and should be avoided, as it creates strong dependencies between modules, making the system harder to maintain and evolve.

 

Example:

# Module A

class A:

def __init__(self, b):

# Module A is initialised with an instance of Module B

self.b = b

 

def modify_b(self):

# Module A directly modifies the internal data of Module B

self.b.internal_data = 10

 

# Module B

class B:

def __init__(self):

# Module B has an internal data attribute

self.internal_data = 0

 

b = B()

a = A(b)

a.modify_b()

print(b.internal_data)  # Output: 10

 

In the example above, Module A directly accesses and modifies the internal data of Module B, creating a strong dependency between the two modules.

 

Common Coupling

 

Common coupling occurs when multiple modules share global data. This can lead to issues when different modules unintentionally interfere with each other by modifying the shared data. It increases the risk of side effects and makes it harder to understand and debug the system.

 

Example:

# Global data

global_variable = 0

 

# Module A

def function_a():

global global_variable

# Module A modifies the global variable

global_variable += 1

 

# Module B

def function_b():

global global_variable

# Module B also modifies the global variable

global_variable += 2

 

function_a()

function_b()

print(global_variable)  # Output: 3

 

In this example, both function_a and function_b modify a global variable, leading to potential unintended side effects and dependencies between the modules.

 

Control Coupling

 

Control coupling happens when one module controls the behaviour of another by passing it information on what to do. This type of coupling reduces the autonomy of the receiving module and can make the system harder to maintain and understand.

 

Example:

# Module A

def function_a(control_flag):

# Module A controls the behaviour of Module B through the control flag

if control_flag == “start”:

function_b(“initialise”)

elif control_flag == “stop”:

function_b(“shutdown”)

 

# Module B

def function_b(command):

# Module B’s behaviour is dictated by the command it receives

if command == “initialise”:

print(“System Initializing”)

elif command == “shutdown”:

print(“System Shutting Down”)

 

function_a(“start”)  # Output: System Initialising

 

Here, function_a passes a control flag to function_b, dictating its behaviour and creating a dependency between the two functions.

 

Stamp Coupling

 

Stamp coupling occurs when modules share a composite data structure but only use a part of it. This can lead to inefficiencies and makes understanding module dependencies more complex. It can also result in unnecessary data being passed around.

 

Example:

# Composite data structure

class Data:

def __init__(self, field1, field2):

# The Data class has multiple fields

self.field1 = field1

self.field2 = field2

 

# Module A

def function_a():

# Module A creates an instance of the Data class

data = Data(10, 20)

# Module A passes the entire data object to Module B

function_b(data)

 

# Module B

def function_b(data):

# Module B only uses part of the data object

print(data.field1)

 

function_a()  # Output: 10

 

In this example, function_a passes an entire Data object to function_b, even though function_b only uses field1.

 

Data Coupling

 

Data coupling happens when modules share data through parameters. This type of coupling is the least restrictive and generally preferred. It allows for clear and direct communication between modules without creating strong dependencies.

 

Example:

# Module A

def function_a():

# Module A passes a specific value to Module B

value = 5

function_b(value)

 

# Module B

def function_b(value):

# Module B uses the value passed from Module A

print(value)

 

function_a()  # Output: 5

 

In this example, function_a and function_b communicate through a parameter, making their interaction clear and direct without unnecessary dependencies.

 

Message Coupling

 

Message coupling is when modules communicate using message passing or events. This type of coupling is even less restrictive than data coupling because it allows modules to be more independent. Modules interact by sending and receiving messages, which can be more flexible and scalable.

 

Example:

class Event:

def __init__(self, message):

self.message = message

 

class A:

def send_message(self, message):

event = Event(message)

b = B()

b.receive_message(event)

 

class B:

def receive_message(self, event):

print(event.message)

 

a = A()

a.send_message(“Hello, World!”)  # Output: Hello, World!

 

In this example, Module A sends a message to Module B through an event, which Module B processes independently.

 

Message Coupling

 

Message coupling is when modules communicate using message passing or events. This type of coupling is even less restrictive than data coupling because it allows modules to be more independent. Modules interact by sending and receiving messages, which can be more flexible and scalable.

 

External Coupling

 

External coupling occurs when modules depend on external systems or devices. This type of coupling can be problematic if the external dependencies change or become unavailable, leading to potential system failures or the need for significant adjustments.

 

Hybrid Coupling

 

Hybrid coupling is a combination of two or more types of coupling. This type of coupling can introduce complexities in understanding and maintaining the system, as it involves multiple ways in which modules are interdependent.

 

Logical Coupling

 

Logical coupling happens when modules are grouped logically but not necessarily functionally. This type of coupling can lead to misunderstandings about module responsibilities and dependencies, making the system harder to manage.

 

Interface Coupling

 

Interface coupling occurs when modules share an interface definition but not the implementation details. This type of coupling allows modules to interact without needing to know each other’s inner workings, promoting modularity and ease of maintenance.

 

Temporal Coupling

 

Temporal coupling exists when two or more modules must be executed in a specific time sequence. This type of coupling can make the system rigid and difficult to modify, as changes to the timing of one module may affect others.

 

Procedural Coupling

 

Procedural coupling occurs when modules share a procedural sequence of actions. This type of coupling can create dependencies based on the order of execution, which can be restrictive and hard to change.

 

Dynamic Coupling

 

Dynamic coupling occurs when modules interact at runtime based on dynamic conditions or data. This type of coupling can be flexible but also unpredictable, making the system’s behaviour harder to anticipate and test.

 

Passive Coupling

 

Passive coupling happens when modules passively share data through intermediaries, such as databases or files, without direct interaction. This type of coupling can lead to hidden dependencies and potential data consistency issues.

 

Advantages of Low Coupling

 

Low coupling in software design ensures that modules are minimally dependent on each other. This enhances modularity and makes the system easier to maintain and update.

 

  • Improved Maintainability: Changes in one module are less likely to affect other modules.
  • Enhanced Modularity: Each module can be developed, tested, and understood independently.
  • Better Reusability: Modules with low coupling can be reused in different systems or contexts without modification.
  • Easier Debugging and Testing: Isolated modules make it simpler to identify and fix issues.
  • Increased Flexibility: Low coupling allows for easier updates and changes to the system without widespread impact.

 

Disadvantages of High Coupling

High coupling in software design means that modules are highly dependent on each other. This can make the system complex and difficult to manage.

  • Increased Complexity: Tight dependencies make the system harder to understand and modify.
  • Harder Maintenance: Changes made on one module often require corresponding changes on dependent modules.
  • Reduced Flexibility: The system becomes rigid and less adaptable to changes.
  • Lower Reusability: Highly connected modules are difficult to reuse across various contexts
  • Difficult Debugging and Testing: Due to intertwined dependencies, identifying and fixing issues is challenging.

Also Read: COCOMO Model in Software Engineering

*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

What is Cohesion?

Cohesion in software engineering is how much its parts belong together within a given module. Modules that have high levels of cohesion mean that their roles are closely related to one another or confined to one specific function. Conversely, low cohesion means having modules with no clear focus or whose duties cannot easily be streamlined into one particular activity or sub-task.

 

High-cohesion enables systems that can be understood and maintained more easily. When a module has high cohesion, it becomes easier for someone else to reason about, test or even change it at any time if the need arises. It is also possible for reusing modules which are cohesive in nature because they can be adapted for different uses without significant modification.

 

Types of Cohesion With Examples

 

In this section, we have covered a few types of cohesion with code examples.

 

Functional Cohesion

 

Functional cohesion occurs when the elements of a module are grouped together because they all contribute to a single well-defined task.

 

Example:

def calculate_area_of_circle(radius):

# Calculates the area of a circle

return 3.14 * radius * radius

 

# Example usage

print(calculate_area_of_circle(5))  # Output: 78.5

 

In this example, the calculate_area_of_circle function is focused solely on calculating the area of a circle, demonstrating high functional cohesion.

 

Sequential Cohesion

 

Sequential cohesion happens when elements of a module are grouped because the output of one element serves as the input to another.

 

Example:

 

def read_data(file_path):

# Reads data from a file

with open(file_path, ‘r’) as file:

return file.read()

 

def process_data(data):

# Processes the read data

return data.upper()

 

def write_data(file_path, data):

# Writes processed data to a file

with open(file_path, ‘w’) as file:

file.write(data)

 

# Example usage

data = read_data(‘input.txt’)  # Reads data from input.txt

processed_data = process_data(data)  # Processes the read data

write_data(‘output.txt’, processed_data)  # Writes the processed data to output.txt

 

Here, the output of read_data is used as input for process_data, and the output of process_data is used as input for write_data, showing sequential cohesion.

 

Communicational Cohesion

 

Communicational cohesion occurs when elements of a module are grouped because they operate on the same data.

 

Example:

def process_report(data):

# Processes the report data

processed_data = data.upper()

print_report(processed_data)

 

def print_report(data):

# Prints the processed report data

print(data)

 

# Example usage

report_data = “this is a report”

process_report(report_data)  # Output: THIS IS A REPORT

 

In this example, both process_report and print_report operate on the same data, demonstrating communicational cohesion.

 

Procedural Cohesion

 

Procedural cohesion happens when elements of a module are grouped because they are part of a sequence of steps to be followed.

 

Example:

 

def initialize_system():

# Initialises the system

print(“System Initialized”)

 

def load_data():

# Loads data into the system

print(“Data Loaded”)

 

def start_processing():

# Starts processing the data

print(“Processing Started”)

 

def main():

# Follows a sequence of initialization, loading data, and starting processing

initialize_system()

load_data()

start_processing()

 

# Example usage

main()

 

Here, initialize_system, load_data, and start_processing are part of a sequence of steps, showing procedural cohesion.

 

Temporal Cohesion

 

Temporal cohesion occurs when elements are grouped together because they are related by the time at which they are executed.

 

Example:

def initialize_system():

# Initialises the system at startup

print(“System Initialized”)

 

def initialize_logging():

# Initialises logging at startup

print(“Logging Initialized”)

 

def initialize_configuration():

# Initialises configuration at startup

print(“Configuration Initialized”)

 

def startup():

# Performs several initialization tasks that need to happen at startup

initialize_system()

initialize_logging()

initialize_configuration()

 

# Example usage

startup()

 

In this example, initialize_system, initialize_logging, and initialize_configuration are all executed at startup, demonstrating temporal cohesion.

 

Logical Cohesion

 

Logical cohesion happens when elements of a module are grouped because they perform similar activities, even if they are functionally different. For example, a module that contains various utility functions for string manipulation.

 

Coincidental Cohesion

 

Coincidental cohesion occurs when elements are grouped arbitrarily without any meaningful relationship. This is the lowest form of cohesion and should be avoided. An example could be a module that contains unrelated functions like error logging and file compression.

 

Class Cohesion

 

Class cohesion refers to the degree to which the methods and properties of a class are related to each other. High-class cohesion means that all elements of the class contribute to a single well-defined purpose.

 

Object Cohesion

 

Object cohesion is similar to class cohesion but focuses on the cohesion of an object instance at runtime. High object cohesion means that all operations performed by an object are related to its state.

 

Layer Cohesion

 

Layer cohesion occurs in layered architectures, where each layer groups related functionalities. High layer cohesion ensures that each layer has a well-defined responsibility, like presentation, business logic, or data access.

 

Domain Cohesion

 

Domain cohesion happens when elements are grouped because they belong to the same domain or context. For example, a module that handles all aspects of user management, including authentication, profile management, and permissions.

 

Subsystem Cohesion

 

Subsystem cohesion refers to the degree to which modules within a subsystem are related and work together to achieve a specific subsystem-level functionality. High subsystem cohesion makes the subsystem easier to understand and maintain.

 

Configuration Cohesion

 

Configuration cohesion happens when elements are grouped because they are part of the configuration settings of a system. High configuration cohesion ensures that all configuration-related tasks are handled in a single place.

 

Communication Cohesion

 

Communication cohesion occurs when elements are grouped because they communicate with the same external system or interface. For example, a module that handles all interactions with a third-party API.

 

Advantages of high cohesion

 

High cohesion in software design means that the elements within a module are closely related and focused on a single task or purpose. This brings several benefits to the system.

  • Easier Maintenance: Highly cohesive modules are simpler to maintain because they have a clear, well-defined purpose.
  • Better Understandability: Modules with high cohesion are easier to understand and reason about, which reduces the learning curve for new developers.
  • Enhanced Reusability: A highly cohesive module can be reused across different projects since it performs a specific, well-defined function.
  • Improved Debugging and Testing: Cohesive modules are easier to test and debug because they encapsulate a single responsibility.
  • Increased Modularity: High cohesion contributes to modular design, where each module operates independently, enhancing the overall system architecture.

 

Disadvantages of Low Cohesion

 

Low cohesion in software design indicates that a module performs a variety of unrelated tasks. This can lead to several issues that affect the system’s quality and maintainability.

  • Poor Modularity: Modules with low cohesion often have multiple, unrelated responsibilities, making the system less modular.
  • Increased Difficulty in Maintenance: Maintaining a module that handles many different tasks is more challenging because changes in one part can affect other unrelated parts.
  • Harder to Understand: Low cohesion makes it difficult for developers to understand the module’s purpose and functionality, leading to a steeper learning curve.
  • Reduced Reusability: Modules with low cohesion are harder to reuse in different contexts because they perform too many unrelated functions.
  • Complex Debugging and Testing: Debugging and testing a module with low cohesion is complex because the module does not encapsulate a single responsibility, making it harder to isolate and fix issues.

 

Difference Between Coupling and Cohesion

 

Aspect Coupling Cohesion
Definition Degree of dependence between modules The degree to which elements within a module belong together
Focus Interaction between different modules Responsibilities within a single module
Ideal Scenario Low coupling High cohesion
Effect on Maintenance Low coupling makes maintenance easier High cohesion makes maintenance easier
Effect on Modularity Low coupling enhances modularity High cohesion enhances modularity
Impact on Reusability Low coupling improves reusability High cohesion improves reusability
Debugging and Testing Easier with low coupling Easier with high cohesion
System Flexibility More flexible with low coupling More focused and reliable with high cohesion
Examples Data coupling, message coupling Functional cohesion, sequential cohesion
Unwanted Scenario High coupling Low cohesion
Key Benefit Reduces interdependencies between modules Increases the clarity and purpose of each module
Main Challenge Managing dependencies Ensuring all elements serve a common goal
Relationship Inverse relationship: As coupling decreases, cohesion tends to increase Direct relationship: As cohesion increases, module quality improves

 

Conclusion

In summary, understanding coupling and cohesion is essential for designing modular and maintainable software. Coupling refers to the degree of interdependence between modules, with low coupling being ideal for easier maintenance and flexibility. Cohesion, on the other hand, measures how closely related the responsibilities within a module are, with high cohesion leading to better understandability, reusability, and ease of maintenance.

 

By striving for low coupling and high cohesion, software engineers can create robust, scalable, and maintainable systems. These principles not only improve the quality of the code but also make the development process more efficient and manageable. Applying these concepts effectively ensures that the software can adapt to changes and grow with evolving requirements.

 

 

FAQs
Coupling refers to the degree of dependence between modules in a software system. Low coupling is preferred as it makes the system more modular and easier to maintain.
Cohesion measures how closely related the functions within a single module are. High cohesion means the module has a well-defined purpose, making it easier to maintain and understand.
Low coupling is important because it reduces dependencies between modules, making the system easier to modify, test, and maintain.
High cohesion is desirable because it ensures that a module performs a single task or a set of related tasks, which enhances understandability, maintainability, and reusability.
Coupling and cohesion significantly impact software design by influencing modularity, maintainability, and flexibility. Low coupling and high cohesion lead to better-structured and more maintainable software systems.

Updated on July 9, 2024

Link

Upskill with expert articles

View all
Free courses curated for you
Basics of Python
Basics of Python
icon
5 Hrs. duration
icon
Beginner level
icon
9 Modules
icon
Certification included
avatar
1800+ Learners
View
Essentials of Excel
Essentials of Excel
icon
4 Hrs. duration
icon
Beginner level
icon
12 Modules
icon
Certification included
avatar
2200+ Learners
View
Basics of SQL
Basics of SQL
icon
12 Hrs. duration
icon
Beginner level
icon
12 Modules
icon
Certification included
avatar
2600+ Learners
View
next_arrow
Hero Vired logo
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved