For practitioners by practitioners

Domain-driven Design: A Practitioner's Guide

Layered architecture.

A layered architecture is a software design pattern that separates different concerns of a software system into different layers or components, with each layer providing a specific set of services to the layer above it. This separation of concerns helps to maintain the modularity and scalability of the system, as well as to reduce the complexity of the overall design.

In Domain-Driven Design (DDD), a layered architecture is often used to organize the solution domain into different parts. For example, it may consist of a presentation layer, an application layer, a domain layer, and an infrastructure layer. The presentation layer handles user interaction, the application layer implements the use cases and workflows, the domain layer represents the business rules and entities, and the infrastructure layer provides technical services such as persistence, messaging, and security.

Using a layered architecture in DDD helps to ensure that the different parts of the system are well-separated and that the interactions between them are clearly defined. This makes it easier to understand and maintain the system, as well as to extend it in the future as new requirements arise.

An example of a layered architecture can be a web application that consists of the following layers:

  • Presentation layer : This layer is responsible for presenting the user interface to the user. It includes components like controllers, views, and templates.
  • Application layer : This layer is responsible for implementing the use cases or business logic of the application. It includes components like services, use case controllers, and DTOs.
  • Domain layer : This layer is responsible for defining the business rules and domain objects of the application. It includes components like entities, value objects, and domain services.
  • Persistence layer : This layer is responsible for storing and retrieving the data from the database. It includes components like repositories, DAOs, and ORM frameworks.

The flow of data between the layers in a layered architecture is typically unidirectional, where each layer communicates only with the layer directly below or above it.

When to use

The layered architecture is a common architectural pattern that is appropriate in many situations. It is especially useful when building large, complex systems that need to be easily maintainable and scalable.

Some scenarios where a layered architecture can be appropriate include:

  • Large-scale enterprise applications that have many different modules or subsystems.
  • Applications that need to support multiple interfaces, such as web and mobile.
  • Applications that require a high degree of flexibility and modularity, where individual components can be easily swapped out or replaced.
  • Applications that require strict separation of concerns, with clear boundaries between different layers of the system.

In general, a layered architecture can be a good choice when you need to build a system that is easy to understand, maintain, and extend over time. It can help you to keep your code organized and ensure that each layer of the system has a clearly defined responsibility.

When to avoid

The layered architecture may not be appropriate in certain situations, including:

  • Small projects: For small projects with simple requirements, a layered architecture may introduce unnecessary complexity.
  • Projects with frequent changes: If a project requires frequent changes, a layered architecture may make it difficult to modify the application as changes to one layer may affect other layers.
  • Projects with changing requirements: If the requirements of a project are not well understood or are likely to change frequently, a layered architecture may not be the best approach as it can be difficult to modify the application to accommodate changing requirements.
  • Projects that require high performance: A layered architecture may introduce overhead in terms of processing time and memory usage, which can impact the performance of the application.
  • Projects with low complexity: For applications with low complexity, a layered architecture may be overkill and may not provide any significant benefits over a simpler architecture.

Comparison to the vertical slice architecture

The layered architecture and vertical slice architecture are both commonly used in software development, but they differ in their approach to structuring code.

The layered architecture is based on a strict separation of concerns, where each layer has a specific responsibility and communicates only with adjacent layers. Typically, the layers in a layered architecture include the presentation layer, application layer, domain layer, and data layer. This architecture is well-suited for large, complex systems where maintaining separation between components is important.

On the other hand, the vertical slice architecture focuses on organizing code around specific features or functions, with all layers represented in each vertical slice. In this architecture, each slice includes a presentation layer, application layer, domain layer, and data layer, all of which are focused on a specific feature or function. This architecture is well-suited for smaller, more focused systems, and for teams that prioritize rapid development and frequent deployment.

In general, the layered architecture is better suited for large, complex systems where maintainability and scalability are important, while the vertical slice architecture is better suited for smaller, more focused systems where rapid development and frequent deployment are important.

' src=

  • Already have a WordPress.com account? Log in now.
  • Subscribe Subscribed
  • Copy shortlink
  • Report this content
  • View post in Reader
  • Manage subscriptions
  • Collapse this bar

Software Alchemy

The Art and Science of Software Development

To ensure you get the best experience, this website uses cookies.

A Template for Clean Domain-Driven Design Architecture

  •   Posted in:
  • Foundational Concepts
  • Architecture
  • Design Patterns
  • Patterns and Practices
  • Domain-Driven Design
  • ASP.NET Core

Architectural Template

The purpose of this blog entry is to introduce an architectural template for building web applications which is based upon my interpretation of the Clean DDD and CQRS concepts that I introduced in the previous entry. The information I provide here is guidance only, and I don't claim this to be the definitive approach to building modern applications. It reflects my own personal software development biases and may or may not be suitable to your needs. Once again, I'm operating under the assumption that you fall into a certain category, namely a developer or team of developers working in a startupy-type environment, or a small team within a larger organization. You embrace Agile and lean startup practices, are flexible in your thinking, and focused on continuous improvement and development. Whatever the case, you should always do your homework as well.

To demonstrate this template, I've created a demo application which attempts to solve a (highly contrived) fictional problem for a fake organization. As indicated in the past few entries, you can find the source code to the demo solution here . Feel free to refer to the source code alongside the architectural guidelines I've outlined below.

In developing this template, I studied solutions and tutorials from a handful of experts. As always, I've linked to those resources at the bottom. The experts/resources that this architecture is based on are Jason Taylor, Julie Lerman, Steve Smith, Jimmy Bogard, Matthew Renze, Vladimir Khorikov, Greg Young, Dino Esposito, and finally the Microsoft e-book, .NET Microservices: Architecture for Containerized .NET Applications.

Out of all of these, I'm most in agreement with the Taylor solution, which in turn seems to be heavily influenced by the Microsoft guide. At first, I wanted to give this template some cool name like "Wolverine Architecture," but I didn't want to come off as too presumptuous, so I will just refer to it as "my architectural template" or "my architecture."

Before I dive in, I'd like to list a few more caveats:

  • The demo application is NOT complete, as it is in an initial state which is sufficient to demonstrate the concepts I've discussed in this and previous blog entries. It will change and evolve over time as I elaborate on more software development topics. As a matter of fact, at this point the actual "app" isn't even an ASP.NET Core web application—I've started it out using a simple console application standing in for the Presentation layer. Hopefully this will help you to get a good idea of how the various layers and their corresponding components communicate through the stack without being distracted by too many boilerplate details that would have been there had I used an actual web app for the main project. I'll try to tag the source code accordingly, so that each revision can be easily indexed to the blog entries that it pertains to.
  • A few key features are currently missing, such as Identity and Security. I'll add those in future posts.
  • This architecture represents the stack up to the Persistence layer. I'm not going to touch on the UI yet.
  • I don't agree with the above references on all points. It's okay to disagree with the experts (although, if you are going to adopt a heretical stance, be well-prepared to defend your choice). I'll try to clarify my reasoning in areas in which I deviate from their approaches.

First, the Use Case

A company would like to have a comprehensive, business-centric application to manage various functions in the organization.

  • They would like to automate processes which belong to the various business units of the organization—Human Resources, Accounting, etc. For example, they need to track payroll at a basic level, and they need a seamless way to onboard or offboard employees through the Manager of HR.
  • They need different adjunct functionalities, like tracking paid time off (PTO) time available, which will be handled through the HR side as well.
  • The business will almost certainly request additional features in the future as the application grows and they have time to interact with it, elucidating more business requirements.

I've been instructed to build an enterprise solution on the .NET Core stack and deploy it to the Azure cloud. Starting out, the system will simply handle basic HR and Accounting, but it MUST be able to grow to accommodate more complex business functions, such as those managed by Operations, or even the executive team themselves. At the outset, I'm only allowed to use a single relational database as the data store, which will also be in the cloud. Additionally, I've been told by the CIO that the Accounting logic will be coded and maintained by a separate team (maybe even a single individual). She tells me this is for political technical reasons. OK, those are my orders. Time to get to work.

A Template for Business-Focused Web Applications in the Microsoft Cloud

Code-level conventions.

As stated in blog entry 4, I generally follow the conventions from Framework Design Guidelines. Once again, I highly, highly recommend that you use a tool like CodeMaid or something similar to automatically clean up and organize your files for you. You can customize it to organize them the way you want. Here are some specifics:

  • Pascal case is used for classes names, method names, properties and so on.
  • Parameter names, private fields, etc. are camel case.
  • Underscores are never used, except in method names for unit tests. I never prefix private fields with underscores.
  • SCREAMING_CASE is never used.
  • While Hungarian notation is not allowed, certain conventions which might resemble it are okay, such as MyCoolController, MyAwesomeVm, UpdateSomethingCommand, etc. In other words, using suffixes. Those are generally okay.
  • I mentioned this in a previous post but here it is again. In recent years there has been a small yet fervent movement to stop prefixing interfaces with "I" because technically it is a vestige of Hungarian notation. DON'T DO THIS. Interfaces should be prefixed with "I" because the distinction between them and other types is so important that their names themselves should express this. If you have any doubts, just look at the source code for the various official Microsoft .NET Core packages. What do they do? (When in doubt, emulate the pros).
  • Fields/constants
  • Properties/indexers
  • Constructors
  • Nested classes

Basic Solution Organization

These are guidelines for organizing the solution into files and projects:

  • There should be one class/enum/interface per source code file. This one drives me nuts. I've encountered solutions in which there are five or six different classes in a single file along with a bunch of enums and other nonsense. However, there is an exception to this rule, which you can see in the demo application: I've nested the handler classes for commands/queries inside the command/query classes themselves. The reason for this is simple, which is that user code doesn't need to call them directly. Remember, we are relying on MediatR to perform the dispatch to handler methods.
  • Project names, folder names, and namespace names should all align. It drives me crazy when I encounter a solution in which there is a folder called "Foo" and the corresponding namespace for classes in that folder is "Bar." Don't do this. Names of everything should align, so that if decide you need to take a folder full of classes and put it into its own project, the namespaces don't break . This idea, which I'll tentatively call the "Project/Folder/Namespace Fungibility principle" is important, because as the solution grows it gives us the flexibility to refactor it easily and move different sections of the architecture into separate microservices. To put it simply, Project Name = Folder Name = Namespace . Do this, and your solutions will be much easier to refactor.
  • Related to the above point is the naming of projects themselves. A good guideline is <Company>.<Solution>.<Layer>.<Bounded context or other detail>. Alternatively, you can use <Solution>.<Layer>.<BC/detail> or whatever. Just be consistent.
  • I recommend keeping your project structure flat (for the most part). This means not hiding projects in some nested folder somewhere, which makes them difficult to find.

