Mastering Code Quality: A Deep Dive into Cohesion and Coupling in Python

ArjanCodes////4 min read

Overview

Software design often feels like a balancing act between making things work and making them sustainable. Two critical metrics for measuring this balance are Cohesion and Coupling. Cohesion refers to how closely the responsibilities within a single class or function relate to one another. High cohesion implies a focused, single-purpose unit. Coupling, conversely, measures the degree of interdependence between different modules. While some interaction is necessary, high coupling creates a fragile "house of cards" where a single change can trigger cascading failures across the system. This tutorial refactors a disorganized vehicle registration system into a robust, modular architecture by applying these principles.

Prerequisites

To follow this guide, you should have a solid grasp of Python fundamentals, particularly Object-Oriented Programming (OOP). You should be familiar with defining classes, using self, and understanding basic data structures like dictionaries. No advanced libraries are required, though a basic understanding of type hinting will help in reading the refactored code.

Key Libraries & Tools

  • Python Standard Library: The core logic uses standard Python features. Specifically, the math library is often cited as a gold standard for cohesion (e.g., the cos() function).
  • Type Hinting (typing): Used to define data structures clearly, making the code more readable and easier to debug.
  • GRASP Principles: The GRASP provide the conceptual framework, specifically the Information Expert pattern.

Code Walkthrough

The Problem: Low Cohesion and High Coupling

The initial code suffered from a "God Method" syndrome. The register_vehicle function was responsible for generating IDs, calculating prices, determining tax rates based on brand names, and printing results. It knew too much about the internal workings of other classes.

Step 1: Defining the Information Expert

According to Craig Larman, we should assign responsibility to the class that has the information necessary to fulfill it. We split the data into two distinct classes: VehicleInfo (for brand-level data) and Vehicle (for specific instances).

class VehicleInfo:
    def __init__(self, brand: str, electric: bool, catalog_price: int):
        self.brand = brand
        self.electric = electric
        self.catalog_price = catalog_price

class Vehicle:
    def __init__(self, id: str, license_plate: str, info: VehicleInfo):
        self.id = id
        self.license_plate = license_plate
        self.info = info

Step 2: Improving Cohesion through Focused Methods

We moved the tax calculation logic into VehicleInfo because that class owns the catalog_price and electric status. This is high cohesion: the class manages its own data logic.

def compute_tax(self) -> float:
    tax_percentage = 0.05
    if self.electric:
        tax_percentage = 0.02
    return tax_percentage * self.catalog_price

Step 3: Reducing Coupling in the Registry

Instead of the application logic manually stitching together IDs and licenses, we moved that into a VehicleRegistry. The main application now only needs to know about one method: create_vehicle.

class VehicleRegistry:
    def create_vehicle(self, brand: str) -> Vehicle:
        vehicle_id = self.generate_vehicle_id(12)
        license_plate = self.generate_vehicle_license(vehicle_id)
        brand_info = self.vehicle_info[brand]
        return Vehicle(vehicle_id, license_plate, brand_info)

Syntax Notes

This tutorial utilizes f-strings (string interpolation) for clean output formatting. It also relies heavily on Type Hinting, which doesn't change runtime behavior in Python but serves as critical documentation for the developer. By using self within the Vehicle class to call methods from the linked VehicleInfo object, we demonstrate composition, a key OOP pattern that favors flexibility over rigid inheritance.

Practical Examples

These principles apply whenever you face "spaghetti code." Real-world applications include:

  • E-commerce Systems: Separating Product (specs) from LineItem (quantity in a specific cart).
  • Game Development: Moving damage calculation into a Weapon class rather than the global Player controller.
  • API Clients: Ensuring a Request builder doesn't also handle the complex Response parsing logic.

Tips & Gotchas

  • The Zero-Coupling Myth: You can never achieve zero coupling; objects must interact. Aim for loose coupling where objects interact through stable interfaces rather than internal implementation details.
  • Naming is a Signal: If your function name contains the word "and" (e.g., calculate_and_print), it likely has low cohesion and should be split.
  • Avoid String Matching: Initially, tax was calculated by checking if a string was "Tesla." Refactoring this to a boolean electric attribute makes the system much easier to extend without modifying the logic for every new brand.
Topic DensityMention share of the most discussed topics · 8 mentions across 8 distinct topics
Cohesion
13%· concepts
Coupling
13%· concepts
Craig%20Larman
13%· people
Elon%20Musk
13%· people
Other topics
38%
End of Article
Source video
Mastering Code Quality: A Deep Dive into Cohesion and Coupling in Python

Cohesion and Coupling: Write BETTER PYTHON CODE Part 1

Watch

ArjanCodes // 26:14

On this channel, I post videos about programming and software design to help you take your coding skills to the next level. I'm an entrepreneur and a university lecturer in computer science, with more than 20 years of experience in software development and design. If you're a software developer and you want to improve your development skills, and learn more about programming in general, make sure to subscribe for helpful videos. I post a video here every Friday. If you have any suggestion for a topic you'd like me to cover, just leave a comment on any of my videos and I'll take it under consideration. Thanks for watching!

What they talk about
AI and Agentic Coding News
Who and what they mention most
Python
27.3%3
Python
18.2%2
Python
18.2%2
4 min read0%
4 min read