laracrafthub/ddd-template

A ready-to-use Laravel template designed for building web applications using DDD.


README

DDD-Template

DDD-Template is a ready-to-use Laravel template designed to facilitate the development of web applications using Domain-Driven Design principles. This template streamlines the process of building robust and scalable applications, ensuring a solid architectural foundation for your project.

✨ Key Features

  • Laravel Framework: Leveraging the power and simplicity of Laravel.

  • Domain-Driven Design: Incorporates DDD principles for effective complex domain modeling.

  • Scalability and Maintainability: Structured to support large-scale applications and ease of maintenance.

🧙 Who is This Template For?

This Domain-Driven Design (DDD) template for Laravel is designed for developers and teams who seek to:

  • Embrace Domain-Driven Design: Ideal for those looking to implement DDD principles in their Laravel projects, facilitating a deep connection between the software and the underlying business concepts.
  • Build Large and Complex Applications: Particularly beneficial for large-scale applications where separating business logic from application and infrastructure code is crucial for maintainability and scalability.
  • Improve Code Organization: Suitable for developers who aim to enhance code structure, making it more readable, maintainable, and easier to navigate.
  • Facilitate Team Collaboration: A great fit for teams that require a clear and consistent coding structure, enabling easier collaboration, especially in larger or distributed teams.
  • Focus on Business Logic: For developers who want to concentrate on implementing business rules and logic without being entangled in framework-specific details.
  • Ensure High-Quality Code: Beneficial for those who prioritize testing and want a structured approach to both unit and integration testing.
  • Adopt Advanced Laravel Practices: Suitable for experienced Laravel developers looking to adopt advanced practices and architectural patterns in their projects.

Whether you are a solo developer, part of a small team, or involved in a large enterprise project, this template offers a structured approach to implementing DDD in Laravel, aligning technical implementation with business requirements, and ensuring long-term project success and maintainability.

🧬 Project Structure

The project is organized into three primary layers, each residing in its own subfolder within the "app/" folder :

  1. Application Layer
    • Location: Application/
    • Purpose: This layer contains all the application logic and acts as a bridge between the domain and the infrastructure layers. It includes controllers, services, and other mechanisms that drive the application flow.
    • Contents: All content originally in Laravel's app/ directory has been moved here. Mainly should contain Framework-Specific Services: Services specific to Laravel, such as controllers, middleware, service providers, broadcast channels....
  2. Domain Layer
    • Location: Domain/
    • Purpose: Dedicated to housing all business logic and domain-specific code. This layer is framework-agnostic and focuses solely on business rules.
    • Contents:
      • Entities: Core classes that represent business objects and their inherent logic. These are typically rich models, containing both state and behavior related to the business domain.
      • Value Objects: Immutable objects that represent descriptive aspects of the domain with no conceptual identity (e.g., Money, DateRange, Address).
      • Aggregates: A cluster of domain objects that can be treated as a single unit. An aggregate will have one of its component objects be the aggregate root.
      • Domain Services: Stateless services that encapsulate domain logic that doesn’t naturally fit within an entity or value object.
      • Domain Events: Events that represent something significant happening in the domain. These are used to trigger side effects across different parts of the application in a loosely coupled manner.
      • Repositories Interfaces: Abstractions for how the domain layer retrieves data from the infrastructure layer, ensuring separation of concerns.
      • Factories: Classes or methods used for creating complex domain objects.
      • Specifications: Classes that encapsulate some business logic, typically used for validation or selection criteria.
      • Policies: Classes or methods representing business rules or decisions.
  3. Infrastructure Layer
    • Location:: Infrastructure/
    • Purpose:: Contains implementations of interfaces defined in the domain layer, such as repositories or external services. This layer interacts with the database and external systems.
    • Contents:
      • Repositories: Implementations of domain interfaces for data access, typically involving Eloquent models.
      • External Services Integration: Code for integrating external APIs and services.
      • Utilities and Helpers: Utility classes and helper functions that assist in infrastructure-related tasks.
      • Mail and Notification Services: Infrastructure for sending emails and notifications.
      • Queue Management: Implementation of job queues and workers.

