Separation of Concerns
debt(d7/e7/b7/t5)
Closest to 'only careful code review' (d7). Deptrac can enforce layer boundaries if configured, but SoC violations are fundamentally conceptual — phpstan won't flag a 100-line controller mixing concerns. Detection relies on code review.
Closest to 'cross-cutting refactor across the codebase' (e7). Untangling business logic from controllers, models, and templates typically requires extracting services, repositories, and view layers across many files — far beyond a parameterised fix.
Closest to 'strong gravitational pull' (b7). Applies across web/cli/queue contexts and shapes every layer decision; once concerns are tangled, every future change is constrained by the existing entanglement.
Closest to 'notable trap most devs eventually learn' (t5). Per the misconception, developers equate SoC with file/class separation rather than conceptual boundaries — a common and documented misunderstanding, but not catastrophically counterintuitive.
Also Known As
TL;DR
Explanation
Separation of Concerns (SoC) is a design principle advocating that a module, class, or function should address a single, well-bounded concern. Mixing concerns — e.g., SQL queries inside HTML templates, or business rules inside database models — produces code that is hard to test, reuse, and change in isolation. SoC underpins MVC architecture, layered architectures, and microservices. In PHP, enforcing SoC means keeping template rendering, business logic, and data access in separate layers with well-defined interfaces between them.
Common Misconception
Why It Matters
Common Mistakes
- Controllers that contain business logic, database queries, and HTML generation.
- Models that send emails, dispatch HTTP requests, or format output.
- Business logic in database stored procedures — makes it invisible to application-level tests.
- Not having a clear mental model of which layer owns which concern before writing code.
Code Examples
// Controller doing DB queries, business logic, AND formatting
class ProductController {
public function show(int $id): string {
$row = $this->db->query('SELECT * FROM products WHERE id = ?', [$id]);
$price = $row['price'] * (1 - $row['discount']);
return "<h1>{$row['name']}</h1><p>£{$price}</p>";
}
}
// Controller: HTTP only
class ProductController {
public function show(int $id): JsonResponse {
return response()->json($this->productService->getDetails($id));
}
}
// Service: business logic
// Repository: data access
// View/Resource: formatting