Separation of Concerns
A design principle that says each part of a system should handle one job, and different jobs should be handled by different parts.
What is it?
Separation of concerns (often abbreviated SoC) is one of the oldest and most important ideas in software design. The computer scientist Edsger Dijkstra introduced the term in 1974, but the idea is far older — it’s essentially “divide and conquer” applied to complexity.
A concern is any distinct piece of functionality or responsibility. In a web application, displaying information to the user is one concern, processing business rules is another, and storing data is a third. Separation of concerns says these jobs should be handled by different, independent parts of the system, not tangled together in one big lump.
When concerns are properly separated, you can change how something looks without affecting how data is stored. You can swap out a database without rewriting the user interface. You can test one piece in isolation because it doesn’t depend on the internals of another piece. Each part becomes simpler to understand, easier to modify, and safer to hand to a different developer (or AI assistant) to work on.
When concerns are not separated, the system becomes fragile. Change one thing, and something seemingly unrelated breaks. This is the software equivalent of pulling one thread and watching the whole sweater unravel.
In plain terms
Separation of concerns is like a well-run kitchen. The person chopping vegetables doesn’t also manage the cash register. The dishwasher doesn’t decide what’s on the menu. Everyone has one clear job, and the kitchen runs smoothly because nobody steps on anyone else’s toes.
At a glance
How separation of concerns works in a web app (click to expand)
graph LR UI[Presentation Layer] -->|user actions| BL[Business Logic Layer] BL -->|queries| DA[Data Access Layer] DA -->|raw data| BL BL -->|processed results| UI style UI fill:#e8b84b,color:#fff style BL fill:#4a9ede,color:#fff style DA fill:#5cb85c,color:#fffKey: Each layer handles exactly one concern. The Presentation Layer (gold) manages what the user sees and clicks. The Business Logic Layer (blue) enforces rules and processes data. The Data Access Layer (green) reads and writes to the database. Each layer only talks to its immediate neighbour — the presentation never reaches directly into the database.
How does it work?
Separation of concerns shows up at every level of software, from the smallest code file to the largest system design. Here are the most common levels.
1. Language-level separation
The most visible example: how web pages are built.
| Technology | Concern | What it handles |
|---|---|---|
| HTML | Structure | What’s on the page (headings, paragraphs, buttons) |
| CSS | Presentation | How it looks (colours, spacing, fonts) |
| JavaScript | Behaviour | What happens when you interact (clicks, animations, data fetching) |
Each technology handles one aspect of the same page. You can completely redesign how a page looks (CSS) without touching what it contains (HTML) or how it behaves (JavaScript).
Think of it like...
A theatre production. The script (HTML) defines what’s said. The set design (CSS) defines how the stage looks. The director (JavaScript) decides what happens when — cues, lighting changes, curtain calls. Change the set design and the script stays the same.
2. Application-level separation
At a larger scale, entire layers of the application handle different concerns:
- Frontend — everything the user sees and interacts with
- Backend — business logic, validation, data processing
- Database — persistent storage and retrieval of data
- API — the contract between frontend and backend
Each layer can be developed and tested independently. A frontend developer doesn’t need to know how the database is structured — they only need to know what the API returns.
Concept to explore
See contracts-and-interfaces for how the boundaries between layers are defined and enforced.
3. Component-level separation
Inside each layer, individual components have their own concerns. A user interface might have:
- A navigation component (handles moving between pages)
- A search component (handles filtering and finding)
- A card component (handles displaying a single item)
Each component manages its own state and rendering. The search component doesn’t need to know how the card component displays results — it just passes data down.
Concept to explore
See single-responsibility-principle for the code-level version of this idea: every function, class, or module should have one reason to change.
When separation breaks down
Violations of SoC are common and create real problems:
| Violation | What went wrong | Why it hurts |
|---|---|---|
| A UI component directly queries the database | Presentation mixed with data access | Can’t change the database without rewriting the UI |
| Business rules duplicated in frontend and backend | Same concern handled in two places | Rules drift apart; one side says “allowed”, the other says “denied” |
| CSS styles embedded inside JavaScript logic | Presentation mixed with behaviour | Designers can’t change the look without editing code logic |
| One function that validates input, processes data, AND saves to database | Three concerns in one place | Can’t test any single step in isolation |
Rule of thumb
If you describe what a piece of code does and you use the word “and” more than once, it probably handles too many concerns.
Why do we use it?
Key reasons
1. Maintainability. When each part has one job, finding and fixing problems is straightforward. You know exactly where to look when something breaks.
2. Independent development. Different people (or AI assistants) can work on different parts without stepping on each other. The frontend team doesn’t block the backend team.
3. Testability. A component with one concern can be tested in isolation. You don’t need a running database to test whether a button looks right.
4. Reusability. A well-separated component can be used in multiple places. A “card” component that only handles display can show products, articles, or user profiles — because it’s not tangled with product-specific logic.
When do we use it?
- When building any system with more than one responsibility (which is nearly every system)
- When multiple people will work on the same codebase
- When you need to change one aspect of the system (e.g., the design) without risking another (e.g., the data layer)
- When you want to test pieces independently without spinning up the entire application
- When planning how to organise files and folders in a new project
Rule of thumb
Separation of concerns isn’t a sometimes-principle — it applies at every scale, from how you organise a single file to how you design a distributed system.
How can I think about it?
The hospital
A hospital is built on separation of concerns.
- The emergency room handles urgent cases
- The pharmacy manages medication
- The radiology department takes and reads scans
- The billing office handles finances
Each department has specialised staff, equipment, and procedures. A radiologist doesn’t prescribe medicine; a pharmacist doesn’t read X-rays. When the hospital upgrades its billing software, the emergency room keeps running without interruption.
If one person had to do triage, dispense medication, read scans, AND process invoices, the hospital would collapse under the complexity.
The newspaper
A newspaper separates concerns across its staff.
- Reporters gather facts (data access)
- Editors decide what’s newsworthy and check accuracy (business logic)
- Layout designers decide how the page looks (presentation)
- Printers produce the physical paper (delivery / infrastructure)
A reporter doesn’t choose the headline font. A layout designer doesn’t verify facts. Each role focuses on one concern, and the newspaper works because information flows through defined handoffs between roles — like data flowing through layers in software.
Concepts to explore next
| Concept | What it covers | Status |
|---|---|---|
| single-responsibility-principle | The code-level version: one class/function, one reason to change | stub |
| layered-architecture | Organising an entire app into horizontal layers by concern | stub |
| contracts-and-interfaces | How separated parts agree on communication rules | complete |
| abstraction-layers | Hiding complexity behind simple interfaces | stub |
Some of these cards don't exist yet
They’ll be created as the knowledge system grows. A broken link is a placeholder for future learning, not an error.
Check your understanding
Test yourself (click to expand)
- Explain what “separation of concerns” means in your own words. Why is it considered a fundamental principle of software design?
- Name three different concerns in a typical web application and describe which layer or technology handles each one.
- Distinguish between language-level separation (HTML/CSS/JS) and application-level separation (frontend/backend/database). How are they related?
- Interpret this scenario: a developer changes a button’s colour in a CSS file, and the application’s login system stops working. What violation of SoC likely caused this?
- Connect separation of concerns to contracts-and-interfaces. How do contracts help enforce separation between parts?
Where this concept fits
Position in the knowledge graph
graph TD SD[Software Development] --> SA[Software Architecture] SA --> SoC[Separation of Concerns] SA --> ABS[Abstraction Layers] SA --> CI[Contracts and Interfaces] SA --> CSM[Client-Server Model] SoC --> SRP[Single Responsibility Principle] SoC --> LA[Layered Architecture] style SoC fill:#4a9ede,color:#fffRelated concepts:
- contracts-and-interfaces — contracts enforce the boundaries that separation creates; they define how separated parts communicate
- abstraction-layers — a mechanism for achieving separation vertically, hiding each layer’s complexity from the one above
- frontend and backend — the most common example of application-level separation in web development
Further reading
Resources
- Separation of Concerns (Embedded Artistry) — Concise definition with practical examples
- Separation of Concerns: The Cornerstone of Modern Software Development (Nordic APIs) — Thorough exploration of SoC with API design perspective
- Separation of Concerns (SoC) in Software Engineering (SW Engineer’s Notes) — Technical walkthrough with code examples
- Software Design Principles That Matter (Franco Fernando) — SoC in the context of other key principles like dependency injection
- Seeing the Problem: An Introduction to Separation of Concerns (dev.to) — From “code that works” to “code that’s structured”