MASA Framework - DDD Design (2)

Clean Architecture

There are many translations of Clean Architecture in China, clean / neat / clear. But either one illustrates its simplicity and clarity.

In the early days it looked like this

CleanArchitecture.jpg

Students who see this picture may have an impression of another picture

Onion Architecture

onion architecture.png

It looks like this now

clean-architecture.jpg

It looks like they are relatives, but they are indeed inextricably related.

Analyze Clean Architecture

This part is mainly organized according to the understanding of the explicit architecture article, and there are translations and their own understanding and digestion. Please correct me if there are any mistakes, thank you

Three Building Blocks

  • User Interface
  • infrastructure
  • Application core

clean-architecture-1.png

control flow

  1. User Interface
  2. Application core
  3. infrastructure
  4. Application core
  5. User Interface

clean-architecture-2.png

tool

There is a sharp contrast between the left and right, with different motivations

  • HTTP/CLI: tell the application what to do
  • SMS/Mailing Server/Search Engine...: Apps tell them what to do

clean-architecture-3.png

Link tools and delivery mechanisms to the application core

The unit of code that connects the tool to the core of the application is called an adapter (port and adapter architecture).

The adapter that tells our application to do something is called the master or active adapter, and the adapter that our application tells us to do is called the slave or passive adapter.

port

These adapters are designed to accommodate a very specific entry point to the application core, the port. A port is nothing but a specification of how a tool can use the application core or how the application core can use it.

You can think of as interfaces and DTOs

Primary or Active Adapter

The primary or active adapter surrounds a port and uses it to tell the application core what to do.

Our active adapters are Controllers or Console Commands which inject in their constructor some object whose class implements the interface (port) required by Controller or Console Commands.

The port can be a service interface or a repository interface required by the controller, and then the concrete implementation of Service, Repository or Query is injected and used in the Controller.

Alternatively, the port can be an interface to the Command Bus or Query Bus. In this case, the concrete implementation of Command Bus or Query Bus is injected into the Controller, which then constructs the Command or Query and passes it to the relevant Bus.

Note: CQRS is actually mentioned here

clean-architecture-4.png

slave or passive adapter

Unlike active adapters that wrap around ports, slave adapters implement a port, an interface, and inject the application core wherever the port is needed.

It can be understood that the right side is the interface or object that meets the needs of the application core, and the left side is the communication mechanism for packaging use cases, such as HTTP/CLI, etc.

clean-architecture-5.png

Suppose we have a requirement that needs to persist data:

  1. We create a persistence interface (around the left port) with a method to save the data and a method to delete the data by ID
  2. An implementation class is provided in the infrastructure, and this interface and the corresponding implementation class are injected through IoC
  3. Inject a persistence interface in the constructor of the class that needs to persist data
  4. If one day we need to switch from SQL Server to MongoDb, we just need to replace the implementation class in step 2 and inject a new implementation class

IoC

Compared with the above figure, there is only one more blue arrow inserted directly into the application core from the outside. In the above example, it is mentioned that the role of IoC will not be repeated here.

So far, we have been explaining the periphery of the application core, and the application core is the focus of our architecture design.

clean-architecture-6.png

Application Core Organization

The onion architecture takes DDD layers and incorporates them into the port and adapter architecture. These layers are designed to bring some organization to the business logic, i.e. inside the port and adapter "hexagon", as in ports and adapters, the dependency direction is towards the center.

application layer

A Use Case is a process (business logic) triggered by one or more user interfaces in our application. The user interface can be a terminal user interface or an administrative interface, or a console interface and API.

Use cases are defined at the application layer and provided by DDD and onion architecture. It can include ports, ORM interfaces, search engine interfaces, message interfaces, etc. It can also be where CQRS handles Handlers, sends emails, and calls third-party APIs.

The application service/Command Handler contains the business logic of the use case, which is used to:

  1. Find one or more entities using Repository
  2. tell these entities to do some domain logic
  3. Persist these entities using Repository, saving data changes

