application-layer
Application Layer & CQRS Patterns for PHP
Service Layer = Application Layer
In DDD terminology, the Service Layer is interchangeable with the Application Layer. A service (also called a handler, operation, action, or interactor) represents one business use case: it orchestrates and coordinates work, controls the transaction, and manages side effects. It does not make business decisions — it is a workflow, not a business rule. The actual decisions live in the domain (rich objects, policies, or a table module). See service-layer.md for the full definition, benefits, the overuse anti-pattern, and how it sits above the domain-modeling spectrum. A Command/Handler here is the in-process expression of a use case; the distribution-patterns skill covers exposing that same use case remotely as a coarse-grained Remote Facade.
When to Use a Service Layer (and the Anti-Pattern to Avoid)
Use a Service Layer whenever more than one delivery channel (HTTP, CLI, queue) needs the same orchestration, or when you want a clear, testable entry point per use case. But do not overuse it: the common failure is Controller → Service → Repository → Entity where the entity is anemic and the service holds all the logic. That is a Transaction Script wearing extra indirection — the fault is an anemic domain, not the pattern. Push business rules down into the domain; keep the service as pure orchestration.
When to Use CQRS (and When NOT to)
CQRS separates read and write models, but adds complexity. Use CQRS only when a bounded context has genuinely divergent read/write workloads. Skip CQRS for simple CRUD, interfaces without complex reads, or early-stage projects where premature separation slows delivery.
| Use CQRS For | Use Simple Controller/Repository For |
|---|---|
| Bounded contexts with divergent read/write workloads | Simple CRUD, single operation per endpoint |
| A read model with 10+ projections or dedicated reporting | Single or few read paths |
| Scaling reads and writes independently | Uniform access patterns |
Most systems do not need CQRS. Start with simple controllers and repositories. Introduce CQRS only when a specific read path has become a clear performance or organizational bottleneck.