common

Best practices for structuring backend project Architectures

There are several popular architectures for structuring backend projects. Here are a few:

  • Layered (n-tier) architecture
  • Hexagonal architecture (Ports and Adapters)
  • Domain-Driven Design (DDD)
  • Microservices architecture
  • Clean Architecture
  • Event-Driven Architecture
  • Package by feature
  • Package by type 
  1. Layered (n-tier) architecture:

    This is the most common architecture, where the project is divided into layers such as presentation, business, and data access layers. Each layer has specific responsibilities and communicates with the layers directly above or below it.

    Here's a basic example of how you might structure a project using a Layered (n-tier) architecture:

    - ProjectName
      - PresentationLayer
        - Controllers
        - Views
        - DTOs
      - BusinessLayer
        - Services
        - Models
        - Interfaces
      - DataAccessLayer
        - Repositories
        - DatabaseContext
      - Tests
        - UnitTests
        - IntegrationTests

     

    In this structure:

    • PresentationLayer contains all the code related to the user interface and user interaction. This includes controllers, views, and Data Transfer Objects (DTOs) if you're using them.

    • BusinessLayer contains the business logic of your application. This includes services, models, and interfaces.

    • DataAccessLayer contains all the code related to data storage. This includes repositories and the database context.

    • Tests contains all the unit and integration tests for your application.

    This is a simplified example. The exact structure can vary based on the needs of your project.

     

  2. Hexagonal architecture (Ports and Adapters):

This architecture aims to create loosely coupled application components. The core application (business logic) is surrounded by several adapters (ports) that connect the application to necessary services like databases, UI, and so on.

- ProjectName
  - Application
    - Ports
      - Inbound
      - Outbound
    - Services
  - Domain
    - Entities
    - ValueObjects
    - Repositories
  - Infrastructure
    - Adapters
      - Inbound
        - Controllers
        - Presenters
      - Outbound
        - Repositories
    - Configuration
  - Tests
    - UnitTests
    - IntegrationTests

In this structure:

  • Application contains the application services and the ports. Ports are interfaces that define the expected inputs (Inbound) and outputs (Outbound) for the application.

  • Domain contains all the business logic and business rules. This includes entities, value objects, and repository interfaces.

  • Infrastructure contains all the implementation details that the application should not be concerned with. This includes the adapters (concrete implementations of your ports), and any configuration code.

  • Tests contains all the unit and integration tests for your application.

This is a simplified example. The exact structure can vary based on the needs of your project.

3. Domain-Driven Design (DDD):

DDD focuses on the core domain and domain logic. It's based on the interactions between business domain objects (entities, value objects, aggregates, etc.) and is particularly useful for complex systems.

- ProjectName
  - Application
    - Commands
    - Queries
    - ApplicationServices
  - Domain
    - Entities
    - ValueObjects
    - Aggregates
    - Repositories
    - DomainServices
    - Events
  - Infrastructure
    - Persistence
      - Repositories
      - DbContext
    - Messaging
    - Configuration
  - Presentation
    - Controllers
    - Views
    - DTOs
  - Tests
    - UnitTests
    - IntegrationTests

In this structure:

  • Application contains the application services, commands, and queries. These are the entry points to your domain logic.

  • Domain contains all the business logic and business rules. This includes entities, value objects, aggregates, repository interfaces, domain services, and domain events.

  • Infrastructure contains all the implementation details that the application should not be concerned with. This includes the persistence layer (like repositories and database context), messaging, and any configuration code.

  • Presentation contains all the code related to the user interface and user interaction. This includes controllers, views, and Data Transfer Objects (DTOs) if you're using them.

  • Tests contains all the unit and integration tests for your application.

This is a simplified example. The exact structure can vary based on the needs of your project.

4 Microservices architecture:

This architecture structures an application as a collection of loosely coupled services. Each service is a small, independent application that can be developed, deployed, and scaled independently.

- ProjectName
  - Service1
    - Application
    - Domain
    - Infrastructure
    - Dockerfile
  - Service2
    - Application
    - Domain
    - Infrastructure
    - Dockerfile
  - Service3
    - Application
    - Domain
    - Infrastructure
    - Dockerfile
  - Shared
    - CommonLibraries
  - DockerCompose

 

5 Serverless architecture:

In this architecture, the application is built and run in stateless compute containers that are event-triggered and fully managed by a third party (a cloud provider).

6 Clean Architecture:

This architecture emphasizes the separation of concerns, making the system more flexible, maintainable, and testable. It separates software elements into independent, interchangeable layers (entities, use cases, interface adapters, and frameworks).

- ProjectName
  - Entities
  - UseCases
    - Interactors
    - Ports
      - InputPorts
      - OutputPorts
  - Controllers
  - Presenters
  - FrameworksAndDrivers
    - Web
    - Database
  - Tests
    - UnitTests
    - IntegrationTests