🧪 Testing Structure

To ensure robustness and reliability, the template includes a comprehensive testing setup:

Unit Tests

Integration Tests

  • Location: tests/Integration/

  • Purpose: Tests the interaction between different parts of the application, ensuring they work together as expected.

  • Features:

    • Comprehensive Coverage: Ensures that modules, when integrated, function as intended and meet business requirements.
    • Database Interactions: Tests involving real database operations to verify data persistence, retrieval, and the integrity of database transactions.
    • Environment Simulation: Utilizes a test environment that closely resembles the production setup, including configurations, to ensure realistic testing conditions.
    • API Testing: Validation of RESTful APIs, ensuring endpoints behave as expected under various scenarios.
    • Middleware and Routing Tests: Ensures that HTTP requests are properly handled and routed, including the functioning of middleware.
    • Service Integration: Verifies that external services and APIs are correctly integrated and interact as expected within the application.
    • Performance Checks: Basic performance testing to identify potential bottlenecks when components are working together.
    • Error Handling: Testing the application’s response to incorrect inputs and unexpected scenarios to ensure robust error handling.

⚙️ Continuous Integration (CI) Setup

This template incorporates a robust Continuous Integration (CI) setup to ensure code quality, consistency, and reliability. The following CI jobs are configured:

  1. Laravel Pint (source)
    • Purpose: Automatically formats the code to adhere to Laravel's coding standards.
    • Action: Runs Laravel Pint to ensure all code follows the prescribed style guidelines.
  2. PHPStan (Application Code)
    • Purpose: Performs static analysis on the application code to detect potential errors and bugs.
    • Configuration: Targets the Application/, Domain/, Infrastructure/ folders with a specific PHPStan configuration to suit DDD requirements.
  3. PHPStan (Tests)
    • Purpose: Ensures the quality and reliability of the test code.
    • Configuration: Analyzes the tests/ folder with a distinct PHPStan configuration, tailored for testing scenarios.
  4. Rector (source)
    • Purpose: Automates code refactoring, ensuring modern and efficient code practices.
    • Action: Runs Rector to refactor codebases, enhancing code quality and maintainability.
  5. Unit Tests
    • Purpose: Validates the correctness of individual units of source code.
    • Action: Executes Unit Tests to ensure the integrity and functionality of small, isolated pieces of the application.
  6. Integration Tests (Parallel Execution)
    • Purpose: Tests the interaction between different layers and components of the application.
    • Configuration: Divided into three separate jobs, each focusing on a specific layer of DDD.
    • Parallel Execution: Utilizes "brianium/paratest" package to run tests in parallel, significantly speeding up the execution time of these typically slower tests.
  7. Renovate Dependency Management (source)
    • Purpose: Automatically manages project dependencies to ensure they are up-to-date and secure.
    • Functionality: Renovate periodically scans project dependencies and submits pull requests to update them. This includes both direct dependencies and transitive dependencies.
    • Benefits:
      • Automated Updates: Keeps dependencies updated without manual intervention, saving time and effort.
      • Security: Promptly updates dependencies with known vulnerabilities, enhancing the security of the application.
      • Customizable: Configurable to suit specific project needs, such as scheduling updates and defining versioning policies.
    • Consistency: Ensures consistent dependency versions across all development and production environments.
    • Integration: Although not a traditional CI job, Renovate integrates smoothly into the development workflow, complementing the other CI processes by keeping the codebase current and secure.

The CI setup plays a crucial role in maintaining high standards of code quality and ensuring that changes and additions to the codebase do not introduce regressions or break existing functionality. One of its most important roles is to assist us in adhering strictly to Domain-Driven Design (DDD) principles. This automated process aids in the early detection of deviations from these principles, ensuring that the development remains true to the core concepts of DDD. By doing so, it makes the development process more efficient, reliable, and aligned with the strategic goals of the project.

