2.2.9 · D2Design Principles

Visual walkthrough — Separation of concerns

2,101 words10 min readBack to topic

We build up in pictures. No formula appears before its picture. Let's go.


Step 1 — What is a "module"? Draw the box

WHAT: We draw a program as a set of boxes, each holding little dots — the elements (functions, variables) that live inside.

WHY start here: Every later idea — coupling, cohesion, separation — is measured between boxes or inside a box. So we must first agree on what a box is. You cannot count arrows before you have things to draw arrows between.

PICTURE: Below, one box M with four inner dots. The dashed edge is its interface. Nothing crosses it yet — this is the blank canvas.


Step 2 — What is a "concern"? Colour the dots

WHAT: We take the dots from Step 1 and colour them by why they'd be edited: coral = "storage changes", lavender = "business rule changes", mint = "screen layout changes".

WHY colour and not shape: Because the only thing SoC cares about is the reason to change. Colour makes that reason visible at a glance. Once dots are coloured, "separate the concerns" becomes a literal instruction: don't mix colours in one box.

PICTURE: The same box, now with a coral, a lavender, and a mint dot all crammed together. This is tangling — many colours in one room. Hold this image; it's the disease we're about to cure.


Step 3 — Draw the dependency arrows

WHAT: Between boxes we draw an arrow whenever one box uses another. Inside a single box we draw thin links between dots that cooperate (call or share data).

WHY arrows matter: An arrow is a path along which a change can travel. Change box ; the danger flows backwards along every arrow pointing at . So counting arrows = counting how far a change can spread. That count is exactly what we'll turn into a number next.

PICTURE: Three boxes. Box has arrows going out to two other boxes, and inside two dots are linked to each other.


Step 4 — Define Coupling: count the arrows leaving the box

WHAT: We simply count the arrows pointing out of to other boxes. In Step 3, reaches two boxes, so .

WHY this number and not, say, arrows in: We measure outward arrows because they are 's fragility to the outside world — every box leans on is a box that can break . We want to lean on as few things as possible, so a change out there can't reach in here. That's why the goal is LOW coupling: fewer arrows out = fewer ways to get hurt.

WHY not just "arrows are bad, delete them all": You can't — a program with zero arrows is a program where nothing talks to anything. Some coupling is necessary. SoC asks for the minimum that still gets the job done.

PICTURE: The box with its two outgoing arrows highlighted and a big "2" — literally counting them.


Step 5 — Define Cohesion: how tight are the dots inside?

WHAT: Inside one box, look at every pair of dots. The denominator is "how many pairs could there be". The numerator is "how many pairs are actually linked and share a concern (colour)". Divide.

WHY a ratio and not a raw count: A raw count of internal links would reward bigger boxes automatically. Dividing by possible pairs makes it fair — it asks what fraction of the box is genuinely one thing. A one-colour box where all dots cooperate scores near ; a rainbow box scores low because same-colour links are rare.

WHY we want it HIGH: High cohesion means the box is about one thing. When you open it, everything inside is there for the same reason — easy to understand, easy to change, easy to test. Goal: HIGH cohesion.

Worked count: Suppose has dots. Total possible pairs . If of those pairs are linked and same-colour, then .

PICTURE: Two boxes side by side. Left: rainbow dots, few links — low cohesion. Right: all-mint dots, richly linked — high cohesion. The fraction is written under each.


Step 6 — Why BOTH, together? The two cheats

WHAT: We plot the two cheats and the sweet spot on one map: coupling on one axis, cohesion on the other.

WHY plot them: It shows why you must move on both axes at once. Cheat A sits in the corner "low coupling, low cohesion". Cheat B sits in "high cohesion, high coupling". Neither is good. The target is the single corner: ==low coupling and high cohesion==.

HOW you actually reach it: Cut the program along the colour boundaries from Step 2. Same-colour dots go in the same box (cohesion up). Because same-colour code changes for the same reason, cross-box arrows become few (coupling down). One cut wins both.

PICTURE: A 2×2 map. Bottom-left = Cheat A. Top-right = Cheat B. Top-left (low coupling, high cohesion) = the SoC target, glowing.


Step 7 — Edge case: the concern that refuses to sit in one box

WHAT: We add a new colour, butter (logging), and find it sprinkled through every box. This is scattering — one concern smeared everywhere. It's the mirror image of tangling.

WHY it's a special case: Steps 4–6 assumed each colour could live in its own box. Logging breaks that assumption: it has to touch business code to log it. If we ignore this, our tidy separation quietly rots as butter dots re-infect every box.

HOW we still separate it: Pull the butter logic into one box and wrap the others with it (a decorator / middleware), so the butter colour physically lives in one place but runs across all. The business boxes stay pure colours.

PICTURE: Left — butter dots scattered in every box (bad). Right — one butter "wrapper" box surrounding the others, arrows showing it runs around them, business boxes now single-colour.


Step 8 — Degenerate case: when NOT to separate

WHAT: We take a tiny two-dot box where both dots are the same colour and always change together, then split it into two boxes anyway. Result: a new arrow appears (coupling ) and neither box is more focused.

WHY show the failure: The contract says cover every case — including the case where the principle shouldn't be applied. SoC is "cut along real seams". No colour change = no seam = don't cut. Adding ceremony to a 10-line script is the third common mistake from the parent note.

PICTURE: Before: one clean single-colour box, coupling 0. After: two boxes joined by a forced arrow, coupling 1, cohesion unchanged. A red "✗ don't" over the split.


The one-picture summary

WHAT it shows: the whole journey on one canvas — the tangled rainbow box (Step 2) on the left, an arrow labelled "cut along colours" pointing right, and the finished layered stack: one colour per box, few arrows between them (low coupling), tight links inside (high cohesion), with the cross-cutting butter wrapper hugging the side.

This single image is Separation of Concerns: one reason, one room.

Recall Feynman retelling — the whole walkthrough in plain words

Picture a program as a bunch of boxes holding coloured dots. The colour of a dot is the reason someone would edit it — red for "the database changed", purple for "the business rule changed", green for "the screen changed". At first every box is a messy rainbow (tangling): change one thing and you might smear paint on everything. So we measure two things. Coupling = how many other boxes a box reaches out to — count the outgoing arrows; we want that small, because every arrow is a path a bug can travel down. Cohesion = what fraction of the dots inside a box are the same colour and actually work together; we want that big, because then the box is truly about one thing. You can't fake it by cheating one number: one giant box has zero coupling but zero cohesion; a thousand tiny boxes look cohesive but drown in arrows. The trick that wins both at once is to cut the program along the colour lines — put same-coloured dots together. Some colours (like logging) insist on living everywhere; those we don't scatter, we pull into a single wrapper that hugs the others. And if two dots are always the same colour and always change together, we leave them alone — cutting there would only add a useless arrow. Do this and you get the final picture: neat single-colour boxes, few arrows between them, tight links inside. One reason, one room.


Connections

  • Parent: Separation of concerns · Hinglish: 2.2.09 Separation of concerns (Hinglish)
  • The "one colour per box" rule at the level of a class: Single Responsibility Principle
  • The two numbers we defined here: Coupling and Cohesion
  • Boxes stacked with one-way arrows: Layered Architecture
  • The butter-wrapper case: Cross-cutting concerns
  • Boxing code at all: Modularity, Information Hiding
  • Same colour ⇒ don't repeat it: Don't Repeat Yourself (DRY)
  • Over-splitting warning: fragmentation