Overview
Separation of concerns (SoC) means dividing a program into distinct parts, each addressing one concern: presentation, business rules, data access, communication, logging. Each part can be understood, changed, and tested with minimal knowledge of the others.
SoC is the parent of SRP (applied to classes) and of layered architectures (applied to systems). Typical LLD layers are controller or CLI (input/output), service (use cases), domain model (rules), and repository (persistence). Mixing them, for example SQL inside UI handlers, makes every change risky.
Reception handles check-in, doctors diagnose, the pharmacy dispenses, and billing charges. Each department has its own expertise; changing the billing system does not change how doctors diagnose.
When to use it
- Structuring any application or LLD solution.
- A single method mixes parsing input, rules, persistence, and output.
- Cross-cutting concerns (logging, auth, caching) are copied everywhere.
Where it shows up in interviews
Recognize it when: interviewer wants clean code structure.
- Design a library system
- Design a movie ticket booking service
Recognize it when: logging, auth, metrics in every method.
- Design a logging framework
- Design an API middleware pipeline
Where it is used in real software
Model-View-Controller separates data, presentation, and input handling in Rails, Spring MVC, and ASP.NET.
The web separates structure, style, and behavior.
Express middleware and Spring AOP apply logging, auth, and transactions separately from business code.
Key terms
- Concern
- A distinct aspect of functionality.
- Layer
- Group of components handling one concern level.
- Cross-cutting concern
- Needed by many components (logging, security).
- Aspect / middleware
- Mechanisms to apply cross-cutting concerns once.
How it works, step by step
- 1List the concerns
Input, validation, rules, persistence, notifications, logging.
- 2Assign each to a layer or component
Controller, service, domain, repository.
- 3Define interfaces between them
Services call repositories through interfaces.
- 4Move cross-cutting logic to decorators or middleware
Apply once.
- 5Check dependencies flow one way
UI -> service -> domain; infrastructure implements domain interfaces.
Layers in a booking service
POST /bookings
| Layer | Concern | Knows about |
|---|---|---|
| Controller | HTTP parsing, status codes | Service |
| Service | Use case: book seat, charge, notify | Domain, repository and notifier interfaces |
| Domain | Rules: seat availability, holds | Nothing external |
| Repository | SQL and mapping | Domain types |
| Middleware | Auth, logging, metrics | Request context |
NOWLayer: Controller | Concern: HTTP parsing, status codes | Knows about: Service
Changing from REST to a CLI touches only the controller; changing databases touches only the repository.
Implementation
// Controller: HTTP onlyapp.post("/bookings", async (req, res) => { try { const booking = await bookingService.book(req.body.showId, req.body.seat, req.user.id); res.status(201).json(booking); } catch (e) { res.status(e instanceof SeatUnavailable ? 409 : 500).json({ error: (e as Error).message }); }}); // Service: use case orchestrationclass BookingService { constructor(private shows: ShowRepository, private notifier: Notifier) {} async book(showId: string, seat: string, userId: string) { const show = await this.shows.get(showId); const booking = show.reserve(seat, userId); // domain rule await this.shows.save(show); // persistence await this.notifier.bookingConfirmed(booking); // notification return booking; }}Complexity and performance
Controller, service, domain, repository.
One layer at a time.
Trade-offs
Layers add files and mapping; tiny scripts do not need them.
Pushing all logic into services leaves domain objects as data bags; keep rules in the domain.
Variants and related techniques
Separate by feature first, then by layer within each slice.
Core domain separated from adapters on all sides.
Common mistakes
- Business rules in controllers.
Fix: Controllers translate I/O; rules belong in the domain or service.
- Repositories returning HTTP DTOs.
Fix: Each layer uses its own types or domain types.
Interview questions
How does SoC differ from SRP?
SoC is the general idea of dividing a system by concern at any level (layers, modules, languages). SRP applies it specifically to classes: one reason to change.
How would you handle logging across many services?
As a cross-cutting concern using decorators, middleware, or AOP, with structured logging configured centrally, rather than hand-written log calls mixed into every business method.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Layer a monolithic 'handle request' function | Easy | Split concerns. |
| Add auth and metrics as middleware | Medium | Cross-cutting concerns. |