class ReservationService {

  public function calculateTotal()
  {
      return $this->pricingService
          ->applySeasonModifier()
          ->applyDiscountRules()
          ->applyChannelCommission()
          ->applyTaxes()
          ->buildInvoice();
  }

}

// Domain rules evolve
// architecture decisions matter
// complexity grows over time

Back to Comparison

A02 — Repository Pattern

Service and Repository layers separate controllers from data access

Pattern: Service + Repository

Philosophy: Invert dependencies, keep controllers thin, abstract data access.

Description

A02 introduces a service layer and repository pattern. Controllers delegate to services, services contain business logic, and repositories abstract data access. This creates clear separation of concerns and improves testability.

Strengths:

  • Controllers remain thin (30 lines) across all phases
  • Dependency inversion through interfaces
  • Services are easier to test with mock repositories
  • Clear separation between infrastructure and logic
  • Good balance between structure and pragmatism

Weaknesses:

  • All complexity migrates to 'God Service' (172 lines)
  • Service still coupled to business logic implementation details
  • No reduction in algorithmic complexity
  • Adding new pricing rules still requires modifying the service
  • Service layer can become a catch-all for logic

Evolution Across Phases

Phase Files Lines of Code Controller (lines) Service Layer (lines)
Phase 01 10 269 29 72
Phase 02 10 407 30 120
Phase 03 10 503 30 143
Phase 04 10 587 30 172

God Service Pattern: Controller stays thin (30 lines) but service grew to 172 lines handling all pricing logic. Repository Pattern decouples data access but doesn't reduce algorithmic complexity.

Key Metrics

Total Files

10

Stable across phases

Total Lines of Code

587

+118% growth P01→P04

Controller Size (Phase 04)

30 lines

+1 line from Phase 01

Testability Score

Medium

Services testable with mocks

Conclusion

Repository Pattern solves the wrong problem.

While it decouples data access (good!), it doesn't address the core issue: algorithmic complexity. All pricing logic still lives in one 'God Service' that handles every pricing scenario. Adding new rules still requires modifying the service and understanding its entire logic flow.

A02 is better than A01, but it's a tactical improvement that doesn't tackle the structural problem of growing domain complexity.

✓ When to Use A02

  • You need testability but domain logic is still relatively simple
  • Team benefits from clear separation of concerns
  • Stable domain with infrequent business rule changes
  • Good stepping stone between A01 and more complex patterns