In onion, hexagonal, or clean architecture, can a domain model contain different properties than the domain model in the database?
W

2

6

I am asking you who know well and have experience in building a software using any layered architecture (onion, hexagonal, clean, etc.). Whenever I google about the software architecture, people have different perspectives and explain the same architecture in a different way.

TERMS

Before you read the question, some terms might confuse you, so I am defining them below. I am not sure if I have the 'right' definitions for them, but I gathered these information from the internet. Let me know if I am misunderstanding.

Domain Layer: contains enterprise/business logic and uses domain model. located at the center and does not depend on any other layers except the domain model.

Application Layer: contains application logic, accepts DTO from the infrastructure layer, and transfer View Model

DTO (Data Transfer Object): a class, JSON string, etc. used for transferring data between layers in and out. may be a pure data container.

VM (View Model): a DTO that is passed to the presentation layer from the application layer.

DO (Domain Model): a class, JSON string, etc. used in domain layer. may be a pure data container.

VO (Value Object): database entity (a database row), or a data format that the database uses. can be transferred to the application layer from the database layer.

SUMMARY

In onion, hexagonal, or clean architecture, the domain layer is in the center (i.e. the domain layer does not depend on any layers other than the domain model which is used for transferring data to other layer or accepting data from the higher layer).

This means the domain model (DTO, POJO, VO, or whatever) that the domain uses might be different from the model that the database(s) use for saving persistent data.

I drew a diagram so that I can give you better explanation.

enter image description here

enter image description here

Q1:

Please look at the red parts of the second image.

If the domain layer is in the center unlike the traditional layered or n-tier architecture, can the domain model have more properties (or different properties) than the database entity (row)?

For example, assume that the domain layer uses a class called Person. The user requests the pictures of all people registered in the server. Let us assume that the database contains only the names of all people. However, we may use other web server to request a picture of a person by the name. So the application layer will read all the names from the database, and with those names, it will get all the pictures from the other web server through a HTTP request. After that, the list of the Person with a name and a picture will be sent to the user as a view model (DTO).

Q2:

The persistence layer may be consisted of a database, file system, other web API, etc.

The presentation layer layer may be a website, desktop app, mobile app, web API, etc.

Both of the layers are part of infrastructure layer and depends on the application layer, but the application layer only depends on the domain layer.

When the application layer is accepting a request from the presentation layer, there is no problem because the presentation layer calls the application layer and the presentation layer knows the application layer.

In most of the time, the application layer needs to get a data from the persistence layer.

There is no way that the application layer can call the persistence layer without having any dependency, because it does not know any classes in the persistence layer.

This is how I am understanding so far, can someone give me a clear explanation how the data should flow and how the communication is done from the lower layer to the higher layer?

For those who want to write code, I prefer C#.

Wither answered 4/9, 2020 at 9:21 Comment(0)
W
3

Q1: > can the domain model have more properties (or different properties) than the database entity (row)?

Yes it can, because a domain model is not a database model. You should not mix them, because they change for different reasons. A domain model (in clean architecture the entities) change because of changes to the application independent business rules. A database model changes because of changes to the way the data is persisted. You would violate the single responsibility if you mix them.

There is no way that the application layer can call the persistence layer without having any dependency, because it does not know any classes in the persistence layer.

This is how I am understanding so far, can someone give me a clear explanation how the data should flow and how the communication is done from the lower layer to the higher layer?

There is a way. It is called dependency inversion. If you are doing structured programming your code will look like this:

+-----+   f()    +-----+
|  A  |  ----->  |  B  |
+-----+          +-----+

There is a class A that calls a method f on class B.

If you are using C# you will see a using B in class A. If you are using java it will be an import B. No matter what programming language you use. The name of class B will appear in A.

But if it is a using or import statement it means that the compiler knows. Thus you have a compile time dependency A -> B.

When the code is executed the flow of control (runtime dependency) is also A -> B.

Let's take a look at another approach

+-----+   f()    +------------+       +-------+
|  A  |  ----->  | BInterface | <---- | BImpl |
+-----+          +------------+       +-------+

In this scenario A depends on an abstraction of the former B that I call here BInterface and the implementation is moved to a class BImpl implements that interface.

At runtime the flow of control still goes from A into method f of BImpl, but at compile time A and BImpl depend on BInterface and thus the dependency from BImpl to BInterface points against the flow of control.

You can achieve this using polymorphism. This approach is called dependency inversion, because you invert the dependency so that it points against the flow of controll.

Back to your question

Your application layer should define an interface that it can use to gather entities. This interface is often called a Repository. Your db layer can then implement that Repository (dependency inversion).

In the clean architeture it will look like this

clean architecture

Remember the double lines between the use case and the database implementation. These lines are called architectural boundaries. Every dependency that crosses this line must point in the same direction to honor the clean archtecture dependency rule.

Also make sure that you do not make the mistake that you put implementation specific stuff in an interface.

An interface is an abstraction and thus tells what can be done, not how it is done.

public interface PersonRepository {

    // WRONG - because the where is usually a part of an SQL or JPQL
    // and thus exposes the implementation.
    public List<Person> findByCriteria(String where);
} 

a better approach would be

public interface PersonRepository {

    public List<Person> findByCriteria(PersonCriteria criteria);
} 

public class PersonCriteria {
    
      private String firstName;
      private MatchMode firstNameMatchMode; // something like STARTS_WITH, ENDS_WITH, CONTAINS

      // setters omitted
}

You might want to implement a more sophisticated criteria, but always keep in min that you should never expose implementation details.

Waterman answered 5/9, 2020 at 5:58 Comment(0)
T
2

Q1: Can the domain model have more properties (or different properties) than the database entity (row)?

Of course. Both models may have different properties. The "persistence port" ("repository") implementation, i.e., the adapter would translate one model into each other.

Q2:

In most of the time, the application layer needs to get a data from the persistence layer.

There is no way that the application layer can call the persistence layer without having any dependency, because it does not know any classes in the persistence layer.

For getting data from the persistence layer, the application layer calls a "repository" (DDD lingo), i.e., a "port for persisting data" (hex arch lingo). This repository (port) belongs to the domain, so the application layer calls the domain layer.

A database adapter implements the port. The adapter belongs to the infraestructure layer, and this is ok, since the infra layer depends not just on the app layer, but on the domain too.

Here are my articles about hexagonal architecture if you are interested:

https://jmgarridopaz.github.io/content/articles.html

Tripartite answered 4/9, 2020 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.