External Dependencies

This is a list of third-party toolkits, libraries, and NuGet packages that the solution depends upon. This is not comprehensive, and more will be added as the solution grows over time.

  • MediatR, by Jimmy Bogard - Used in both Domain layer and Application layer. This is a really powerful package and is the special sauce that brings everything together. As stated in the previous entry, MediatR facilitates a simple, elegant CQRS implementation.
  • Entity Framework Core - Microsoft's ORM. Used almost exclusively inside CQRS commands to update the database and sometimes to perform simple queries against it.
  • Dapper - A powerful and efficient micro-ORM which allows us to write flexible queries which translate well into DTO/view models. Used on the query side of the stack to return query results by projecting complex SQL queries into 1NF view models.
  • FluentValidation - Plugs nicely into MediatR and allows for validation of commands that are sent down the stack before they hit the Domain layer.
  • Mapster - A fast and intuitive object mapping library which assists in mapping view models and persistence models to/from domain models. Alternatively, you could use AutoMapper, also by Jimmy Bogard, but at this time I prefer Mapster because it's faster and the usage is slightly more intuitive.
  • Serlilog - A powerful logging library which sits on top of the base .NET Core logging infrastructure.

Logical Organization of the Solution

When working with this or any other architecture, I strive to produce solutions that are neatly organized and easy to navigate. A great principle to follow in this regard is  Screaming Architecture  ( The architecture should scream the intent of the system! ), which is another Uncle Bob-ism. Starting from this, let's discuss for a minute component organization  and  functional organization , which are two distinct methodologies for organizing classes, interfaces, components, and other objects together inside a software solution.

Component Organization

Under component organization, classes, interfaces and other objects are grouped together in folders or projects based upon their category , or what they represent—e.g. Controllers, Views, so on. The underlying concept here is  categorical cohesion , which simply means that entities of the same classification or category should go together. Imagine grouping baseball players from a baseball league. In this way, all third basemen from all teams would go together into one group, pitchers in another, and so on.

This is the default for most solutions in .NET, especially MVC solutions. At first, this seems easier to grasp but has its drawbacks. As the solution grows, you may find yourself "jumping around" more to find dependencies for different components. I've certainly found this to be the case with most legacy systems I've worked on in corporate environments, in which F12, Ctrl-F12, and Ctrl-Q become my best friends.

Component Organization

These are all the same thing?

Functional Organization

On the other hand, functional organization is based upon the idea of spatial locality: it is more efficient to keep items that are often used together near each other. The underlying concept is functional cohesion, which means that entities which work toward the same goal or purpose should go together. Going back to the baseball analogy, this would simply imply that players from each team should go together, regardless of their positions, because they play together and operate as a functional unit on that team.

As applied to a .NET software solution, classes and other objects are grouped together in folders or projects based upon their use case , or what purpose they serve—e.g. RegisterOrUpdateEmployee , GetPaidTimeOffPolicyList , etc. The benefit to this approach is that it's easier to navigate the solution, especially as it grows, and it helps you to maintain a high level of cohesion around different use cases of the system. Some of the downsides to this are that you might break from framework conventions, lose automatic scaffolding from certain tools, and so on. Personally, I think it's worth the cost. As an aside, it's worth noting that Angular uses functional organization by default, so this isn't a totally radical methodology.

Functional Organization

These all work well together.

In my architecture I use functional organization to the greatest extent possible, where it makes sense . Once again, the 80/20 rule (Pareto principle) applies. In situations where it doesn't make sense, I fall back to component organization. In Renze's demo solution he mixes unit test classes into the same folders as the classes under test within the application projects. DON'T EVER DO THIS. Unit tests are a different animal, and they belong in their own projects. Once again, principles and practices are guidance, general rules to follow, and as the character Morpheus states in the Matrix , "some of them can be bent, others can be broken."

When applied to the architectural layers of a Clean DDD solution, functional organization looks like this. Layer/grouping:

  • Domain - Each domain entity
  • Application - Aggregate root corresponding to each use case
  • Persistence - Each database table
  • Infrastructure - Each functional area of the operating system (file operations, etc.) and/or external resources
  • Presentation - Aggregate root corresponding to each screen or web page
  • Cross-cutting (Common) - Each cross-cutting concern (Logging, Security, etc.)

The Template

Just as a refresher, here is what the architecture looks like at a high level.

Clean Domain Driven-Design, Jacobs Interpretation

Core Layers

As stated in the previous entry, the core is comprised of the Domain layer and the Application layer. Think of this as the "zone of abstractions and logic".

Domain Layer Organization

Domain Layer Organization

Once again, the Domain Layer should have no knowledge of outside layers, even by proxy (i.e. by exposing interfaces which are implemented by outside layers). It is strictly for business entities and logic.

Key points:

  • I start with a single Domain project, in which I create root-level folders that hold base classes corresponding to different key DDD concepts—Models, Events, so on. Additional projects can be added, for instance to separate out bounded contexts, but this is the main one.
  • I also have a separate root level folder to house interfaces and other abstractions. I've named this Abstractions, and it's pretty similar to the way that the official .NET Core packages are structured. In fact, at some point in the future we could even separate this into its own project. This is a recurring pattern throughout the layers.
  • There is a Common folder at the root level as well, which holds various Domain entities and value objects that don't belong to any particular bounded context. This is essentially a "shared kernel" in DDD-speak. Note that this pattern doesn't just apply to the Domain layer. Anything which cuts across Bounded Contexts goes into a "Common" folder for each layer.
  • Additional root level folders exist for each bounded context. In the future, as the solution scales, each one can be broken off into its own project with little refactoring involved, if we continue to abide by the Fungibility principle I stated above. You can see this in the demo app, where I have created a separate Domain project for the Accounting bounded context.
  • I studied a few different ValueObject base class implementations and I settled on the one that Taylor's solution and the Microsoft e-book use. In this implementation , child classes must explicitly state which data properties are used for comparison. While this might seem like more effort, I prefer this over reflection-based approaches because the design of each value object should not be taken lightly, and furthermore you don't want to take a performance hit from using reflection in these. See below.
  • In general, the Domain layer should have zero reliance on external packages and third-party dependencies. However, if you examine the demo application, you'll see that I put in a hard dependency on MediatR as a means of dispatching domain events. Some may regard this as worthy of a slap on the wrist, but I consider it to be a situation where breaking the rules is acceptable, because trying to abstract away MediatR is simply is not worth the effort, and it wouldn't be hard to remove if the need arose to use a different in-process messaging implementation.

Finally, here are some thoughts on putting persistence abstractions (interfaces) in the domain layer. At least two of the solutions I examined do this. For example, in Khorikov's solution he puts CQRS commands into the Domain layer, and the Microsoft e-book does basically the same thing with repository interfaces. 

I don't agree with them. In my architectural template, CQRS commands and queries, and repository interfaces (if you choose to use them) NEVER go into the Domain layer, because they have nothing to do with pure business logic. Persistence logic, even through interfaces, does not belong in there. In this respect, my architecture is more conservative than other Clean DDD solutions—the Domain layer should ONLY be concerned with business logic and interaction among domain entities. The Application layer is the appropriate place to put persistence interfaces because that is the layer of orchestration and coordination.

Application Layer Organization

Application Layer Organization 1

In my opinion, this is the most important layer in the entire architecture, so I'll go into some detail on this. 

  • IOrgManagerDbContext - This is a facade which abstracts away an Entity Framework Core database context for our application data. This will be used almost exclusively on the command side of the stack.
  • IOrgManagerDbQueryFacade - This is a facade which abstracts away calls to a micro-ORM called Dapper. This will be used mostly on the query side of the stack, although there's no restriction against using this inside commands, should the need arise.
  • There is a Common folder in here as well. Think of it as a higher-level shared kernel. In here are subfolders, each of which corresponds to a separate Entity Framework Core entity, which in turn will map to a database table, since we're using EF code-first. You might be wondering why this is not broken apart by bounded context as well. The reason is simple: we are only targeting one database. As stated earlier, the approach is to build a monolithic application comprised of several projects, which can be broken apart into separate microservices at some later date. When (if) that time comes, we can worry about splitting the data model.
  • Also, at the root level there are folders corresponding to different bounded contexts. Just like with the Domain layer, these can be moved into separate projects, should the need arise. Each bounded context folder has subfolders corresponding to each aggregate root. Inside each of these, we've separated our commands from queries. See below on how this could scale, should the need arise to split the stack.
  • This layer may reference "helper" libraries such as mappers, internal messaging components (MediatR).
  • As stated in the previous blog entry, the use of the Mediator pattern along with CQRS is almost a no-brainer. Encapsulating commands/queries as MediatR requests is how we accomplish this.
  • We get additional benefits, such as being able to inject cross-cutting concerns into the request pipeline, which is exactly what I've done. The RequestCachingBehavior that I've implemented is a great example of this.

Application Model Classes

Remember from the last entry what I said about view models? To recap, they are models that map to some piece of the UI and are used to communicate back and forth between the UI and the Presentation layer (web API). In this architecture I treat both CQRS commands and the DTOs that are returned from queries as view models. This might strike you as wrong or otherwise violating the Single Responsibility principle, but in this instance it's okay. This is because the task-based orientation of CQRS functionally aligns with the UI, so there's typically a 1:1 correspondence between the models that present information to the user and those that are required/produced by CQRS commands and queries. Furthermore, if there comes a time when the two must be decoupled, there's nothing from stopping us from doing that and putting that mapping logic into the Presentation layer.

