The 7 Types of Cohesion You Need to Know to Be the Best Software Engineer with Pythonic Code Samples

Spread the love

In this blog post, you will learn what cohesion is, why it’s important, and the seven types of cohesion, which are coincidental cohesion, logical cohesion, temporal cohesion, procedural cohesion, communicational cohesion, sequential cohesion, and functional cohesion (“CPSC 333: Levels of Cohesion”, n.d.).

What is Cohesion in Software Engineering and Why is it Important?

Cohesion in Software Engineering refers to the level of relatedness in functionality of a software module, where a module from an Object Oriented Programming (OOP) is a class (Hooshyar & Izadkhah, 2017). Software that is highly cohesive has desirable traits, such as being robust, reliable, reusable, and understandable. Software that has low cohesion has the following undesirable traits, such as difficult to understand, test, maintain, and reuse.

The Seven Types of Cohesion

The seven types of cohesion from least desirable to most desirable are coincidental cohesion, logical cohesion, temporal cohesion, procedural cohesion, communicational cohesion, sequential cohesion, and functional cohesion.

Coincidental Cohesion

Coincidental cohesion, the worst level of cohesion, involves having methods in a module that are all completely unrelated in functionality (“CPSC 333: Levels of Cohesion”, n.d.). For example, a Utilities class with methods read_file, display, and calculate_price_based_on_discount is an example of coincidental cohesion since none of the functionality of the methods are related. The following pythonic code sample has a module, or class, that is coincidentally cohesive, which should be avoided at all costs:

# The below class is coincidentally cohesive because none of the functionality of the methods are related.

class Utilities:
    @classmethod
    def calculate_price_based_on_discount(cls, price:float, discount:float):
        return price - price*discount
    
    @classmethod
    def read_file(cls, file_name):
        file_contents = ""
        with open(file_name) as file_handle:
            file_contents = file_handle.read()
        
        return file_contents
    
    @classmethod
    def display(cls, message):
        print(message)

In this situation, it is better to create separate classes for the methods, which increases cohesion. You can create a Price class with a method that calculates the discounted price, a ConsoleOutputDisplayer class for displaying console output, and a FileReader class for reading the contents, such as the following:

class Price:
    def __init__(self, price:float):
        self._price = price
    
    def discounted_price(self, discount:float):
        return self._price - self._price*discount

class ConsoleOutputDisplayer:
    @classmethod
    def display(cls, msg:str):
        print(msg)

class FileReader:
    def __init__(self, file_name:str):
        self._file_name = file_name

    def read(self):
        file_contents = ""
        with open(self._file_name) as file_handle:
            file_contents = file_handle.read()
        
        return file_contents

Logical Cohesion

Logical cohesion, a step above coincidental cohesion, involves grouping functionality based on performing similar functionality (“CPSC 333: Levels of Cohesion”, n.d.); however, the functionality is still different, so it should be avoided unless absolutely necessary. For example, as seen in the following pythonic code sample, a DeviceInputReader class with methods that read input from different input devices is logically cohesive because all the methods are related in the sense that they read input from input devices:

import pyautogui

# This class is Logically Cohesive because all the methods
# read input from different devices.

class DeviceInputReader:
    @classmethod
    def read_file(cls, file_name:str):
        file_contents = ""
        with open(file_name) as file_handle:
            file_contents = file_handle.read()
        
        return file_contents
    
    @classmethod
    def read_console(cls, prompt:str):
        return input(prompt)
    
    @classmethod
    def read_mouse_position(cls):
        return pyautogui.position()

In this situation, to make this code easier to maintain and reuse, it is better to create a different class for each input device, which is functionally cohesion, which is the highest and most desirable form of cohesion, which will be discussed more thoroughly later on in this blog post. Also, one can use an interface or abstract class in python which enables you to loosely couple the classes, which is another preferable design pattern.

import pyautogui
from abc import ABC, abstractmethod

# Improvement from Logical Cohesion to Functional Cohesion

class Reader(ABC):
    @abstractmethod
    def read():
        pass

class FileReader(Reader):
    def __init__(self, file_name:str):
        self._file_name = file_name

    def read(self):
        file_contents = ""
        with open(self._file_name) as file_handle:
            file_contents = file_handle.read()
        
        return file_contents

