Cohesion measures how strongly related and focused the responsibilities within a module (class, function, or package) are. High cohesion means the module does one thing well; low cohesion means it does many unrelated things.

Core Concept

Cohesion answers the question: “How well do the parts of this module belong together?”

  • High Cohesion: Elements work together toward a single, well-defined purpose
  • Low Cohesion: Elements are loosely related or unrelated, serving multiple purposes

Why Cohesion Matters

Understandability

High cohesion makes code easier to understand:

  • One focused responsibility per module
  • Clear purpose and boundaries
  • Predictable behavior

Maintainability

Changes are localized and less risky:

  • Related functionality grouped together
  • Modifications affect one focused area
  • Fewer unexpected side effects

Reusability

Focused modules are more reusable:

  • Single purpose means fewer dependencies
  • Clear interface with minimal assumptions
  • Can be extracted and used elsewhere

Levels of Cohesion

From lowest (worst) to highest (best):

1. Coincidental Cohesion (Worst)

Elements grouped arbitrarily with no meaningful relationship:

// BAD: Random unrelated methods
public class Utilities
{
    public void SendEmail(string to, string body) { }
    public decimal CalculateTax(decimal amount) { }
    public void LogMessage(string message) { }
    public string FormatDate(DateTime date) { }
}

2. Logical Cohesion

Elements perform similar operations but on different types of data:

// BAD: Grouped by similarity, not purpose
public class InputHandler
{
    public void Handle(string type, object data)
    {
        switch (type)
        {
            case "file": HandleFile((string)data); break;
            case "network": HandleNetwork((Stream)data); break;
            case "user": HandleUser((UserInput)data); break;
        }
    }
}

3. Temporal Cohesion

Elements grouped because they execute at the same time:

// BAD: Grouped by "when" not "what"
public class Startup
{
    public void Initialize()
    {
        ConnectDatabase();
        LoadConfiguration();
        StartWebServer();
        InitializeLogging();
    }
}

4. Procedural Cohesion

Elements grouped because they follow a sequence:

// MEDIOCRE: Better than temporal, but still procedural
public class OrderProcessor
{
    public void ProcessOrder()
    {
        ValidateOrder();
        CalculateTotal();
        ChargeCustomer();
        UpdateInventory();
        SendConfirmation();
    }
}

5. Communicational Cohesion

Elements operate on the same data:

// GOOD: Operates on same data
public class CustomerReport
{
    private Customer _customer;
 
    public string GetName() => _customer.Name;
    public string GetAddress() => _customer.Address;
    public decimal GetTotalPurchases() => _customer.CalculateTotal();
}

6. Sequential Cohesion

Output of one element is input to the next:

// GOOD: Clear data flow
public class TextProcessor
{
    public string Process(string input)
    {
        string trimmed = Trim(input);
        string normalized = Normalize(trimmed);
        string validated = Validate(normalized);
        return validated;
    }
}

7. Functional Cohesion (Best)

All elements contribute to a single, well-defined task:

// EXCELLENT: Single focused responsibility
public class EmailValidator
{
    public bool IsValid(string email)
    {
        return HasAtSign(email)
            && HasDomain(email)
            && HasValidFormat(email);
    }
 
    private bool HasAtSign(string email) => email.Contains("@");
    private bool HasDomain(string email) => email.Split('@')[1].Contains(".");
    private bool HasValidFormat(string email) => /* validation logic */;
}

Achieving High Cohesion

Single Responsibility Principle

Single Responsibility Principle directly addresses cohesion:

// BAD: Multiple responsibilities (low cohesion)
public class UserService
{
    public void CreateUser(User user) { }
    public void SendWelcomeEmail(User user) { }
    public void GenerateReport(DateTime start, DateTime end) { }
    public void CleanupOldRecords() { }
}
 
// GOOD: Single responsibility per class (high cohesion)
public class UserRepository
{
    public void CreateUser(User user) { }
    public User GetUser(int id) { }
}
 
public class EmailService
{
    public void SendWelcomeEmail(User user) { }
}
 
public class ReportGenerator
{
    public Report GenerateUserReport(DateTime start, DateTime end) { }
}

Feature-Based Organization

Group by feature, not by technical layer:

// BAD: Low cohesion - organized by type
/Controllers/UserController.cs
/Controllers/OrderController.cs
/Services/UserService.cs
/Services/OrderService.cs
/Models/User.cs
/Models/Order.cs
 
// GOOD: High cohesion - organized by feature
/Users/UserController.cs
/Users/UserService.cs
/Users/User.cs
/Orders/OrderController.cs
/Orders/OrderService.cs
/Orders/Order.cs