The persistence models are a different story... Several the solutions I studied were reusing the EF Core model classes as Domain entities. NO, NO, NO, NO! Even Taylor's solution does this, and his architecture is the closest to mine out of all them. I disagree with virtually all the experts on this. Here's why:

Persistence model classes never quite map perfectly to database tables and queries because of what Greg Young calls an object-relational impedance mismatch . This sounds complicated but it's not. All it means is that databases and programming languages differ in the way they represent data and relationships between entities, so of necessity there always must be some degree of translation going on. More specifically, databases are (traditionally) relational, which means that they are based upon Set Theory . Modern programming frameworks are (often) object-oriented, which means that they are based on Graph Theory . Furthermore, databases have their own data types which are almost always different from the data types used in your programming language of choice, so conversion or even data loss is involved when communicating between the two. If you are using an ORM like Entity Framework, then it will handle this for you. If you are writing straight ADO.NET code, then you have to deal with the pain of mapping between them yourself.

Taking this a step further, domain entities and persistence entities have radically different intents: one is used to model the business and the other is used to store data. The accepted answer from this stack exchange question , by Robert Bräutigam, explains it quite well:

DDD and EF have little to nothing to do with each other. DDD is a modeling concept. It means to think about the Domain, the Business Requirements, and model those. Especially in the context of object-orientation it means to create a design which mirrors business functions and capabilities. EF is a persistence technology. It is mainly concerned with data and database records. These two are sharply divorced. A DDD design may use EF in some form under the hood, but the two should not interact in any other way. Some interpretations of Domain-Driven Design do advocate data-modeling, and I think this is what your question is about. In this interpretation "Entities" and "Value Objects" are essentially function-less data holders only, and the design concerns itself with what properties these hold and what relation they have between each other. In this context DDD vs. EF may come up. This interpretation however is flawed, and I would strongly recommend ignoring it altogether. In conclusion: DDD and EF are not mutually exclusive, they are actually irrelevant to each other, as long as you are doing proper object-modeling and not data-modeling. DDD objects should not in any shape or form be EF artifacts. DDD Entities should not be EF "entities" for example. Inside some business-relevant function, a DDD design might use EF with some related data-objects, but those should be always hidden under a business-relevant behavior-oriented interface.

One solution to avoid getting tangled in this mess is to use mapping. You'll notice that the folders corresponding to different commands/queries have mapper classes which allow you to map from view models to domain models, and back again. Additionally, the folders corresponding to different database tables have mapper classes that allow you to map from persistence entities to domain models, and back again as well. This is the price that we must pay for using a Clean DDD approach because it's important to maintain the decoupling between Domain layer entities and view models/persistence entities. This is the biggest pain point in this architecture, but fortunately that pain can be minimized by using tools such as AutoMapper or Mapster. I've abstracted the mappers for each entity pair behind interfaces, because this makes our solution much more testable and flexible. Dependency injection is used to provide the actual implementations to the command/query classes that need them.

Persistence Entities and Facades

You might be questioning why view models and persistence models are declared in the Application layer instead of Presentation/Persistence. The answer, quite simply, is because the Application layer is doing all the heavy lifting in the system and depends upon them to manipulate the data model inside command handlers, and relay query results back up the stack from inside of query handlers.

Remember from the last entry, in which I talked about the asymmetry of the solution? You can clearly see this in the Application and Persistence layers, in which I'm using two different persistence technologies: Entity Framework Core and Dapper.

  • EF Core is Microsoft's ORM for .NET Core. I'm using this on the command/write side of the stack because it makes inserting and updating data to the database much easier. It can also be used for simple queries against the database inside CQRS commands. I've abstracted the EF Core DbContext behind an interface which gets injected into CQRS command handlers.
  • Dapper is a lightweight micro-ORM. I'm using this on the query/read side of the stack because it facilitates writing complex database queries without incurring the performance penalties typically associated with ORMs, including EF Core. I've abstracted a few key Dapper methods behind a query facade interface which gets injected into the CQRS query handlers.

You'll notice that the IOrgManagerDbContext and  IOrgManagerDbQueryFacade interfaces still allow CQRS command/query handlers to use LINQ and/or straight SQL queries. Aren't these leaky abstractions—i.e. allowing database details into the Application layer? In a sense, yes. Technically I've broken another rule and I'm sure Uncle Bob would yell at me for this. However, I'm of the camp that trying to create a "pure" abstraction that removes ALL knowledge of the underlying data store is not worth the effort, because the paradigms underlying various data stores can be so radically different that it's difficult to keep underlying details from leaking across the interface boundary anyway. What if the underlying data store is a NoSQL database? Or the file system? The Repository pattern attempts to do mitigate this problem, but I'm not a fan of using it in CQRS solutions. Read on.

To Repo, or Not to Repo?

I disagree with a few the experts on the use of the Repository pattern. In my opinion, repositories are an unnecessary abstraction in CQRS solutions—they are trying to solve a problem which doesn't exist, which is the encapsulation of task-based operations into a Unit of Work ; the commands themselves already do this. Furthermore, I believe that repositories can tend to sway you toward CRUD-type semantics, whereas CQRS commands (ideally) are unambiguously centered around business tasks. I'm not 100% against repositories, but I think they are more appropriate for CRUD applications.

While it's true that forgoing the use of repositories and writing LINQ/SQL queries directly in the CQRS handlers isn't truly persistence agnostic, it is still flexible enough that we can swap out one database provider for another (in theory). Regarding testability, we still maintain the ability to write unit tests against our CQRS handlers by mocking out the persistence facade interfaces.

Periphery Layers

The periphery is comprised of the Persistence, Infrastructure, and Presentation layers. Think of this as the "zone of implementations and concretes." Honestly, I'm not going to go into great detail with these because they are self-explanatory.

Persistence Layer Organization

Persistence Layer Organization

It's important to mention that another benefit to using Entity Framework Core is that it allows us to scaffold our database from the persistence model classes, which can be a huge time saver and result in a clean, robust database schema. That's exactly what I've done, so the EF configuration classes are in here, functionally organized into subfolders, along with the EF code migrations.

The Persistence layer additionally houses the implementations for the EF Core DbContext interface and the Dapper QueryFacade interface.

Infrastructure Layer Organization

Infrastructure Layer Organization

This is very similar to the Persistence layer. The Infrastructure layer contains concrete implementations for abstractions that are defined in the Application layer relating to things like Identity, accessing the file system, external messaging, and so on. Likewise, implementations for abstractions defined in the Common layer should also go in here, a good example being the IDateTime interface, discussed below.

You might be wondering why Identity is in here instead of in the Persistence layer. The reason is that Identity is an entirely separate architectural area from persistence, and there's no reason to assume that user identity will be backed by a DB, as opposed to some third-party identity store accessed through an API (there are dozens out there).

Presentation Layer Organization

Presentation Layer Organization

For all intents and purposes the Presentation layer is the top of the stack as far as back end code is concerned. The UI is treated separately. In the finished solution, this will be an ASP.NET Core web API with thin logic inside of it. The only code inside here will be:

  • ASP.NET Core boilerplate, to get the web API up and running.
  • Controllers, which act as the REST interface that the UI will communicate with.
  • High-level components, namely from the Application layer, which get injected into the controllers and called as a consequence of various controller actions. All these components are wired together using an IOC container and dependency injection.

While keeping the Presentation layer decoupled from the Application layer is a must, decoupling from the UI isn't as big of a deal. At some point in the future, should we feel the need, there is nothing to stop us from peeling off the Presentation layer and replace it with a desktop UI, implemented using WPF. In this case, the Presentation layer is the UI. Alternatively, we can unplug the stack starting from the Application layer on down and put it inside a different web API, one that is specifically targeted toward mobile clients. Anything is possible.

In some of the other demo solutions I studied, the web API project was treated as the Application layer. I don't agree with this. My stance is to treat the Web API project as belonging to the Presentation Layer (as distinct from the UI). This coincides with the Taylor solution and provides for much better decoupling at an architectural level.

Common Layer Organization

Common Layer Organization

There isn't much going on here, just your usual cross-cutting concerns like text manipulation and the like. As always, be careful what you put into this layer and make sure that it's a cross-cutting concern.

Here's a short explanation of the  IDateTime interface. This is in here because it's used by virtually every layer, including the Domain layer. The actual implementation for it is in the Infrastructure layer. This is something you might take for granted, but it is an incredibly powerful pattern. Some of the benefits are:

  • All components and logic which are dependent upon the system date/time instantly become unit testable.
  • What's more, if you have a system which is highly sensitive to the current date/time, you can put a special implementation behind this, and all subsystems will stay in sync.
  • I'd take this further and put in the provision that all date/times must be in UTC across the whole stack, except when being presented to the user. The reasons for this are numerous, but suffice it to say, I've acquired this point of view after working on dozens of legacy systems which DON'T do this.

Unit Test Projects

Unit Tests Organization

When adding unit tests to a solution, I largely follow the conventions espoused by Roy Osherove in his book The Art of Unit Testing . For instance, the folder structure of unit test projects should mirror the folder structure of the projects under test, and each test should be cohesive and test only one thing. In terms of code coverage, 100% is rarely feasible or necessary. Aim to test the most critical pieces first. Test-driven development (TDD) is easier when using CQRS, and I may touch on that in a future post. If you've designed them well and are using dependency injection properly, then command/query handlers should be easily unit testable.

Points for Style: F# Projects

F# Project

In the demo application I've added an F# project to the solution, representing specialized logic in the Domain layer for a bounded context. This is just to demonstrate how easy it is to create multi-paradigm solutions, and the way that I dovetail F# code into a .NET solution which is mainly built using C#. As stated in the blog entry on DDD, functional programming techniques are extremely powerful when used to implement domain logic. In this kind of a scenario, anemic domain models are okay, because the business rules are encapsulated inside functions. I'm not going to do a lot in the future using F# in the demo application, however a complete multi-paradigm solution would probably be comprised of 80% C# code, and 20% F# code. This gives you an idea of what's possible.

