Clean Architecture
debt(d5/e7/b7/t5)
Closest to 'specialist tool catches it' (d5). The detection_hints list deptrac, phpstan, and psalm — specialist static analysis tools that can enforce dependency rules and flag violations like domain entities importing ORM namespaces or use cases importing HTTP objects. These are not default linters and require deliberate configuration of layer boundaries.
Closest to 'cross-cutting refactor across the codebase' (e7). The common_mistakes describe deeply structural problems — Eloquent-extending domain entities, HTTP objects inside use cases, controllers bypassing the application layer. The quick_fix states the dependency rule must be enforced, but correcting entrenched violations requires untangling framework coupling from domain logic across many classes and files throughout the codebase, which is a cross-cutting architectural refactor.
Closest to 'strong gravitational pull' (b7). Clean Architecture applies to web, cli, and queue-worker contexts (the full applies_to scope) and is tagged as architecture-level. Every new feature, every new class, every new layer addition must respect the dependency rule. It shapes how controllers, use cases, repositories, and entities are written system-wide, imposing a persistent design constraint on all future maintainers.
Closest to 'notable trap' (t5). The misconception field explicitly states the canonical wrong belief: developers believe Clean Architecture requires a specific folder structure, when the substance is dependency direction. This is a documented and widely encountered gotcha — developers who follow a 'Clean Architecture folder template' without enforcing the dependency rule think they are compliant but are not. It is a notable trap most developers encounter, not a catastrophic one.
Also Known As
TL;DR
Explanation
Clean Architecture (Robert C. Martin) defines concentric layers: at the centre, Entities (business rules); then Use Cases (application logic); then Interface Adapters (controllers, presenters, gateways); then Frameworks and Drivers (web, DB, UI). The Dependency Rule states that dependencies must point inward — outer layers depend on inner layers, never the reverse. The domain and use case logic knows nothing about HTTP, databases, or frameworks. This makes the core testable without any infrastructure and enables replacing frameworks or databases without touching business logic.
Diagram
flowchart TD
subgraph Frameworks
WEB[Web / HTTP]
DB2[Database]
end
subgraph Adapters
CTRL[Controllers]
REPO[Repositories]
end
subgraph UseCases
UC[Application Use Cases]
end
subgraph Entities
ENT[Domain Entities]
end
WEB --> CTRL --> UC --> ENT
style ENT fill:#6e40c9,color:#fff
style UC fill:#238636,color:#fff
style CTRL fill:#1f6feb,color:#fff
style WEB fill:#d29922,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Domain entities that extend Eloquent models — the domain is now coupled to the ORM.
- Use case classes that import HTTP request objects — business logic should not know the delivery mechanism.
- Skipping the application layer and calling repositories directly from controllers.
- Applying Clean Architecture to simple CRUD apps — the overhead is rarely justified without complex domain logic.
Code Examples
// Domain entity coupled to Eloquent — violates dependency rule:
class Order extends Model { // Depends on ORM — infrastructure leaks into domain
protected $fillable = ['user_id', 'total', 'status'];
public function isPaid(): bool { return $this->status === 'paid'; }
}
// Dependency rule: outer layers depend on inner layers, never the reverse
// 1. Entity (innermost — pure PHP, zero deps)
class Order { public function place(Cart $cart): void { ... } }
// 2. Use Case
class PlaceOrderUseCase {
public function __construct(private OrderRepository $repo) {}
public function execute(PlaceOrderRequest $req): OrderResponse { ... }
}
// 3. Interface Adapter (controller, presenter)
class OrderController {
public function store(Request $req): JsonResponse {
$response = $this->useCase->execute(PlaceOrderRequest::fromHttp($req));
return response()->json($response->toArray());
}
}
// 4. Framework/DB (outermost) — implements interfaces from inner layers
class EloquentOrderRepository implements OrderRepository { ... }