Command Handler can be used in two different ways:

  1. Contains the real business logic that executes the use case
  2. As a middleware in the architecture, receive Command and trigger logic in the application service

clean-architecture-7.png

Domain layer

In addition to the properties of the object itself, the objects in the domain can also operate the properties inside the object, which is specific to the domain itself and independent of the business process that triggers the logic. They are independent and do not know the application layer at all.

clean-architecture-8.png

Domain Services

Sometimes we come across some domain logic involving different entities, same or not, that domain logic does not belong to the entity itself, it has no direct responsibility.

Then we can use domain services to carry this part of the logic. Some people may think that it can be placed in the application layer, but the domain logic cannot be reused in other use cases. Domain logic should be inside the domain, not up to the application layer.

Domain services can use other domain services, or other domain objects

domain model

At the very center, dependent on anything outside of it, is the domain model, which contains business objects that represent something in the domain. As for how to define the domain model, please refer to the first article.

components

Components intersect all layers within the application core, from outside to inside. Such as authentication, authorization, billing, users, comments, or accounts, but they are still realm-related.

Bounded contexts like authorization and authentication should be seen as external tools hidden behind some kind of port.

clean-architecture-9.png

Decoupled Components

Having fully decoupled components means that one component has no direct knowledge of any other component. In other words, it probably doesn't have an interface, so we need some new architectural constructs.

Such as events, eventual consistency, service discovery, etc. As you go down this path, you start to break away from the monolith.

Dapr may be a good choice here. It includes these functions. If you are interested in Dapr, you can read the previous tutorials to teach you how to learn Dapr.

MASA FrameworkSolutions

Combining the features of DDD, Clean Architecture and MASA Framework, we will define specifications in the form of interfaces in MASA.BuildingBlocks and implement the interfaces in MASA.Contrib.

This means that you can write your code by only caring about the interface definition in BuildingBlocks, or you can adjust or extend the default behavior we provide based on the interface re-implementation in DDD landing your own business features. For example, if you have your own UoW, storage layer, etc., you can change it at will.

application layer

Application service:

Implement the use cases of the application, connecting the presentation layer (interface layer) and the domain layer

In addition, based on the CQRS architecture demonstration of MASA.EShop.Services.Catalog in the MASA EShop example, the application layer can also host the Command Hanlder of CQRS. In addition to continuing to use the domain layer to solve the Command business, you can also choose to stop here, simplify the architecture in the Command Handler and directly process the Command.

Example code: https://github.com/masalabs/MASA.EShop/tree/develop/src/Services/MASA.EShop.Services.Catalog/Application/CatalogBrands

work unit:

The default event is opened for the first time in the application service, so UoW will also be activated at the application layer (in fact, the bottom layer will be activated automatically according to the operation of the warehouse, only the first addition, deletion and modification will be automatically activated, this function can be turned off and changed to manual control)

Middleware:

For development using Event Bus, the application layer can also be used as a unified AOP entry and exit.

For example, unified event parameter validation:

First you need to enable the unified validation middleware https://github.com/masalabs/MASA.EShop/blob/develop/src/Services/MASA.EShop.Services.Catalog/Application/Middleware/ValidatorMiddleware.cs

Then write the validation logic for the corresponding Event/Command https://github.com/masalabs/MASA.EShop/blob/develop/src/Services/MASA.EShop.Services.Catalog/Application/Catalogs/Commands/DeleteProductCommandValidator.cs

Domain layer

The concepts of entities, aggregations, and value objects will not be introduced. You can refer to the content of the previous chapter.

Anemia model vs congestion model

In the domain, the business logic in the domain needs to be limited, and with the support of EF Core for the hyperemia model, the hyperemia model is more suitable for the development of the domain model.