Example code for a domain class built using F#.

Layer Interaction

Simplistically, this demonstrates how the layers interact with each other.

Layer Interaction

In this entry I went into detail about how to implement Clean DDD and CQRS in a .NET Core solution. I mentioned some of the experts whose solutions I studied and spoke a little bit about some of their solutions. I presented the use case for a fictional company to create an organization management tool, and I introduced the demo application. I laid out some of the code-level conventions and project-level guidelines for organizing the solution, and I talked about functional organization vs. component organization. Finally, I went into detail about each layer of the architecture, building off the concepts presented in the previous blog entry. Finally, I introduced unit tests at a surface level, and I wrapped up by pointing the way toward building multi-paradigm solutions, which combine both functional F# code with OOP C# code.

Experts / Authorities / Resources

Robert c. martin (uncle bob).

  • Clean Coder
  • Screaming Architecture

Roy Osherove

  • Roy Osherove - Home
  • The Art of Unit Testing (Book)

Jason Taylor

  • Clean Architecture with ASP.NET Core 2.1
  • Northwind Traders Demo App (GitHub)

Julie Lerman/Steve Smith

  • Domain-Driven Design Fundamentals
  • Domain-Driven Design Fundamentals (GitHub)

Steve Smith

  • Architect Modern Web Applications with ASP.NET Core and Azure
  • Clean Architecture (GitHub)

Jimmy Bogard

  • Jimmy Bogard - Home
  • LosTechies.com
  • MediatR (GitHub)

Matthew Renze

  • Clean Architecture: Patterns, Practices, and Principles
  • Clean Architecture Demo (GitHub)

Vladimir Khorikov

  • Domain-Driven Design in Practice
  • CQRS In Practice (GitHub)
  • CQRS Documents

Dino Esposito

  • Modern Software Architecture: Domain Models, CQRS, and Event Sourcing

Microsoft - Microservice/DDD Guide

  • .NET Microservices: Architecture for Containerized .NET Applications
  • E-Shop On Containers (GitHub)
  • CodeMaid - Home
  • Using CodeMaid (YouTube)
  • Dapper (GitHub)

This is entry #8 in the Foundational Concepts Series

If you want to view or submit comments you must accept the cookie consent.

presentation layer ddd

The Presentation Layer - Clean Architecture & Domain-Driven Design on PHP

February 24, 2022 by Northon Torga

The entry point of our application is not coincidentally the last article of the introduction series about Clean Architecture and DDD on PHP . When developing using Clean Architecture and DDD, the Presentation layer is the last thing we focus on .

We already discussed the main aspects of our application, but I've never really mentioned HTTP yet. This should come as a surprise if you never develop using Clean Architecture and DDD.

When you rely too much on frameworks like Laravel, Express.js, etc and/or is used to MVC architecture, you usually first start with the Controllers and work your way down to the other layers, if there is any other layer at all.

Plug-and-play Presentation

The beauty of Clean Architecture is not only having a plug-and-play infrastructure , but also having a plug-and-play presentation . It really does not matter if your user is going to access the application via HTTP, CLI, telnet or even smoke signals.

Accessing  the Presentation directory you will only see a single directory there: Api. The proof of concept code available at GitHub  created for  this series has only one entry point , therefore so far our application is only a REST API .

It could easily be more than that, but for the sake of simplicity we'll focus on how the Presentation layer was created so that our application becomes accessible as a REST API .

The Presentation layer has 2 fundamental goals: handle I/O and inject infrastructure. Let's dive into these goals, shall we? 🦈

Handling I/O

The Presentation layer has 3 layers:

  • Controllers are responsible for handling the inputs;
  • Presenters are responsible for handling the outputs;
  • Middlewares exist in the middle, they can either help during the input or the output.

Inside the Api directory you will only see Middlewares and Controllers . That's because the Presenters are embedded into the Controllers for the sake of simplicity.

The first task when receiving an user input in the Controllers is to transform the received data into Value Objects . Remember, we'll hardly never use native types on our application, everything must be objects .

This is done by the getExecutionParams() method which gets the params sent by the user and tries to create the Value Objects.

The proof of concept is a 2 years old code, currently I'm not longer using try/catch on the Presentation layer at all. You may want to check an article I wrote about Error Handling with Middlware later to understand how I was able to simplify the process a lot.

Middlewares can also play an important role in converting inputs. Take for example the Authorization process of an API. The API key can be converted into a Value Object by an Authorization Middleware so that the format of the key is checked and then an infrastructure implementation can be used to query a database to validate if the API key is or not valid.

Most of the time, the output of the API is a success message ( line 66) or an information that was requested by the user. That information is very likely an Entity or a Value Object, such as seem on the GetContactController.php :

All Entities and Value Objects on the code implements the JsonSerializable interface of PHP so it's convertible into JSON by the json_encode() method. That's why the "Presenter" part of our Controller is basically the json_encode() with the Entity Contact inside it (line 47) .

In cases where the Presenter does more than just return an object, for example an endpoint that returns an HTML table converted from an Entity, then it would make sense to have it separated. In CLIs having the Presenter in it's own class makes a lot of sense so you can format the output with colors, columns, etc.

Oh, we can't forget about the role of Middlewares in the output. A ResponseMiddleware can later be used to transform the JSON into XML if the user sends an Accept header requesting a response in JSON. That way your API is able to respond both in JSON and in XML for instance.

You can also use Middlewares to handle the output for exceptional cases, such as the one mentioned on the Error Handling with Middlware article. Seriously, check that article, you won't regret. 😁

Enough about I/Os. Now let's get into the real fun part. Dependency Injection.

Injecting Infrastructure

Dependency Injection sounds cool because it's cool. With Clean Architecture you won't be requiring dependencies directing on your code as you use to. Now, all the infrastructure is regulated by interfaces , just like explained on the very first article of this series .

Since we're following interfaces, we can have multiple implementations for the infrastructure. It's the Controller task to provide an UseCase (Domain Layer) with an infrastructure implementation that guess what, implements an interface the UseCase knows how to use.

It's probably sounding like jibber-jabber for you now, but we can see that on code. Take the GetContactController.php controller again:

You can see that I'm initiating a ContactQueryRepository object (line 34) . This is an infrastructure implementation, file-based (although the name does not tell right away - my bad), of the ContactQueryRepositoryInterface :

Once I initiate the ContactQueryRepository object, I pass it to the GetContactInteractor UseCase right on the next line. That's it. That's dependency injection.

Why is that great? Well, let's see. Imagine that tomorrow I want to have a database-based implementation of that same interface, to get contacts. However, I only want to use that database-based implementation if the ContactId is greater than 1000. I don't know, maybe I was in a rush and couldn't migrate the files into a database, thus the first 1000 Contacts will be kept in file format.

The only thing I need to do besides creating a DatabaseContactQueryRepository class, is to add an if in my controller so that I pass to the GetContactInteractor UseCase the database implementation of ContactQueryRepositoryInterface instead of the standard file-based one.

I didn't change a single line on the Domain layer. In fact I didn't change anything, I created a new implementation and added an if into my controller. That's plug-and-play infrastructure right there .

The idea of having multiple implementations for the same interface is denominated  " Strategy Design Pattern ". I highly recommend you read more about Strategy in the Refactoring Guru website . That website is pure gold.

Final Thoughts

Combining Clean Architecture and DDD is a natural process. They share a lot of common principles. Once you get the hang of it, it feels like you have just learned how to program for the first time . At the same that it's liberating, you feel ashamed of what you have been writing so far.

Don't worry about that though. That's what progress feels like . Now your code has exactly the idea of what you mean by a concept that only existed in real life. No more fat controllers and skinny models, now the model (Domain) is at the center of your application, everything just fits right together.

I'm pretty sure the ethical hackers out there will agree with me when I say DDD and Clean Architecture makes an attempt to invade way, way, way harder . It's such a pain that I would rather resort to social engineering if I'm trying to pentest a system designed with DDD and Clean Architecture concepts in mind rather than spending the whole month barking up the wrong tree. 😁

What we usually see when pentesting is that code is as much vulnerable as a team without social engineering training. A chain is only as strong as its weakest link they say. At least with Clean Architecture and DDD you're strengthening one part of your business. It's one last thing to worry about when going to sleep.

« The Domain Layer - Clean Architecture & Domain-Driven Design on PHP

presentation layer ddd

Member-only story

The Evolution of DDD Layered Architecture

Dwen

DDD Architecture

The traditional four-tier architecture.

  • Presentation Layer: The Presentation Layer is responsible for handling the presentation of the user interface (UI) and user interactions. It can take various forms such as web interfaces, mobile applications, or desktop applications.
  • Application Layer: The Application Layer carries out the processing of business logic. It is responsible for receiving and handling user requests, converting them into corresponding operations, and may also include coordination and transformation logic.
  • Domain Layer: The Domain Layer encompasses the core business logic and domain models. It serves as the heart of the software system, encapsulating business entities, business rules, and business processes.
  • Data Access Layer: The Data Access Layer is responsible for interacting with the data persistence storage, such as databases. It includes operations for reading, writing, and updating data. It provides interfaces for accessing and manipulating data.

By separating the domain model and business logic from the infrastructure, user interface, and even application layer logic, we can reduce dependencies and create a more focused and cohesive system.

Breaking down a complex system into different layers ensures that each layer has strong cohesion and only relies on lower layers.

The infrastructure layer in a traditional layered architecture is situated at the bottom, encompassing persistence and messaging mechanisms.

The message here contains:

  • MQ message.

The components within the infrastructure layer can be viewed as low-level services of the application, and the higher layers couple with this layer to reuse the technical infrastructure.

However, it is still important to avoid direct coupling between core domain model objects and the infrastructure layer.

Improvements to the Four-Layer Architecture.

The DDD startup development team has identified some drawbacks to placing the infrastructure layer at the bottom in the traditional four-layer architecture. For example, it becomes challenging to implement certain technical aspects within the domain layer.

  • Violation of the basic principles of layered architecture.
  • Difficulty writing test cases.