🚧 Challenges in Integrating DDD with Laravel

Eloquent ORM and Layer Separation

One of the notable challenges in integrating Domain-Driven Design (DDD) into the Laravel framework is the separation of the Domain layer from the Infrastructure layer, particularly when working with Eloquent ORM. Eloquent, as an Active Record implementation, tends to blur the lines between the domain and persistence layers. This section highlights the challenge and our approach to addressing it:

  • Eloquent's Active Record Pattern: Eloquent ORM follows the Active Record pattern, where model objects are directly tied to database tables. This pattern inherently couples business logic (Domain) with data persistence (Infrastructure), which can be at odds with the DDD principle of clear separation between domain logic and infrastructure concerns.

  • Approach and Compromises:

    • Selective Use of Eloquent: While Eloquent is a powerful and convenient ORM, we limit its usage to ensure it doesn't dominate the domain logic. In areas where Eloquent's tight coupling interferes with DDD principles, we opt for alternative approaches.
    • Repository Pattern: To mediate between Eloquent and the Domain layer, we implement the Repository pattern. Repositories interface with Eloquent models, allowing most of the domain layer to remain agnostic of the underlying ORM implementation.
    • Focused Domain Models: We strive to keep our domain models focused on business logic, delegating data persistence concerns to the infrastructure layer as much as possible.
    • Balancing DDD and Practicality: Recognizing the practical benefits of Eloquent in a Laravel context, we balance strict adherence to DDD with the pragmatic use of Laravel's features. This balance allows us to leverage Laravel's strengths while still maintaining a separation of concerns in line with DDD.
  • Continual Refinement: As the Laravel framework evolves, and as we gain more insights, we continuously refine our approach to better align with DDD principles without sacrificing the framework's benefits.

In our endeavor to maintain a clear separation between domain and infrastructure concerns, we have adopted a novel approach in handling Eloquent models:

  • Two-Class Strategy for Eloquent Models:

    • Domain Layer Class: In the Domain layer, each Eloquent model primarily encapsulates entity business logic. This class focuses on the business rules and behaviors that are core to the domain entities.
    • Infrastructure Layer Class: In the Infrastructure layer, a corresponding Eloquent model is defined to handle infrastructure-specific aspects. This includes defining relationships (belongsTo, hasMany, etc.), casts, fillable fields, and the usage of traits related to infrastructure concerns like database interactions.
    • Class Extension: The Domain layer class extends the Infrastructure layer class. This structure allows the domain model to inherit necessary database and ORM functionalities while keeping the business logic separate and focused. This way, the Domain model remains insulated from direct database operations, yet benefits from the infrastructure capabilities provided by Eloquent.
  • Rationale and Benefits:

    • Clear Separation of Concerns: This two-class strategy reinforces the separation of business logic (domain) from database and infrastructure concerns, adhering more closely to DDD principles.
    • Leveraging Eloquent's Strengths: While keeping the domain models focused on business rules, this approach still allows us to utilize the full power and convenience of Eloquent for database interactions and relationships.
    • Maintaining Flexibility: This setup provides the flexibility to evolve the domain logic independently of the infrastructure-related code, making the system more adaptable to changes in business requirements.

Through this innovative structuring of Eloquent models, we strike a balance between the rigorous application of DDD principles and the practical advantages offered by Laravel’s Eloquent ORM.

This challenge reflects a common tension in software architecture between ideal design principles and the practicalities of specific frameworks or tools. Our approach aims to strike a balance, ensuring that our use of Laravel and Eloquent serves our DDD objectives without overly compromising the design.

🧑‍💻 Local Development Tasks

This project includes a task file designed to streamline and simplify the execution of common development tasks. These tasks can be run locally, facilitating a more efficient development workflow. You can find here a description on the available tasks.

🤝 Contributing

Contributions to enhance this DDD template are welcome (see CONTRIBUTING for details). Please follow the standard GitHub pull request process to submit your changes.

📝 License ©

This project is licensed under the MIT License.