Encapsulate data and behaviors to show the complete behavior of real business objects. Each field has a clear division of responsibilities, and the logic is dispersed into field objects. This is also an obvious difference between the application layer and the domain layer.

For entity-related objects, we provide corresponding classes, as well as enumeration classes that may be needed for auditing and value objects.

Enumeration classes: We provide Enumeration, referenced from: https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types

entities.png

Domain Services:

Domain services can call other domain services (including intra-process or cross-process), so we provide IDomainService, and its functions include:

  • Automatically coordinate event delivery within and across processes
  • Support callee is CQRS
  • By default, it supports event stacking, which is triggered uniformly after UoW ​​Commit. It also supports sending events in real time (for example, subsequent business can be downgraded, but the main business logic of cross-process events cannot be downgraded)
  • Cross-process events support eventual consistency and Saga

domain-service.png

Warehousing:

The repository defined in the domain is an interface, representing the business concerned in the current domain. For example, users have different definitions for IRepository<User> in user management and business cards. But in the infrastructure, BaseRepository<User> can be the same, because BaseRepository<User> can be the most complete implementation, but only a part of it is recognized by the repository service in the domain

repositories.png

infrastructure layer

Provide an implementation for the interface, such as the implementation of the warehouse interface, the implementation of MQ or mediator in Event Bus (MASA Framework has been implemented, so only the implementation of the warehouse interface is currently in our example), etc.

MASA Framework Template Architecture

The free combination is provided in the MASA Framework template, and you can adjust it according to your needs, such as whether to include Blazor, Dapr, DDD, CQRS, etc.

Our MASA.EShop recommends 4 architectures, from simple to complex, this article introduces the most complex one

Minimal APIS + CQRS + Dapr actor

ddd-layers.png

The Ordering service in MASA.EShop adopts this architecture layering. In fact, there are also layering explanations above, but the previous explanation is from the perspective of MASA BuildingBlocks, and the next step will be from the perspective of developers.

  • User Interface Layer: It is responsible for providing the user interface and complete front-end logic. A user can also be a computer system, not specifically a person. So here can be either API, or Blazor, MVC, etc.

  • Application Layer: It can be thin or thick (thin is recommended under current layering). Responsible for coordinating User Interface and Domain, including service orchestration and forwarding, AOP, sending events, etc.

    If you have a Domain Layer, you can make the Command very thin and call Domainin. If you want to simplify CQRS, you can also do application services directly at this layer without Domain. Of course, the same is true for Query, but even if Query uses Domain, it is recommended to put the query in the application service, so that the Query and Command can be separated to gain the advantages of CQRS.

  • Domain Layer: The business core, including the interface of domain objects and domain services and adapters. It is recommended to adopt the congestion model to keep the behavior in the domain, and the domain services that are cross-domain and need to be reused can be used. The warehousing interface limits the warehousing behavior in the field. Unlike physical warehousing, it focuses more on the business itself, rather than the complete warehousing capacity of the entity.

  • Infrastructure Layer: Provides implementation for interfaces, such as the implementation of warehouse interface, the implementation of MQ or intermediary in Event Bus (MASA Framework has been implemented, so only the implementation of warehouse interface is currently in our example), etc.

Summarize

So far, we have not only implemented support for the monolithic architecture, but also provided support for the microservice architecture through Event Bus.

If you are interested in DDD or MASA Framework, you may wish to run MASA.EShop and have a look. It provides four reference architectures, which can meet the architecture requirements of most business scenarios.

Apply what you have learned, there is no end to learning.

refer to:

DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together:https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/

open source address

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks

MASA.Contrib:https://github.com/masastack/MASA.Contrib

MASA.Utils:https://github.com/masastack/MASA.Utils

MASA.EShop :https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

Gitee address: MASA.Blazor: BlazorComponent/MASA.Blazor

If you are interested in our MASA Framework, whether it is code contribution, use, issue, please contact us

16373211753064.png

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324158861&siteId=291194637