How to solve it?

Use dependency inversion design principles: Low-level services, such as the infrastructure layer, should rely on interfaces provided by higher-level components such as the user interface, application, and domain layers.

Dependency Inversion Principle.

In traditional software development, high-level modules often depend directly on low-level modules, creating tight coupling between them.

This can make the codebase rigid, difficult to maintain, and resistant to changes.

The DIP suggests inverting this dependency by introducing abstractions or interfaces that both the high-level and low-level modules depend on.

To summarize it simply, the infrastructure layer is at the top, implementing the interfaces defined in all other layers.

There are different opinions regarding the Dependency Inversion Principle.

Some argue that it only involves the topmost and bottommost layers, where the upper layer implements the abstract interfaces defined by the lower layer.

Therefore, in the depicted diagram, the infrastructure layer would be positioned at the top, while the user interface layer, application layer, and domain layer would be considered at the same level and positioned below.

Everyone is entitled to hold their own perspective on this matter.

User Interface Layer.

The User Interface Layer typically includes user interfaces and web services.

It is responsible for handling user display and user requests, and should not contain domain or business logic.

Some argue that since user interfaces need to validate user input, it is inevitable that they should include business logic.

However, the validation performed by user interfaces is different from the validation of the domain model.

There should be limitations on the validation behaviors that are ad hoc and only specific to the domain model.

If the User Interface Layer uses objects from the domain model, then the domain objects are limited to data rendering and presentation.

In such cases, a presentation model can be used to decouple the user interface from the domain objects.

As users can be humans or other systems, the User Interface Layer may provide APIs in the form of open host services.

The User Interface Layer directly interacts with the Application Layer and serves as an adapter between the front-end and back-end.

If your microservice needs to provide services to multiple external applications, and the input and output parameters for each external application are different, it is impractical to develop a set of one-to-one application services.

In this scenario, the Facade interface plays a valuable role in assembling and transforming DO (Domain Object) and DTO (Data Transfer Object) objects.

Application Layer.

The Application Layer primarily consists of Application Services, which are responsible for coordinating and executing the operations related to use cases and workflows.

In theory, the Application Layer should not contain any business rules or logic, but rather focus on handling the operations specific to use cases and processes.

The Application Layer is positioned above the Domain Layer, as the Domain Layer contains multiple aggregates.

Therefore, the Application Layer can coordinate multiple aggregate services and domain objects to orchestrate and compose services, collaborating to fulfill business requirements.

The Application Layer also serves as the communication channel between microservices, allowing them to interact with each other.

It can invoke other microservices to accomplish service composition and orchestration between them.

When designing and developing software, it is important not to place business logic that belongs in the domain layer into the application layer.

This is because having a bloated application layer can lead to a loss of focus in the domain model.

Over time, the microservices may degrade into an MVC architecture, resulting in a lack of clarity in the business logic.

The application layer has several key responsibilities, including:

  • The application layer is responsible for the composition, orchestration, forwarding, transformation, and delivery of services. It handles the execution sequence of business use cases and the assembly of their results. Additionally, it facilitates the publication of coarse-grained services to the frontend through an API gateway.
  • Authentication.
  • Permission verification.
  • Transaction control.
  • Send or subscribe to realm events.

Domain layer.

The domain layer primarily consists of domain objects such as aggregate roots, entities, value objects, and domain services.

The domain layer is responsible for implementing the core business logic and ensuring the correctness of business operations through various validations.

It primarily embodies the business capabilities of the domain model and is used to express business concepts, business states, and business rules.

The business logic of the domain model is primarily implemented by entities and domain services.

Entities and domain services are not on the same level when it comes to implementing business logic in the domain.

When certain functionalities within the domain cannot be achieved by a single entity or value object, domain services come into play.

They can combine multiple entities or value objects within an aggregate to implement complex business logic.

Infrastructure Layer.

Provides common technical infrastructure services for other layers:

  • Three-party tools.
  • Message queue
  • API Gateway.

The infrastructure layer encompasses foundational services that utilize dependency inversion to encapsulate basic resource services, thereby decoupling them from the application and domain layers.

The MVC architecture often suffers from strong coupling between the upper application layers and the underlying database.

Many companies fear the consequences of changing the database during architectural evolution, as it may require rewriting a significant amount of code.

However, by adopting dependency inversion, the application layer can remain decoupled and independent of the core business logic.

In the event of a database change, only the DB foundational service needs to be replaced, ensuring a more seamless transition.

If you like such stories and want to support me, please give me a clap.

Your support is very important to me, thank you.

Dwen

Written by Dwen

I'm an independent entrepreneur, a developer and a father, enjoys speaking, writing, and sharing.

More from Dwen and ITNEXT

Fine-Tuning Golang: Advanced Techniques for Code Optimization

Fine-Tuning Golang: Advanced Techniques for Code Optimization

Unlock the full potential of your golang applications with our comprehensive guide on code optimization techniques, designed to enhance….

Modern Git Commands and Features You Should Be Using

Martin Heinz

Modern Git Commands and Features You Should Be Using

It’s not 2005 anymore and git offers more than just add, commit, push and pull. let’s explore all the new, modern git commands, that you….

Deciphering the Kubernetes Networking Maze: Navigating Load-Balance, BGP, IPVS and Beyond

Hossein Yousefi

Deciphering the Kubernetes Networking Maze: Navigating Load-Balance, BGP, IPVS and Beyond

In the kubernetes world, every day you hear ipvs vs iptables || purelb vs metallb || overlay vs underlay || nodeport vs loadbalance and a….

Effective Strategies for Gracefully Stopping Java Threads

Javarevisited

Effective Strategies for Gracefully Stopping Java Threads

Explore the best practices and techniques for safely and effectively stopping java threads, ensuring your multithreaded applications run…, recommended from medium.

10 Advanced C# Tricks for Experienced Developers 🔥🔥

Konstantin Fedorov

10 Advanced C# Tricks for Experienced Developers 🔥🔥

As a c# developer, exploring beyond the basics can help you unlock a new level of programming excellence and write more efficient….

Bounded Contexts: Behavior Over Data Structures — Part I

Rico Fritzsche

Level Up Coding

Bounded Contexts: Behavior Over Data Structures — Part I

Using domain-driven design key concepts for modularization: bounded context and aggregates..

presentation layer ddd

General Coding Knowledge

presentation layer ddd

Coding & Development

presentation layer ddd

Stories to Help You Grow as a Software Developer

presentation layer ddd

Alessandro Traversi

Event-Driven Architecture vs. Domain-Driven Design: Understanding the Distinctions and Synergies

In the realm of software architecture, event-driven architecture and domain-driven design are two prominent paradigms. both have their….

Stop using Exceptions

Callum Linington

Stop using Exceptions

Exceptions are so bad… they’re poorly implemented and they lead to terrible endemic design patterns..

Why  Modular Monolith architecture is better choice for future Microservice architecture

Aleksandr Pezikov

Why Modular Monolith architecture is better choice for future Microservice architecture

How a modular monolith architecture can help you to reduce costs and build a better microservice architecture.

10 Tools for Software Architects to Increase the Productivity

Ali Zeynalli

10 Tools for Software Architects to Increase the Productivity

Text to speech

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Design the infrastructure persistence layer

  • 9 contributors

This content is an excerpt from the eBook, .NET Microservices Architecture for Containerized .NET Applications, available on .NET Docs or as a free downloadable PDF that can be read offline.