In this structure:

  • Entities contains the business objects of the application.

  • UseCases contains the business rules of the application. This includes Interactors (classes that implement the use cases) and Ports (interfaces used by the Interactors).

  • Controllers are part of the input adapters. They translate requests from the web into calls to the use cases.

  • Presenters are part of the output adapters. They format the data from the use cases for the web.

  • FrameworksAndDrivers contains all the details about the web framework, database, etc. These are the details that the application should not depend on.

  • Tests contains all the unit and integration tests for your application.

This is a simplified example. The exact structure can vary based on the needs of your project.

 

7. Event-Driven Architecture

  • Description: This architecture revolves around the detection and handling of events. Systems are designed to detect and react to events, which are typically messages from other parts of the application.
  • Benefits: Highly adaptable, scalable, and good for systems where asynchronous communication is a priority.
  • Challenges: Complex debugging and testing, designing effective error handling can be challenging.
ProjectName
  - Services
    - Service1
      - Events
        - IncomingEvents
        - OutgoingEvents
      - Handlers
      - Models
      - Repositories
    - Service2
      ...
  - EventBus
    - Handlers
    - Interfaces
  - SharedKernel
    - CommonEvents
    - Utilities
  - APIGateway
  - ExternalIntegrations
    - Integration1
      - Adapters
      - Clients
    - Integration2
      ...
  - Database
    - Migrations
    - Models
    - Repositories
  - Tests
    - UnitTests
    - IntegrationTests
    - EventFlowTests

Components Description

Services: Individual microservices or modules, each handling its own area of business logic.

  • Events: Subcategories for incoming and outgoing events.
  • Handlers: Event handlers that respond to incoming events and initiate business logic.
  • Models: Domain models used within the service.
  • Repositories: For interacting with the database.

EventBus: A component for routing events between services.

  • Handlers: Handlers for routing events.
  • Interfaces: Interfaces for services to interact with the event bus.

SharedKernel: Common code that can be used across different services.

  • CommonEvents: Definitions of events common to multiple services.
  • Utilities: Helper utilities and tools.

APIGateway: The entry point of the system, managing incoming requests and routing them to the appropriate services.

ExternalIntegrations: Integrations with external systems and services.

  • Adapters: Adapters for converting data between formats.
  • Clients: Clients for interacting with external APIs.

Database: Layers for database interaction.

  • Migrations: Database migrations.
  • Models: Data models.
  • Repositories: Repositories for data access.

Tests: Testing layers, including unit tests, integration tests, and event flow tests.

This structure provides a clear separation of components, facilitating scalability and modifications in the system. It also supports the asynchronous and distributed nature of EDA, where event processing is a key element.

 

8 Package by feature (Пакетирование по функциям).
Вертикальное разделение кода, тестов и конфигов

Similar to "Microservices architecture", but in monolith. 

project-name/
├── src/
│   ├── Http/
│   │   └── Controller/
│   ├── Auth/
│   │   ├── Command/
│   │   ├── Entity/
│   │   ├── Query/
│   │   ├── Test/
│   │   └── Config/
│   ├── Blog/
│   │   ├── Command/
│   │   ├── Entity/
│   │   ├── Query/
│   │   ├── Test/
│   │   └── Config/
│   ├── Shop/
│   │   ├── Command/
│   │   ├── Entity/
│   │   ├── Query/
│   │   ├── Test/
│   │   └── Config/
│   └── Mailer/
│       ├── Command/
│       ├── Entity/
│       ├── Query/
│       ├── Test/
│       └── Config/
└── tests/
    └── Functional/

 

9 Package by type (Пакетирование по типам)

При этом подходе код организуется по типам или областям ответственности, таким как модели, контроллеры, репозитории и т.д. Классы одного типа группируются вместе, независимо от их функциональной принадлежности.

Пример структуры проекта на PHP с пакетированием по типам:

src/
    Models/
        User.php
        Post.php
        Invoice.php
        ...
    Controllers/
        AuthController.php
        BlogController.php
        PaymentController.php
        ...
    Services/
        AuthService.php
        BlogService.php
        PaymentService.php
        ...
    Repositories/
        UserRepository.php
        PostRepository.php
        InvoiceRepository.php
        ...
tests/
    Models/
        UserTest.php
        PostTest.php
        InvoiceTest.php
        ...
    Controllers/
        AuthControllerTest.php
        BlogControllerTest.php
        PaymentControllerTest.php
        ...
    Services/
        AuthServiceTest.php
        BlogServiceTest.php
        PaymentServiceTest.php
        ...
    Repositories/
        UserRepositoryTest.php
        PostRepositoryTest.php
        InvoiceRepositoryTest.php
        ...

В этом примере код разделен на пакеты Models, Controllers, Services и Repositories. Классы одного типа (модели, контроллеры и т.д.) объединены вместе, независимо от их функциональной принадлежности.

 

 

Sources:

 

Афоризм дня:
Мы потому клеймим ложь наибольшим позором, что из всех дурных поступков этот легче всего скрыть и проще всего совершить. (523)

Leave a reply

Яндекс.Метрика