class MouseReader(Reader):
    def __init__(self):
        pass

    def read(self):
        return pyautogui.position()


class ConsoleReader(Reader):
    def __init__(self, prompt:str):
        self._prompt = prompt
    
    def read(self):
        return input(self._prompt)
        

Temporal Cohesion

Temporal Cohesion involves grouping parts of a module based on the time they are processed during execution of the program. Typically, any code that involves starting up, initializing, shutting down, or terminating involves code that exhibits temporal cohesion (Samir, 2023b).

Temporal cohesion can occur at the function/method level and class level (Samir, 2023a). To see temporal cohesion at the function level consider the following pythonic code sample:

def startup():
    initialize_configuration()
    intialize_database()
    

def initialize_configuration():
    print("initializing configuration")

def intialize_database():
    print("initializing database")

The implementation of the startup function is temporal since initializing the configuration and initializing the database are procedures that must be executed when the program starts. It is also important to note that the individual functions initialize_configuration and initialize_database are functionally cohesive since they each perform a well-defined task.

At the class level, consider the class called Initializer, which is temporally cohesive, and has the methods initialize_configuration and initialize_database, and it has the following implementation (Note: the actual implementations are mocked with print statements since the implementations are not necessary for understanding the concept):

class Initializer:
    def __init__(self):
        pass

    def intialize_configuration(self):
        print("initializing configuration")
 
    def intialize_database(self):
        print("initializing database")

To increase cohesion, it is better if you place these initialize methods into separate classes. The following illustrates an implementation where the initialize methods are in separate modules:

class Configuration:
    def __init__(self):
        pass

    def initialize(self):
        print("initialize the configuration")

class Database:
    def __init__(self):
        pass

    def initialize(self):
        print("initialize the database")

class Application:
    def __init__(self):
        self._config = Configuration()
        self._database = Database()
    
    def startup(self):
        self._config.initialize()
        self._database.initialize()

def main():
    app:Application = Application()
    app.startup()

Procedural Cohesion

Procedural cohesion involves grouping methods of a class based on their sequence of execution (“Software Engineering”, 2018). For example, a RemoteMessageSender class with a ping method and send_message method. The RemoteMessageSender is procedurally cohesive because before a message is sent, the ping method is invoked to ensure the host is alive.

class RemoteMessageSender:
    def __init__(self):
        pass
    
    def ping(self):
        print("Ping Receiver")
    
    def send_message(self, message):
        print("Send Remote Message")

It is important to note that procedural cohesion is like sequential cohesion, but sequential cohesion is different because it involves code execution where the output from one method call is the input to the next method call, and the execution forms a chain.

Communicational Cohesion

Communicational cohesion is the third highest level of cohesion, and it is more preferable than previous levels of cohesion mentioned (Samir, 2023a). Communicational cohesion involves having a class with a group of methods that read and write the same data or data structure. For example, a data access object that queries, updates, inserts, and deletes records in a database associated with user table is communicationally cohesive. The following python code sample of a UserDao or data access object is communicationally cohesive (Note: The implementation of interacting with the data is mocked since the actual implementation is not necessary for understanding the concept.):

class UserDao:
    def __init__(self):
        pass

    def get_user_by_id(self, id):
        print(f"Get user by id {id}")

    def delete_user_by_id(self, id):
        print(f"Delete user by id {id}")

    def update_user_by_id(self, id, user):
        print(f"Update user by id {id}")
    
    def insert_user(self, user):
        print(f"Inserting user {user}")

class User:
    def __init__(self, id, name):
        self._id = id
        self._name = name
    
    @property
    def id(self):
        return self._id

    @property
    def name(self):
        return self._name

    def __str__(self):
        return f"User(id={self._id},name={self._name})"

def main():
    u = User(1, "Gary Drocella")

    userDao = UserDao()
    userDao.get_user_by_id(5)
    userDao.delete_user_by_id(5)
    userDao.update_user_by_id(5, u)
    userDao.insert_user(u)

main()

Another example of communicational cohesion is a grocery list because all of the methods operate on the same data structure, which in the following pythonic code sample, is a list:

class GroceryList:
    def __init__(self):
        self._grocery_list = []
    
    def add_item(self, item):
        self._grocery_list.append(item)
    
    def get_item_at_index(self, i):
        return self._grocery_list[i]

Sequential Cohesion

In sequential cohesion, the output of a method in a class becomes the input to another method in the same class (“Software Engineering”, 2018). To demonstrate sequential cohesion consider the implementation of an initialize method in a Configuration class that invokes a private method read_config, which reads a configuration file, and invokes another private method called parse_config, which parses the JSON configuration data from read_config and stores it in an instance variable called _config that is a dict datatype. In this scenario, read_config and parse_config are sequentially cohesive.

The following pythonic code sample has the implementation of the Configuration class, which is sequentially cohesive:

from abc import ABC, abstractmethod
import os
import json

class Reader(ABC):
    @abstractmethod
    def read(self):
        pass

    @abstractmethod
    def can_read(self):
        pass


class FileReader(Reader):
    def __init__(self, file_name:str):
        self._file_name = file_name

    def read(self):
        file_contents = ""

        if self.can_read():
            with open(self._file_name) as file_handle:
                file_contents = file_handle.read()
        
        return file_contents

    def can_read(self):
        return os.access(self._file_name, os.R_OK)

class Configuration:
    def __init__(self, config_file_name):
        self._config_file_name = config_file_name
        self._config = None

    def initialize(self):
        # The below methods are sequentially cohesive because
        # the output of _read_config() is the input to _parse_config()
        config = self._read_config()
        self._config = self._parse_config(config)

    def _read_config(self):
        reader:Reader = FileReader(self._config_file_name)
        return reader.read()

    def _parse_config(self, config):
        return json.loads(config)

    @property
    def config_dict(self) -> dict:
        return self._config

def main():
    config = Configuration("config.json")
    config.initialize()
    config_dict = config.config_dict

main()

Functional Cohesion

Functional cohesion is the highest and most desirable level of cohesion because all the elements of the module contribute to perform one well-defined task (Ingeno, 2018). One example of a functionally cohesive module is the FileReader class that has been reused throughout this blog post. All the components of the FileReader class serve one purpose, which is to read a file. The following is the implementation of the FileReader class:

from abc import ABC, abstractmethod
import os


class Reader(ABC):
    @abstractmethod
    def read(self):
        pass


class FileReader(Reader):
    def __init__(self, file_name:str):
        self._file_name = file_name

    def read(self):
        file_contents = ""

        with open(self._file_name) as file_handle:
            file_contents = file_handle.read()
        
        return file_contents


def main():
    reader:Reader = FileReader("data.in")
    print(reader.read())

main()

Other examples of functional cohesion include a method that calculates a discounted price, a method that calculates the square root of a number, a method that sorts an array, or a constructor that only sets the instance variables of a class.

In this blog post, you learned about the seven types of cohesion, which are coincidental cohesion, logical cohesion, temporal cohesion, procedural cohesion, communicational cohesion, sequential cohesion, and functional cohesion. You were also given many different code samples of each type of cohesion.

Thanks for reading! For more blog posts just like this, subscribe, share, and buy me a coffee.

Subscribe

* indicates required

Intuit Mailchimp

References

CPSC 333: Levels of Cohesion. (n.d.). Ucalgary.Ca. Retrieved December 16, 2023, from https://pages.cpsc.ucalgary.ca/~eberly/Courses/CPSC333/Lectures/Design/cohesion.html

Ingeno, J. (2018). Software architect’s handbook. Packt Publishing.

Izadkhah, H., & Hooshyar, M. (2017). Class cohesion metrics for software engineering: A critical review. Computer Science Journal of Moldova73(1), 44-74.

Samir, A. (2023a, June 2). 📚Overview of Cohesion: Communicational Cohesion. Linkedin.com. https://www.linkedin.com/pulse/communicational-cohesion-types-ofcohesion-ahmed-samir-ahmed/

Samir, A. (2023b, June 5). Temporal cohesion — types of cohesion. Linkedin.com. https://www.linkedin.com/pulse/temporal-cohesion-types-ahmed-samir-ahmed/

Software engineering. (2018, July 30). GeeksforGeeks. https://www.geeksforgeeks.org/software-engineering-coupling-and-cohesion/


Posted

in

by