DEV Community

Cover image for Coupling, Decoupling, and Cohesion
Rinon Tendrinomena
Rinon Tendrinomena

Posted on

Coupling, Decoupling, and Cohesion

In software development, especially when writing JavaScript, two big ideas help make your code easier to work with, change, and understand: cohesion and coupling.

Think of your code like building with toys or organizing a kitchen. These concepts decide whether your project feels smooth or turns into a big mess.

Cohesion – "Keep related things together"

Cohesion means how well the code inside one file, function, or module belongs together.

  • High cohesion = everything inside does one clear job
  • Low cohesion = it's a random mix of unrelated stuff

Analogy: Imagine your kitchen drawer.

Kitchen drawer to explain coupling and cohesion

A messy junk drawer (low cohesion) has spoons, batteries, tape, old receipts, and a phone charger all mixed up. Finding anything takes forever.

A well-organized drawer (high cohesion) has only cooking tools in one place, only cleaning stuff in another. Easy to find, easy to use.

JavaScript example – low cohesion (avoid this):

// utils.js – does everything (bad!)
function calculateTotal(price, tax) {
  return price + tax;
}

function sendEmail(to, message) {
  console.log(`Email sent to ${to}`);
}

function getUserAge(birthYear) {
  return new Date().getFullYear() - birthYear;
}

function saveToLocalStorage(key, value) {
  localStorage.setItem(key, value);
}
Enter fullscreen mode Exit fullscreen mode

This file does math, emailing, age calculation, and storage. Hard to understand, hard to test, hard to fix.

High cohesion (better):

// priceCalculator.js
export function calculateTotal(price, taxRate) {
  const tax = price * taxRate;
  return price + tax;
}

export function applyDiscount(total, percent) {
  return total * (1 - percent / 100);
}
Enter fullscreen mode Exit fullscreen mode

One file = one job (price math). Clean and focused.

Coupling – "How much do modules know about each other?"

Coupling measures how connected two pieces of code are. How much one part depends on the insides of another.

  • High / tight coupling = modules are glued together
  • Low / loose coupling = modules talk nicely but don't know too much about each other

Analogy: Lego bricks vs superglued blocks.

Lego bricks snap together easily and you can pull them apart to rebuild (low coupling).

If you put superglue between every brick, you can't change anything without breaking the whole thing (high coupling).

Another visual – good vs bad coupling:

Cohesion vs coupling

Left side (messy): everything connected to everything → hard to change.

Right side (clean): small groups connected only when needed → easy to work with.

JavaScript example – tight coupling (bad):

// userService.js
class UserService {
  getUser(id) {
    // Directly knows it's using localStorage (tight!)
    const data = localStorage.getItem(`user_${id}`);
    return JSON.parse(data);
  }

  saveUser(user) {
    localStorage.setItem(`user_${user.id}`, JSON.stringify(user));
  }
}
Enter fullscreen mode Exit fullscreen mode

This code is glued to localStorage. If you want to switch to a server or IndexedDB later, you have to change this file and every place that uses UserService.

Loose coupling (good) – using dependency injection:

// storage.js (interface-like)
export class LocalStorageService {
  get(key) { return JSON.parse(localStorage.getItem(key)); }
  set(key, value) { localStorage.setItem(key, JSON.stringify(value)); }
}

// userService.js
export class UserService {
  constructor(storageService) {
    this.storage = storageService;   // just uses the interface
  }

  getUser(id) {
    return this.storage.get(`user_${id}`);
  }

  saveUser(user) {
    this.storage.set(`user_${user.id}`, user);
  }
}

// Usage
const storage = new LocalStorageService();
const userService = new UserService(storage);
Enter fullscreen mode Exit fullscreen mode

Now UserService doesn't care how storage works. You can easily swap it for:

class ApiStorageService {
  async get(key) { /* fetch from API */ }
  async set(key, value) { /* send to API */ }
}
Enter fullscreen mode Exit fullscreen mode

This is decoupling – removing the strong glue between parts.

Decoupling – The Action of Making Coupling Loose

Decoupling means actively reducing how much modules depend on each other's details.

Common ways in JavaScript:

  • Use function parameters instead of global variables
  • Pass dependencies (dependency injection)
  • Use interfaces / simple objects instead of concrete classes
  • Events / callbacks instead of direct calls
  • Separate files by responsibility

Why Should You Care?

Good cohesion + low coupling = your code is like Lego:

  • Easy to understand (one file = one clear idea)
  • Easy to change (swap one piece without breaking others)
  • Easy to test (test small parts alone)
  • Easy for teams (different people work on different pieces)
  • Easy to grow (add new features without chaos)

Bad cohesion + high coupling = your code is like a house of cards made of superglue:

  • Tiny change breaks many places
  • Hard to test
  • New developers get scared
  • Bugs hide everywhere

Quick Rule to Remember

Aim for:

  • High cohesion inside each module (one job per file/function)
  • Low coupling between modules (talk through simple contracts, not internals)

Next time you write JavaScript, ask yourself:

"Does this function/file do one main thing?" → Cohesion

"Does it know too much about other parts?" → Coupling

Keep practicing these ideas – your future self (and teammates) will love you for it!

Top comments (0)