Skip to content

Design Patterns

Design patterns are proven solutions to recurring problems in software development. At Synapse Studios, we use specific patterns that align with our clean architecture principles and help us build maintainable, testable applications.

Why Patterns Matter

Patterns provide:

  • Common vocabulary - Teams can communicate complex ideas efficiently
  • Proven solutions - Avoid reinventing the wheel for solved problems
  • Consistent structure - Makes codebases more predictable and maintainable
  • Clear responsibilities - Each pattern has a specific purpose and boundary

Our Core Patterns

Use Cases

The heart of our business logic organization. Use cases orchestrate the flow of data to and from entities, and direct those entities to use their business rules to achieve the goals of the use case.

When to Use:

  • Implementing business workflows and processes
  • Coordinating multiple domain operations
  • Keeping business logic independent of frameworks

Key Benefits:

  • Single Responsibility Principle adherence
  • Framework independence
  • Excellent testability
  • Clear business intent

Application Service

The Domain-Driven Design equivalent of Use Cases. Application Services orchestrate domain operations with strict separation—they contain no business logic, only coordination.

When to Use:

  • Working in DDD contexts
  • Need strict "no business logic" discipline in orchestration layer
  • Building systems with bounded contexts

Key Benefits:

  • Clear separation between orchestration and domain logic
  • Aligns with DDD terminology and patterns
  • Forces domain logic into appropriate places

Note: At Synapse, we typically prefer Use Cases over Application Services for broader accessibility.

Domain Service

Encapsulates domain operations that don't naturally belong to entities or value objects. When business logic spans multiple aggregates or is fundamentally an activity rather than a thing, Domain Services provide a home for that behavior.

When to Use:

  • Logic spans multiple entities or aggregates
  • Operation is intrinsically an activity (verb, not noun)
  • Forcing logic into an entity would distort its purpose

Key Benefits:

  • Prevents domain logic from leaking into application layer
  • Keeps entity responsibilities focused
  • Maintains domain model integrity

Repository Pattern

Mediates between the domain and data mapping layers, providing a more object-oriented view of the persistence layer. Repositories encapsulate the logic needed to access data sources.

When to Use:

  • Abstracting database operations
  • Switching between different data sources
  • Testing business logic without a database
  • Implementing complex queries

Key Benefits:

  • Separation of concerns
  • Improved testability through mocking
  • Consistent data access interface
  • Database technology independence

Page Object Pattern

Encapsulates page structure and behaviors in acceptance tests, providing a clear API for test scenarios while hiding implementation details of the UI.

When to Use:

  • Writing end-to-end tests
  • Creating maintainable test suites
  • Reducing test brittleness
  • Sharing test utilities across scenarios

Key Benefits:

  • DRY principle in tests
  • Reduced maintenance when UI changes
  • Readable test scenarios
  • Reusable page interactions

Pattern Relationships

These patterns work together to create a cohesive architecture:

  1. Use Cases (or Application Services in DDD) call Repositories to fetch and persist data
  2. Use Cases may delegate complex business logic to Domain Services
  3. Domain Services contain business logic that doesn't fit in entities
  4. Page Objects interact with the UI that triggers Use Cases
  5. Repositories return domain entities that Use Cases orchestrate

Getting Started

  1. Start with Use Cases when implementing new features
  2. Add Repository abstractions for data access
  3. Implement Page Objects for acceptance tests

Further Reading

See how these patterns are implemented in practice:

  • NestJS Implementation
  • React Implementation
  • Testing Guidelines