• No results found

All sufficiently complex enterprise applications consist of multiple layers. From a user’s perspective, the layers are abstracted away and they exist solely to assist the programmer in managing all the emergent complexity. Distinct layers imply that translation must happen between some of the layers for information to propagate. For example, in a typical enterprise use case, an entity is loaded from the database, operated upon, persisted back to the database and information regarding the operation is returned to the user client app through a service/application layer, perhaps via a REST Web API service. The entity is contained within the domain layer and should not be forced into areas it doesn’t belong, like in the presentation layer where a specific MVC view may require a user to enter

information in several steps (basket, buying process, etc.). For instance, the user can enter the order’s product item first, but the order might still have unspecified info about shipping or billing information.

119 Architecting and developing Docker applications If the client application was using the Domain Entity, that target entity could be in invalid state. That is not good. You need to have Always-valid entities (see the Validations in Domain-Driven Design section) controlled by Aggregate-Roots, so entities should not be bound to the client Views - this is what the ViewModel is for. The ViewModel is a building block of the presentation layer and the domain entity doesn’t belong there. Instead, an appropriate domain layer entity should be created based on data contained in the view model. This can be done directly or by passing a DTO to a service. When tackling complexity, it is important to have a Domain Model controlled by Aggregate- Roots and following Domain-Driven Design patterns.

A service designed based on DDD patterns will usually be composed by several internal layers. The following figure xx-xx shows how that design is implemented in the eShopOnContainers app.

A layer is simply a set of classes that you can group in a project folder, or you can also put each layer in a different class library. A layer is something logical, a group of classes; you don’t need to

implement it as a class library if you don’t want to. However, implementing each major layer as a library provides a better control of dependencies between each layer. For instance, the Domain-Model Layer should not take any dependency on any other layer (the Domain Model classes should be POCO

classes) as shown in figure x-xx below about the Ordering.Domain layer library which only has dependencies with the .NET Core libraries.

Figure X-XX. DDD Layers in the Ordering microservice from eShopOnContainers

120 Architecting and developing Docker applications Eric Evans's excellent book Domain Driven Design says the following about the Domain Model Layer and Application Layer.

“Domain Model Layer: Responsible for representing concepts of the business, information about the

business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software.”

The Domain Layer is where the business is expressed. When implementing a microservice’s Domain Model Layer in .NET, that layer would be coded as a class library with the domain entities that will capture data plus behavior (methods).

Following the Persistence Ignorance and the Infrastructure Ignorance principles, this layer must completely ignore the data persistence details. These persistence tasks should be performed by the infrastructure layer. Therefore, this layer should not take direct dependencies on the infrastructure, which means that an important rule should be that your Domain Model entity classes should be

POCO (Plain-Old CLR Objects). Domain Entities should not have any direct dependency with any data- access infrastructure framework like Entity Framework or NHibernate or any other data-access framework. Ideally, your Domain entities should not derive or implement any type defined in the infrastructure level.

Luckily, most modern ORM frameworks like Entity Framework Core allow this approach so your domain model classes are not coupled to the infrastructure. However, having POCO entities is not always possible when using certain NO-SQL persistence and frameworks like Actors and Reliable Collections in Azure Service Fabric. However it is a good goal, and certainly possible if using relational databases and Entity Framework Core.

You could, of course, also implement data access without an ORM, but that can require more custom code and a larger effort.

“Application Layer: Defines the jobs the software is supposed to do and directs the expressive domain

objects to work out problems. The tasks this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems. This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.”

When implementing a microservice’s Application Layer in .NET, that layer would be coded as an application project that varies depending on what you are building. For instance, a common application layer project type can be an ASP.NET Web API project which implements the

microservice’s interaction, remote network access and external Web APIs to be used from the UI or client apps. It includes queries if using a CQS approach, commands accepted by the microservice, and even the event-driven communication between microservices. However, the ASP.NET Web API must not contain business rules or domain knowledge (especially domain rules in regards to transactions or updates), which should be owned by the Domain Model class library.

The Application Layer (in this case an ASP.NET Web API project) must only coordinate tasks and must not hold or define any domain state (domain model), but it will delegate the business rules execution to be run by the domain model classes themselves (Aggregate Roots and Domain Entities), which will ultimately update the data within those domain entities.

121 Architecting and developing Docker applications Basically, the application logic is where you implement all use cases that depend on a given front end, implementation for instance related to Web API or specific interfaces/contracts for your services front- end. The domain logic placed in the domain layer, however, is invariant to use cases and entirely reusable across all flavors of presentation and application layers you might have, and it must not depend on any infrastructure framework.

Infrastructure Layer: How the data initially held in domain entities in-memory will be persisted in databases or any other persistent store is a different matter. It will be implemented in the

Infrastructure Layer, as when using Entity Framework Core code to implement the Repository pattern classes that use DBContext to persist data in a relational database.

In accordance with the previously mentioned Persistence Ignorance and the Infrastructure Ignorance

principles, the Infrastructure Layer must not contaminate the Domain-Model layer. You must keep the Domain-Model entity classes agnostic from the infrastructure that you use to persist data (EF or any other framework) by not taking hard dependencies on frameworks. Your Domain-Model layer class library should have only your domain code, just POCO entity classes implementing the heart of your software completely decoupled from invasive infrastructure technologies.

Thus, your layers or class libraries and projects should ultimately depend on your Domain Model layer/library, not vice versa, as shown in the figure X-XX.

That layer’s design should be independent per microservice, and as mentioned previously, you can implement your most complex microservices following DDD patterns, while implementing them in a much simpler way (simple CRUD in a single layer) for simpler data-driven microservices.

References – Persistence Ignorance principles

Persistence Ignorance principle http://deviq.com/persistence-ignorance/ Infrastructure Ignorance principle

https://ayende.com/blog/3137/infrastructure-ignorance

122 Architecting and developing Docker applications

Designing a microservice Domain-Model