--- slug: separation-of-concerns type: pattern summary: "Organizing a system so each part addresses exactly one reason to change, keeping unrelated concerns from tangling together." created: 2026-04-04 updated: 2026-04-18 related: abstraction: relation: enabled-by note: "You separate concerns by abstracting them behind boundaries." architecture: relation: refined-by note: "Architecture decides which separations matter most." big-ball-of-mud: relation: violated-by note: "Concerns are scattered instead of isolated." boundary: relation: implemented-by note: "These are the structural mechanisms for separating concerns." code-smell: relation: detects note: "Concern violations produce many common smells." cohesion: relation: measured-by note: "A well-separated concern is a cohesive module." component: relation: implemented-by note: "These are the structural mechanisms for separating concerns." conways-law: relation: enabled-by note: "Team separation produces concern separation in the code." god-object: relation: violated-by note: "A god object packs unrelated reasons to change into one object." coupling: relation: reduces note: "Separated concerns are loosely coupled by design." decomposition: relation: applied-by note: "Decomposing a system along concern boundaries." kiss: relation: enables note: "Simplicity requires putting things in the right place, not just reducing volume." local-reasoning: relation: enables note: "Separated concerns let you reason about one domain at a time." module: relation: implemented-by note: "These are the structural mechanisms for separating concerns." monolith: relation: improves note: "Internal structure keeps a monolith healthy." --- # Separation of Concerns > **Pattern** > > A named solution to a recurring problem. > "Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one's subject matter in isolation for the sake of its own consistency." > — Edsger W. Dijkstra ## Context Any non-trivial system has multiple reasons to change: the business rules evolve, the user interface gets redesigned, the database is replaced, the deployment strategy shifts. **Separation of concerns** is the principle of organizing a system so that each part addresses one of these reasons, and only one. It operates at the **architectural** scale and is one of the oldest principles in software design. The idea is simple. The discipline of applying it consistently isn't. ## Problem How do you keep a system changeable when different aspects of it evolve at different rates, for different reasons, driven by different people? ## Forces - Mixing concerns in the same [module](module.md) means a change to one concern risks breaking another. - Separating concerns too aggressively creates indirection and fragmentation. The code for a single feature ends up scattered across many files. - Some concerns are hard to separate cleanly (logging, error handling, and security tend to cut across everything). - Different stakeholders care about different concerns and should be able to work without stepping on each other. ## Solution Identify the distinct reasons your system might change. Business logic is one concern. Presentation is another. Data persistence, authentication, error handling, configuration — each is a concern. Organize your code so that each concern lives in its own [module](module.md) or [component](component.md), behind its own [boundary](boundary.md). The classic example is the Model-View-Controller pattern: the model handles business logic, the view handles presentation, and the controller handles input. Each can change independently. But separation of concerns isn't limited to MVC. It applies at every level, from splitting a function that does two things into two functions, to splitting a monolith into services. The test is simple: when a requirement changes, how many places do you need to edit? If a change to the pricing logic requires touching the database schema, the API handlers, and the email templates, those concerns are not separated. If it requires editing only the pricing module, they are. In agentic coding, separation of concerns determines how precisely you can scope an agent's work. "Update the pricing logic" is a clear instruction when pricing lives in one place. It's a dangerous instruction when pricing is entangled with half the codebase. The agent either misses changes or makes ones it shouldn't. ## How It Plays Out A web application mixes HTML generation, database queries, and business rules in the same functions. Every change is a risky, time-consuming affair. The team gradually refactors: business rules move into a domain layer, database access into a repository layer, and HTML into templates. Changes get smaller, safer, and faster. An AI agent is tasked with updating the email notification format. In a system with separated concerns, the agent edits the email templates and the formatting logic — nothing else. In a tangled system, the agent finds that email content is generated inline within the order processing code, mixed with business logic and database calls. The agent either touches too much or too little. > **💡 Tip** > > When you notice a pull request touching many unrelated files for a single logical change, that is a smell: concerns are not well separated. Use that signal to guide refactoring priorities. > **💡 Example Prompt** > > "Move the email content generation out of the order processing code. Put the email templates and formatting logic in their own module. The order processor should call a send_notification function, not build HTML." ## Consequences Separation of concerns makes systems easier to understand (each piece has one job), easier to change (changes are localized), and easier to test (you can test each concern in isolation). It supports team autonomy, since different concerns can be owned by different people or agents. The cost is structural overhead. Separate concerns need explicit [interfaces](interface.md) between them. Cross-cutting concerns (like logging or authorization) don't fit neatly into any one box and require special patterns. Over-separation can be as harmful as under-separation: if you split every concern into its own file in its own directory, working with the codebase becomes a scavenger hunt. ## Sources - Edsger W. Dijkstra coined the term "separation of concerns" in his 1974 note *[On the Role of Scientific Thought](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html)* (EWD447), calling it "the only available technique for effective ordering of one's thoughts." The epigraph quote is from the same document. - David Parnas laid the practical groundwork in *[On the Criteria To Be Used in Decomposing Systems into Modules](https://dl.acm.org/doi/10.1145/361598.361623)* (1972), arguing that modules should be organized around design decisions they hide rather than processing steps they perform. His information-hiding principle is separation of concerns made concrete. - Trygve Reenskaug created the [Model-View-Controller pattern](https://folk.universitetetioslo.no/trygver/themes/mvc/mvc-index.html) at Xerox PARC in 1979, giving separation of concerns its most widely recognized architectural expression. The original MVC reports described splitting user-facing applications into model, view, and controller — each addressing a distinct concern. --- - [Next: Monolith](monolith.md) - [Previous: Composition](composition.md)