Use cases represent the core business logic of our application. They act as
orchestrators, coordinating the interactions between different parts of the
system to accomplish specific business goals. Each use case corresponds to a
specific action or operation that a user can perform within our application.
Purpose
Use cases serve several important purposes in our architecture:1
Business Logic Encapsulation
• They encapsulate the business rules and workflows of our application
2
Orchestration
• They coordinate interactions between different domain entities and
infrastructure services
3
Independence
• They keep the business logic separate from infrastructure concerns like
HTTP, databases, or external services
4
Reusability
• They can be called from different controllers or even from other use cases
Implementation
1
Structure
Use cases follow a consistent structure:• Single Responsibility: Each use case performs one specific action• Explicit Dependencies: All dependencies are injected through the constructor• Single Entry Point: Each use case exposes a single
execute method• Domain-Oriented: They work with domain entities, not DTOs or other external representations2
Example
Key Principles
1
Input and Output
• Input: Use cases accept domain entities as input, not DTOs• Output: Use cases return domain entities or specific result objects, not DTOs• Transformation: Any transformation between DTOs and domain entities should happen in controllers or dedicated mappersThis approach makes use cases more reusable and prevents them from being coupled to specific API contracts.
2
Error Handling
• Use cases should throw domain-specific errors that represent business rule violations• These errors should be descriptive and provide enough context to understand the issue• The presentation layer is responsible for translating these errors into appropriate HTTP responses
3
Dependency Inversion
• Use cases should depend on interfaces, not concrete implementations• This makes them easier to test and less coupled to specific infrastructure choices• All dependencies should be explicitly declared in the constructor
4
No Side Effects
• Use cases should avoid side effects that aren’t part of their core responsibility• Any side effects (like sending emails or notifications) should be handled through events or dedicated services• This keeps use cases focused and easier to test
5
Composability
• Complex workflows can be composed of multiple use cases.• Smaller, focused use cases are easier to test and maintain.• Use cases can call other use cases when needed.
Best Practices
1
Keep Use Cases Small and Focused
• Each use case should do one thing well
2
Validate Inputs Early
• Check that inputs are valid before performing operations
3
Use Descriptive Names
• Names should clearly indicate what the use case does
4
Document Public APIs
• Document the inputs, outputs, and possible errors of each use case
5
Write Thorough Tests
• Test happy paths, error cases, and edge cases
6
Don't Mix Concerns
• Keep business logic separate from infrastructure concerns
7
Domain First
• Let domain rules guide the implementation, not infrastructure or frameworks
Organization
Use cases are organized by domain entities or functional areas:This organization makes it easier to find related use cases and understand the system’s capabilities.
Testing
Use cases are tested through unit tests that mock all dependencies. We’ll
determine later if we want to do integration tests on use cases.