Download PDF

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Data persistence components provide access to the data hosted within the boundaries of a microservice (that is, a microservice's database). They contain the actual implementation of components such as repositories and Unit of Work classes, like custom Entity Framework (EF) DbContext objects. EF DbContext implements both the Repository and the Unit of Work patterns.

The Repository pattern

The Repository pattern is a Domain-Driven Design pattern intended to keep persistence concerns outside of the system's domain model. One or more persistence abstractions - interfaces - are defined in the domain model, and these abstractions have implementations in the form of persistence-specific adapters defined elsewhere in the application.

Repository implementations are classes that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model. If you use an Object-Relational Mapper (ORM) like Entity Framework, the code that must be implemented is simplified, thanks to LINQ and strong typing. This lets you focus on the data persistence logic rather than on data access plumbing.

The Repository pattern is a well-documented way of working with a data source. In the book Patterns of Enterprise Application Architecture , Martin Fowler describes a repository as follows:

A repository performs the tasks of an intermediary between the domain model layers and data mapping, acting in a similar way to a set of domain objects in memory. Client objects declaratively build queries and send them to the repositories for answers. Conceptually, a repository encapsulates a set of objects stored in the database and operations that can be performed on them, providing a way that is closer to the persistence layer. Repositories, also, support the purpose of separating, clearly and in one direction, the dependency between the work domain and the data allocation or mapping.

Define one repository per aggregate

For each aggregate or aggregate root, you should create one repository class. You may be able to leverage C# Generics to reduce the total number concrete classes you need to maintain (as demonstrated later in this chapter). In a microservice based on Domain-Driven Design (DDD) patterns, the only channel you should use to update the database should be the repositories. This is because they have a one-to-one relationship with the aggregate root, which controls the aggregate's invariants and transactional consistency. It's okay to query the database through other channels (as you can do following a CQRS approach), because queries don't change the state of the database. However, the transactional area (that is, the updates) must always be controlled by the repositories and the aggregate roots.

Basically, a repository allows you to populate data in memory that comes from the database in the form of the domain entities. Once the entities are in memory, they can be changed and then persisted back to the database through transactions.

As noted earlier, if you're using the CQS/CQRS architectural pattern, the initial queries are performed by side queries out of the domain model, performed by simple SQL statements using Dapper. This approach is much more flexible than repositories because you can query and join any tables you need, and these queries aren't restricted by rules from the aggregates. That data goes to the presentation layer or client app.

If the user makes changes, the data to be updated comes from the client app or presentation layer to the application layer (such as a Web API service). When you receive a command in a command handler, you use repositories to get the data you want to update from the database. You update it in memory with the data passed with the commands, and you then add or update the data (domain entities) in the database through a transaction.

It's important to emphasize again that you should only define one repository for each aggregate root, as shown in Figure 7-17. To achieve the goal of the aggregate root to maintain transactional consistency between all the objects within the aggregate, you should never create a repository for each table in the database.

Diagram showing relationships of domain and other infrastructure.

Figure 7-17 . The relationship between repositories, aggregates, and database tables

The above diagram shows the relationships between Domain and Infrastructure layers: Buyer Aggregate depends on the IBuyerRepository and Order Aggregate depends on the IOrderRepository interfaces, these interfaces are implemented in the Infrastructure layer by the corresponding repositories that depend on UnitOfWork, also implemented there, that accesses the tables in the Data tier.

Enforce one aggregate root per repository

It can be valuable to implement your repository design in such a way that it enforces the rule that only aggregate roots should have repositories. You can create a generic or base repository type that constrains the type of entities it works with to ensure they have the IAggregateRoot marker interface.

Thus, each repository class implemented at the infrastructure layer implements its own contract or interface, as shown in the following code:

Each specific repository interface implements the generic IRepository interface:

However, a better way to have the code enforce the convention that each repository is related to a single aggregate is to implement a generic repository type. That way, it's explicit that you're using a repository to target a specific aggregate. That can be easily done by implementing a generic IRepository base interface, as in the following code:

The Repository pattern makes it easier to test your application logic

The Repository pattern allows you to easily test your application with unit tests. Remember that unit tests only test your code, not infrastructure, so the repository abstractions make it easier to achieve that goal.

As noted in an earlier section, it's recommended that you define and place the repository interfaces in the domain model layer so the application layer, such as your Web API microservice, doesn't depend directly on the infrastructure layer where you've implemented the actual repository classes. By doing this and using Dependency Injection in the controllers of your Web API, you can implement mock repositories that return fake data instead of data from the database. This decoupled approach allows you to create and run unit tests that focus the logic of your application without requiring connectivity to the database.

Connections to databases can fail and, more importantly, running hundreds of tests against a database is bad for two reasons. First, it can take a long time because of the large number of tests. Second, the database records might change and impact the results of your tests, especially if your tests are running in parallel, so that they might not be consistent. Unit tests typically can run in parallel; integration tests may not support parallel execution depending on their implementation. Testing against the database isn't a unit test but an integration test. You should have many unit tests running fast, but fewer integration tests against the databases.

In terms of separation of concerns for unit tests, your logic operates on domain entities in memory. It assumes the repository class has delivered those. Once your logic modifies the domain entities, it assumes the repository class will store them correctly. The important point here is to create unit tests against your domain model and its domain logic. Aggregate roots are the main consistency boundaries in DDD.

The repositories implemented in eShopOnContainers rely on EF Core's DbContext implementation of the Repository and Unit of Work patterns using its change tracker, so they don't duplicate this functionality.

The difference between the Repository pattern and the legacy Data Access class (DAL class) pattern

A typical DAL object directly performs data access and persistence operations against storage, often at the level of a single table and row. Simple CRUD operations implemented with a set of DAL classes frequently do not support transactions (though this is not always the case). Most DAL class approaches make minimal use of abstractions, resulting in tight coupling between application or Business Logic Layer (BLL) classes that call the DAL objects.

When using repository, the implementation details of persistence are encapsulated away from the domain model. The use of an abstraction provides ease of extending behavior through patterns like Decorators or Proxies. For instance, cross-cutting concerns like caching , logging, and error handling can all be applied using these patterns rather than hard-coded in the data access code itself. It's also trivial to support multiple repository adapters which may be used in different environments, from local development to shared staging environments to production.

Implementing Unit of Work

A unit of work refers to a single transaction that involves multiple insert, update, or delete operations. In simple terms, it means that for a specific user action, such as a registration on a website, all the insert, update, and delete operations are handled in a single transaction. This is more efficient than handling multiple database operations in a chattier way.

These multiple persistence operations are performed later in a single action when your code from the application layer commands it. The decision about applying the in-memory changes to the actual database storage is typically based on the Unit of Work pattern. In EF, the Unit of Work pattern is implemented by a DbContext and is executed when a call is made to SaveChanges .

In many cases, this pattern or way of applying operations against the storage can increase application performance and reduce the possibility of inconsistencies. It also reduces transaction blocking in the database tables, because all the intended operations are committed as part of one transaction. This is more efficient in comparison to executing many isolated operations against the database. Therefore, the selected ORM can optimize the execution against the database by grouping several update actions within the same transaction, as opposed to many small and separate transaction executions.

The Unit of Work pattern can be implemented with or without using the Repository pattern.

Repositories shouldn't be mandatory

Custom repositories are useful for the reasons cited earlier, and that is the approach for the ordering microservice in eShopOnContainers. However, it isn't an essential pattern to implement in a DDD design or even in general .NET development.

For instance, Jimmy Bogard, when providing direct feedback for this guide, said the following:

This'll probably be my biggest feedback. I'm really not a fan of repositories, mainly because they hide the important details of the underlying persistence mechanism. It's why I go for MediatR for commands, too. I can use the full power of the persistence layer, and push all that domain behavior into my aggregate roots. I don't usually want to mock my repositories – I still need to have that integration test with the real thing. Going CQRS meant that we didn't really have a need for repositories any more.

Repositories might be useful, but they are not critical for your DDD design in the way that the Aggregate pattern and a rich domain model are. Therefore, use the Repository pattern or not, as you see fit.

Additional resources

Repository pattern.

Edward Hieatt and Rob Mee. Repository pattern. https://martinfowler.com/eaaCatalog/repository.html

The Repository pattern https://learn.microsoft.com/previous-versions/msp-n-p/ff649690(v=pandp.10)

Eric Evans. Domain-Driven Design: Tackling Complexity in the Heart of Software. (Book; includes a discussion of the Repository pattern) https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215/

Unit of Work pattern

Martin Fowler. Unit of Work pattern. https://martinfowler.com/eaaCatalog/unitOfWork.html

Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application https://learn.microsoft.com/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Previous Next

Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback .

Submit and view feedback for

DEV Community

DEV Community

minericefield

Posted on Jan 16 • Updated on Jan 25

[DDD] Tactical Design Patterns Part 1: Domain Layer

I will be applying Domain-Driven Design (DDD) tactical design patterns in this article. I'm sorry. I'm not good at English. It is divided into the following sections:

  • Domain Layer (this article)
  • Application Layer
  • Presentation/Infrastructure Layer

To keep the description of source code in the article compact, I will be implementing it from a bottom-up approach.

GitHub Repository

https://github.com/minericefield/ddd-onion-lit

Language & Framework

TypeScript & NestJS

Architecture

Onion Architecture

An organization has decided to create a task management application for internal use (though this situation is unusual to apply DDD). Though focusing on tactical design patterns, I have prepared a simple use case diagram and a simple domain model diagram.

Something like a use case model diagram

use case model diagram

Users can perform several basic operations on tasks. It may seem unusual, but I haven't included features such as changing the progress status of tasks or setting deadlines. I omitted them because it didn't appear there would be much to learn from implementing those features in the sample code. Regarding the actor responsible for creating users, we don't have a clear understanding yet. For now, there is a consensus to avoid a situation where everyone can freely create users. Agilely, we will proceed with the implementation while leaving notes and discussion memos in diagrams for undecided aspects. However, an unknown actor is a quite rare situation.

Something like a domain model diagram

domain model diagram

I have documented various constraints, along with the behavior and multiplicity of each entity. The specification of limiting comments on a task to 20 may seem a bit unusual, but I included it as a valuable constraint to emphasize the learning theme. Ideally, I would have liked to provide details about value objects, but I have omitted them this time. The domain model diagram will be created after developing the use case diagram. This is because lacking a clear understanding of the use cases makes it challenging to conduct appropriate domain modeling. However, the representations in the domain model diagram will capture fundamental invariants that extend beyond specific use cases.

Directory Structure

While I'd like to proceed with the implementation starting from the domain layer, let's first check the directory structure to have a rough idea of the architecture.

The structure follows an Onion Architecture ("presentation" can also be named as "user-interface"). Some may suggest organizing it in a feature-based slice when using NestJS (such as having src/task/domain or src/task/application ). While that is also a valid approach, this time I referred to the module structure of IDDD for inspiration. com.saasovation.agilepm.domain.model.product No concepts of organizations like com.saasovation or context boundaries like agilepm are present. If I were to insist, the product aligns directly with the context of task management. What I took inspiration from are the modules that follow, such as domain and application. Within these, specific top-level module and aggregates come into play.

Domain Layer

This is where we express the business logic.

I've defined common exception classes for the domain layer.

For now, I've introduced validation and unexpected exceptions. These are simple extensions of standard exceptions. Domain layer exceptions primarily point to violations of business rules. While these exceptions don't have a direct relationship with the domain model, they will become necessary in the implementation of the domain layer. These are concepts that do not depend on specific protocols etc. Unexpected exceptions might be used alongside defensive programming practices. However, particularly in the domain layer, it's crucial to avoid being overly defensive, as it could blur the representation of business rules. Their usage might be quite limited.

User Email Address Value Object

I have created a value object for the user's email address. This is a minimal implementation that provides only validation and encapsulation of the value. The constructor is made public as is.

Let's go through this implementation because there seem to be some strange points.

Is a private setter necessary for the value?

In IDDD, a private setter was provided for each property of domain objects, and validation was performed within the setter (self-delegation). Especially in the case of domain objects with multiple constructors or properties, encapsulating the constraints of each property within setters through self-delegation would result in a simpler and more extensible implementation. This time, I didn't provide a private setter because there wasn't a particular advantage to self-delegation, and I opted for simplicity by only providing a constructor.

Is a specific exception class necessary?

I provided a specific exception class ( InvalidUserEmailAddressFormatException ) to indicate a format violation of the email address. However, this is not a mandatory concept in DDD. I just referenced the implementation of creating specific exception classes for particular exceptions from the "Good Code, Bad Code: Think like a software engineer" .

  • Specific and descriptive exception classes contribute to improvement of readability and error identification.
  • Setting error messages.
  • Providing metadata useful for debugging.
  • (However, be careful not to make it feel unnatural in the representation of the domain layer).

Furthermore, particularly for domain layer exceptions, it's beneficial to have them easily identifiable. This is because many use cases invoke behaviors from multiple domain objects. While it's not advisable to be overly concerned about external layers when implementing the domain layer, providing specific exception classes enables use cases or their clients to flexibly respond based on the received exception.

Is the term "Validation" appropriate?

The InvalidUserEmailAddressFormatException extends ValidationDomainException , but the term "Validation" might not be precisely suitable. In IDDD, validation was categorized as guards for each property, distinctly separated from validation. A guard, in this case, is an assertion about the validity of each parameters, and the following code snippet aligns with this concept:

In IDDD, exceptions thrown by guards were IllegalArgumentException , indicating that the argument is invalid. The concept of validation, did not appear here. Validation typically refers to cross-object validation, such as deferred validation traversing all properties within an entity. This validation's implementation details are placed as a separate resource, distinct from domain objects. But this time, I have chosen a simple approach, broadly expressing any concept that validates individual values or other invariants as "Validation" . Additionally, I have not included what is conventionally referred to as a validator in IDDD (In IDDD, a validator, unlike guards that immediately throw exceptions, traverses the object, aggregates all errors, and notifies them collectively).

A few other implementation patterns

Equality check.

Implementing the behavior of equality checking is a common practice, and it comes with several benefits:

  • Clients can confirm equality without needing in-depth knowledge of the internal structure of the value object.
  • Maintainability will be raised.
  • Something like FooValueObjectA == FooValueObjectB .
  • Value objects represent conceptually unified "values," and such a representation feels more natural.

While the email address created in this example is a simple value object with only one primitive property, the format of value objects can vary.

If clients repeatedly reference properties directly for comparisons, there's a risk of oversight when adding properties to the value object. In contrast, by using equals , modifications can be consolidated in one place. (For example, if a middle name is added)

This time, I have only implemented the minimum behavior required in the source for value objects. However, equality verification based on property (and type) comparison is one of the fundamental characteristics of value objects. In practice, you might implement the behavior of equality verification, e.g., by preparing a layer supertype with equality verification behavior.

Avoiding Validation during Reconstitution

During creation of a new object, a FACTORY should simply balk when an invariant isn’t met, but a more flexible response may be necessary in reconstitution. If an object already exists somewhere in the system (such as in the database), this fact cannot be ignored. (Domain-Driven Design: Tackling Complexity in the Heart of Software)

Addressing this issue can be approached in various ways. One example is delegating the responsibility of validation to the factory.

In the reconstitution factory ( ReconstituteUser ), validation is omitted. Alternatively, each value object class itself can hold factory interfaces for both creation and reconstitution.

However, the reconstitute as an interface within the value object class itself may feel somewhat impure. It might make sense for aggregate roots to have an interface called reconstitute. This is because reconstitution is basically the concept of reassembling aggregate roots. The distinction between the creation and reconfiguration of objects inside the boundary is just an implementation that may be needed in the process, and it may be prohibited to have it as an interface for the value object class itself. In any case, it may be necessary to consider validation during reconstitution.

While the email address format, as seen in my example, can be broadly regarded as part of the invariants, the term "invariant" is less commonly used in this this kind of context. It is more frequently employed when describing intricate business rules that need to be consistently maintained within an aggregate.

User ID Value Object

Next, I created a value object for the user ID.

For now, the only expectation for a user ID is uniqueness; there are no other specific requirements. In languages with a structural type system, like TypeScript, it can be beneficial to use a brand property for such simple entity IDs. In IDDD, the generation of user IDs was handled by the Repository . The implementation class of the Repository can generate IDs using specific persistence mechanisms or data store functions or as seen in the sample code, use a bulit-in module . But some may find it slightly awkward that a LevelDBRepository doesn't utilize LevelDB functionalities in this approach. And it may be preferable that the return value of the repository always be the aggregate root. This time, I have opted to generate IDs through a factory.

The implementation of the UserIdFactory could be functionalities such as RDB features or UUID frameworks. This allows choosing the most suitable implementation for the requirements.

User Aggregate Root

Now that the internal objects within the boundary are in place, let's create the aggregate root.

Currently, the user has no specific behavior. A user is an entity with an identifier called "id" and also serves as the aggregate root. The constructor is public and expects domain objects to be passed directly. Therefore, external resources outside the aggregate will create internal objects within the boundary and pass them to the exposed constructor. This time, for simple aggregate roots like this, we generate them following this construction approach.

User Repository

Now that we have the aggregate root, let's create the corresponding repository. Several necessary interfaces are declared:

This abstract class outlines the essential behavior that the UserRepository should provide.

Email Address Duplication Check Domain Service

Confirming duplication by asking the email address or the user itself is not feasible as a modeling approach. Users don't have knowledge of email addresses other than their own, nor should they.

Email address duplication confirmation is expressed through a domain service (defining only the abstraction is also an option). Clients will use this domain service to check for duplication before generating the user aggregate root. It's common to see domain services that return a boolean result for duplication checks. While Evans suggests that domain services should return domain objects, in cases like this domain service, returning a boolean might be more natural and straightforward as an interface. The reason I chose to throw an exception in this implementation is to express that email address duplication is a clear violation of a business rule. Using a boolean return value might lack expressive power in representing a business rule violation, and it might force the client side into a somewhat procedural implementation. On the other hand, using void is also somewhat awkward. Therefore, considering:

  • A Result type to represent business rule violations
  • A some kind of universal domain object to represent the existence or duplication status

could be a good alternative for return value.

Enforcing Invariants with a Factory

It might be an option to generate the user aggregate root through a factory, enforcing invariants.

I've created a concrete factory that focuses on generating a new user based on a name and email address for simplicity. In real practice, factories are more often abstracted to handle tasks like ID generation and querying persistence infrastructure . The reasons for introducing a factory and the implementation methods vary, but enforcing invariants is a crucial theme in the context of factories. It's worth noting that there are two main types of factories:

  • Factories representing ubiquitous language
  • Factories necessary for implementation

In this case, the UserFactory falls into the category of Factories necessary for implementation . In the case of the former domain service, the knowledge that "email addresses must not be duplicated" is appropriately expressed and encapsulated in the domain layer. However, the situation of "checking for duplication in the domain service before generating a user" still represents a leakage of responsibility from the domain layer, and clients are forced into an unstable procedural implementation. By encapsulating the generation process, including enforcing invariants, within the factory, such situations can be avoided.

Modules help organize related concepts into easily understandable structures, reduce the coupling between modules, and provide functionality to restrict access to available resources. In Java, modules can be implemented using packages , and in C#, using namespaces . However, TypeScript doesn't have these features. Ideally, we would like to define modules and restrict the invocation of aggregate root generation methods so that they can only be called from factories.

Next, I will create the domain.task module.

Comment ID Value Object

Same implementation as UserId.

Comment Entity

Comments have a UserId (objects within the boundary can hold references to other aggregate roots). Expressing the association with the aggregate root through ID references is a technique introduced in IDDD. It can make entities more compact and easy to handle while also contributing to performance improvements. Here, a dependency across modules has occurred (although the module itself has not been implemented in TypeScript, a directory structure resembling modules is used for representation).

However, this is an acceptable dependency. There are some alternatives, but none of them are recommended. Let's briefly go through them.

Place UserId in shared

Placing any shared object in the shared directory can make it unclear what concept the resource originates from. UserId should be a resource explicitly included in the user module. The shared directory is intended for more abstract shared objects or universal concepts that are not related to a specific domain.

Place a concrete generic EntityId in shared and have each entity use it directly

Something like this.

However, couldn’t the team have achieved loose coupling among these elements by the use of a generic identity type, (...) True, the team could have achieved looser coupling. However, it would also have opened up the potential for bugs in code where each Identity type could not be distinguished from the others. (Implementing Domain-Driven Design)

As mentioned in IDDD, we might pass the wrong type of ID.

Considering the reasons mentioned above, it's acceptable to directly couple UserId.

Comment Entity First-Class Collection

The invariant conditions related to the collection of comments can be directly expressed by the task entity. However, encapsulating them in a first-class collection can achieve better cohesion, resulting in a simpler and more understandable implementation of the task entity.

Always want to see the list of comments in descending order

In general, we prefer not to express display-related responsibilities in domain objects. However, in this case, the requirement is to always have comments in descending order, not limited to a specific user interface. And with minimal control over the order. For tasks like transforming domain objects into a specific structure that can be exposed externally or converting them into a format that is easy for specific end-users to read, these responsibilities might belong to DTOs or the presentation layer. This time, I chose to implement the requirement for descending order directly within the first-class collection, treating it as a high-level requirement outlined on the domain model diagram. There might be feeling some resistance to giving get value such behavior, so it could also be a good idea to define other getters.

The maximum number of comments for one task is 20

If there are already 20 comments, an exception is thrown when trying to add a new one.

Task Name Value Object

If the task name exceeds 50 characters, an exception will be thrown.

Task ID Value Object

Same implementation as other entity ids.

Task Aggregate Root

The Task aggregate root encompasses various behaviors that align with the ubiquitous language:

  • Adding a comment - addComment
  • Assigning a user - assignUser

The constructor is made private, and interfaces for creation and reconstitution are provided:

  • No comments
  • Not assigned to anyone
  • This requires self-discipline, as it should ideally be used only by the repository.

Task Repository

A repository corresponding to the aggregate root is defined for tasks.

  • Domain-Driven Design: Tackling Complexity in the Heart of Software
  • Implementing Domain-Driven Design
  • Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy
  • ドメイン駆動設計 モデリング/実装ガイド
  • ドメイン駆動設計 サンプルコード&FAQ
  • ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

satyjeet11 profile image

Optimizing Your Fleet, Maximizing Your Profits: The ROI Case for MDM in Transit

satyjeet - Apr 5

vamsikrishna011 profile image

Harnessing Green AI: Pioneering Sustainable AI Development Services

Nagavamsi - Apr 5

chintanonweb profile image

Deep Dive into Angular's HttpClient: Everything You Need to Know

chintanonweb - Apr 5

josuesalazaku profile image

Tailwind CSS: A Utility-First Approach to Streamlining Web Development

Josué Salazaku - Apr 5

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Domain-driven design (DDD)

In domain-driven design (DDD) , a domain is the core of the software system. The domain model is defined first, before you develop any other module, and it doesn’t depend on other low-level modules. Instead, modules such as databases, the presentation layer, and external APIs all depend on the domain.

In DDD, architects decompose the solution into bounded contexts by using business logic-based decomposition instead of technical decomposition. The benefits of this approach are discussed in the Targeted business outcomes section.

DDD is easier to implement when teams use hexagonal architecture. In hexagonal architecture, the application core is the center of the application. It is decoupled from other modules through ports and adapters, and has no dependencies on other modules. This aligns perfectly with DDD, where a domain is the core of the application that solves a business problem. This guide proposes an approach where you model the core of the hexagonal architecture as the domain model of a bounded context. The next section describes hexagonal architecture in more detail.

This guide doesn’t cover all aspects of DDD, which is a very broad topic. To gain a better understanding, you can review the DDD resources listed on the Domain Language website.

Hexagonal architecture

Hexagonal architecture, also known as ports and adapters or onion architecture , is a principle of managing dependency inversion in software projects. Hexagonal architecture promotes a strong focus on the core domain business logic when developing software, and treats external integration points as secondary. Hexagonal architecture helps software engineers adopt good practices such as test-driven development (TDD), which, in turn, promotes architecture evolution , and helps you manage complex domains in the long term.

Let’s compare hexagonal architecture to classical layered architecture, which is the most popular choice for modeling structured software projects. There are subtle but powerful differences between the two approaches.

In layered architecture, software projects are structured in tiers, which represent broad concerns such as business logic or presentation logic. This architecture uses a dependency hierarchy, where the top layers have dependencies on the layers below them, but not the other way around. In the following diagram, the presentation layer is responsible for user interactions, so it includes the user interface, APIs, command line interfaces, and similar components. The presentation layer has a dependency on the business layer, which implements domain logic. The business layer, in turn, has dependencies on the data access layer and on multiple external services.


        Classical layered architecture

The main disadvantage of this configuration is the dependency structure. For example, if the model for storing data in the database changes, this affects the data access interface. Any change to the data model also affects the business layer, which has a dependency on the data access interface. As a result, software engineers cannot make any infrastructure changes without affecting the domain logic. This, in turn, increases the likelihood of regression bugs.

Hexagonal architecture defines dependency relationships in a different way, as illustrated in the following diagram. It concentrates decision making around domain business logic, which defines all the interfaces. External components interact with the business logic through interfaces called ports . Ports are abstractions that define the interactions of the domain with the external world. Each infrastructure component must implement those ports, so changes in those components no longer affect the core domain logic.


        Hexagonal architecture

The surrounding components are called adapters . An adapter is a proxy between the external world and the internal world, and implements a port defined in the domain. Adapters can be categorized in two groups: primary and secondary. Primary adapters are the entry points to the software component. They allow external actors, users, and services to interact with the core logic. AWS Lambda is a good example of a primary adapter. It integrates with multiple AWS services that can invoke the Lambda functions as entry points. Secondary adapters are external service library wrappers that handle communications with the external world. A good example of a secondary adapter is an Amazon DynamoDB client for data access.

Targeted business outcomes

The hexagonal architecture discussed in this guide helps you achieve the following objectives:

Reduce time to market by improving the development cycle

Improve software quality

Adapt more easily to change

These processes are discussed in detail in the following sections.

Warning

To use the Amazon Web Services Documentation, Javascript must be enabled. Please refer to your browser's Help pages for instructions.

Thanks for letting us know we're doing a good job!

If you've got a moment, please tell us what we did right so we can do more of it.

Thanks for letting us know this page needs work. We're sorry we let you down.

If you've got a moment, please tell us how we can make the documentation better.

IMAGES

  1. Domain Driven Design: Layers

    presentation layer ddd

  2. Domain Driven Design implemented by functional programming

    presentation layer ddd

  3. Domain Driven Design Implementation Guide

    presentation layer ddd

  4. Domain driven design layers

    presentation layer ddd

  5. Data driven design vs domain driven design

    presentation layer ddd

  6. domain driven design

    presentation layer ddd

VIDEO

  1. Présentation des 8 positions d'études de l'échiquier électronique Scisys MK 12

  2. What actually does a buyers agent do? Arizona Real Estate 602-321-6188 #RLS8GUY

  3. Did Factor V Leiden Cause this Patient's Acute Stroke?

  4. Tale Vs Luminous Windt

  5. Puffer Demo

  6. Aluminum Foils Your Fridge & Lights Up Your City! The Unexpected Journeys of This Metal #viral

COMMENTS

  1. architecture

    15. There is a big difference between the application layer and the presentation layer from a DDD view point. Although DDD centers around how to model the domain using the DDD building blocks and concepts such as bounded contexts, Ubiquitous language and so, it is still vital to clearly identify and separate the various layers in your app. The ...

  2. Designing a DDD-oriented microservice

    The three layers in a DDD microservice like Ordering. Each layer is a VS project: Application layer is Ordering.API, Domain layer is Ordering.Domain and the Infrastructure layer is Ordering.Infrastructure. You want to design the system so that each layer communicates only with certain other layers.

  3. DDD

    This layer is the part where interaction with external systems happens. This layer is the gateway to the effects that a human, an application or a message will have on the domain. Requests will be accepted from this layer and the response will be shaped in this layer and displayed to the user. As you can see in the sample project, the system ...

  4. [DDD] Tactical Design Patterns Part 3: Presentation/Infrastructure Layer

    Presentation / Infrastructure Layer. Due to the nature of these layers, implementations primarily focus on framework-specific details. However, in DDD, specifics about framework functionalities are not crucial. Let's just roughly go through and confirm these layers.

  5. A Brief Intro to Clean Architecture, Clean DDD, and CQRS

    Presentation Layer. The Presentation layer is an API layer that brings together all the Application layer components and injects them with the proper implementations (typically using an IOC container). In my interpretation, this layer is NOT the user interface (UI), but rather presents a facade which the UI communicates with. I'll discuss this ...

  6. Layered Architecture

    In Domain-Driven Design (DDD), a layered architecture is often used to organize the solution domain into different parts. For example, it may consist of a presentation layer, an application layer, a domain layer, and an infrastructure layer. The presentation layer handles user interaction, the application layer implements the use cases and ...

  7. A Template for Clean Domain-Driven Design Architecture

    DDD is a modeling concept. It means to think about the Domain, the Business Requirements, and model those. Especially in the context of object-orientation it means to create a design which mirrors business functions and capabilities. EF is a persistence technology. It is mainly concerned with data and database records.

  8. The Presentation Layer

    The Presentation layer has 3 layers: Controllers are responsible for handling the inputs; Presenters are responsible for handling the outputs; Middlewares exist in the middle, they can either help during the input or the output. Inside the Api directory you will only see Middlewares and Controllers. That's because the Presenters are embedded ...

  9. The Evolution of DDD Layered Architecture

    Presentation Layer: The Presentation Layer is responsible for handling the presentation of the user interface (UI) and user interactions. It can take various forms such as web interfaces, mobile applications, or desktop applications. ... Improvements to the Four-Layer Architecture. The DDD startup development team has identified some drawbacks ...

  10. Domain Driven Design

    Domain-driven design (DDD) is an approach to software development for complex needs by connecting the implementation to an evolving model. The premise of domain-driven design is the following: ... Application Layer: Mediates between the Presentation and Domain Layers. Orchestrates business objects to perform specific application tasks ...

  11. Monoliths to microservices using domain-driven design

    Domain Driven Design (DDD) is a software development approach first introduced by Eric Evans. DDD requires a good understanding of the domain for which the application will be written. ... Create a presentation layer. The next step is to separate the presentation layer from the backend layer. In a traditional n-tier application, the application ...

  12. Designing the infrastructure persistence layer

    That data goes to the presentation layer or client app. If the user makes changes, the data to be updated comes from the client app or presentation layer to the application layer (such as a Web API service). When you receive a command in a command handler, you use repositories to get the data you want to update from the database.

  13. [DDD] Tactical Design Patterns Part 1: Domain Layer

    Situation. An organization has decided to create a task management application for internal use (though this situation is unusual to apply DDD). Though focusing on tactical design patterns, I have prepared a simple use case diagram and a simple domain model diagram.

  14. Domain Driven Design

    Speaking in terms of more "classical" DDD, yes domain objects are typically not allowed anywhere outside of the domain. But it is not an absolute rule that domain objects are not used in the presentation layer. For example, Naked Objects represents a school of thought where domain objects are used directly.

  15. Overview

    In domain-driven design (DDD), a domain is the core of the software system. The domain model is defined first, before you develop any other module, and it doesn't depend on other low-level modules. Instead, modules such as databases, the presentation layer, and external APIs all depend on the domain. In DDD, architects decompose the solution ...

  16. c#

    As I understand, "all good DDD applications" should have 4 layers: Presentation, Application, Domain, and Infrastructure. The database should be accessed using Repositories. Repository interfaces should be in Domain layer and repository implementation - in Infrastructure (reference DDD: Where to keep domain Interfaces, the Infrastructure?

  17. web applications

    In order to have "layer purity" - yes, that's the way to do it. But you can easily avoid having much redundant code. Make a BaseService that defines all common methods (like save(..), update(..), delete(..)Other, more complex methods are likely to (and should) require some interaction with the domain object.

  18. DDD

    Depending on their form, a good place for them is either the Application Layer or the Presentation Layer. If the DTOs are only for presentation purposes, then the Presentation Layer is a good choice. If they are part of an API, be it for input or output, that is an Application Layer concern.