Cohesion Order Refactoring

Cohesion Order technique from tidyings:

// BEFORE: Low cohesion - scattered responsibilities
public class ShoppingCart
{
    public void AddItem(Item item) { }
    public void CalculateShipping() { }
    public void AddDiscount(Discount d) { }
    public void CalculateTax() { }
    public void RemoveItem(Item item) { }
    public decimal GetTotal() { }
}
 
// AFTER: High cohesion - grouped by concern
public class ShoppingCart
{
    // Item management
    public void AddItem(Item item) { }
    public void RemoveItem(Item item) { }
 
    // Price calculations
    public void CalculateTax() { }
    public void CalculateShipping() { }
    public void AddDiscount(Discount d) { }
    public decimal GetTotal() { }
}
 
// EVEN BETTER: Extract separate responsibilities
public class ShoppingCart
{
    private CartItems _items;
    private PriceCalculator _pricing;
 
    public void AddItem(Item item) => _items.Add(item);
    public void RemoveItem(Item item) => _items.Remove(item);
    public decimal GetTotal() => _pricing.Calculate(_items);
}

Measuring Cohesion

LCOM (Lack of Cohesion of Methods)

Measures how many method pairs don’t share instance variables:

// High LCOM (low cohesion)
public class BadClass
{
    private int _fieldA;
    private int _fieldB;
 
    public void Method1() { _fieldA++; }  // Uses only fieldA
    public void Method2() { _fieldB++; }  // Uses only fieldB
    // Methods don't share data - low cohesion!
}
 
// Low LCOM (high cohesion)
public class GoodClass
{
    private int _fieldA;
    private int _fieldB;
 
    public void Method1() { _fieldA++; _fieldB++; }
    public void Method2() { _fieldA--; _fieldB--; }
    // Methods share data - high cohesion!
}

Code Smell Indicators

Signs of low cohesion:

  • Large classes: Too many responsibilities
  • Long methods: Doing too many things
  • Feature envy: Methods using other classes’ data more than their own
  • Shotgun surgery: Changes require modifications across many methods

Cohesion vs Coupling

Cohesion and coupling work together:

AspectHigh CohesionLow Coupling
FocusInternal to moduleBetween modules
GoalRelated elements togetherIndependent modules
ResultEasy to understandEasy to change

The Sweet Spot: High cohesion within modules, low coupling between modules

// IDEAL: High cohesion + Low coupling
public class Order
{
    private OrderItems _items;
    private OrderPricing _pricing;
 
    // High internal cohesion - all about order processing
    public void AddItem(Item item) => _items.Add(item);
    public decimal CalculateTotal() => _pricing.Calculate(_items);
}
 
// Low coupling - Order doesn't know about payment processing
public class PaymentProcessor
{
    public void ProcessPayment(Order order, PaymentMethod method)
    {
        decimal amount = order.CalculateTotal();
        // Process payment
    }
}

Common Pitfalls

God Classes

Classes that do everything (extremely low cohesion):

// BAD: God class
public class Application
{
    public void Start() { }
    public void HandleUserInput() { }
    public void ProcessData() { }
    public void RenderUI() { }
    public void ManageDatabase() { }
    public void SendEmails() { }
    // Hundreds of methods...
}

Utility Classes

Collections of unrelated helper methods:

// BAD: Low cohesion utility class
public static class Utils
{
    public static string FormatDate(DateTime d) { }
    public static void Log(string msg) { }
    public static int CalculateAge(DateTime birth) { }
    public static void SendEmail(string to) { }
}

Better approach - create focused classes:

public class DateFormatter { }
public class Logger { }
public class AgeCalculator { }
public class EmailSender { }

Package-Level Cohesion

Cohesion principles also apply at the package/component level. Robert C. Martin defines three Package Cohesion Principles:

Reuse-Release Equivalence Principle (REP)

“The granule of reuse is the granule of release.”

If classes are reused together, they should be versioned and released together. This ensures users can depend on stable, trackable versions.

Common Reuse Principle (CRP)

“The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.”

Group classes that are typically used together. Don’t force users to depend on classes they don’t need—this creates unnecessary coupling.

Common Closure Principle (CCP)

“The classes in a component should be closed together against the same kinds of changes.”

This is the Single Responsibility Principle applied to packages. Classes that change for the same reasons should be in the same package, minimizing the impact of changes.

The Tension Diagram

These three principles create competing forces:

  • REP and CCP are inclusive (make packages larger)
  • CRP is exclusive (makes packages smaller)

Early in development, favor CCP (developability). As systems mature and are reused, shift toward REP and CRP.

See Package Principles for detailed coverage including the tension diagram.

Resources

See Also