1

I am building an API Rest with Spring Boot and I would like to clarify a concept about my architecture, to see if the community can help me.

Imagine that in my database I have a table called Person. I am mounting an architecture based on three layer architecture. The general scheme would be as follows:

  • On the one hand I have the PersonDao.java, which will be in charge of accessing the database to retrieve the tuples from the Person table. To do this, it uses a class called PersonEntity.java, which contains (as attributes) all the columns of the table. PersonDao.java is going to return an object from the PersonModel.java class. PersonModel.java is the class that represents the Person business model.

  • On the other hand, I have the PersonService.java, which is responsible for carrying out the business logic of my application. This service calls PersonaDao.java to access the information stored in the database. PersonService.java works with objects of the PersonModel.java class, since this class represents the business objects of my application. PersonService.java will always return a PersonDto,java.

  • Finally, PersonController.java. This controller will be the one that exposes the connection interface of the Rest API. He always works with DTO and communicates with PersonService.java through DTO as well.

PersonController <-> (PersonDto) <-> PersonService <-> (PersonModel) <-> PersonDao <-> (PersonEntity) <-> DB

The question is: Is it necessary to use the PersonModel.java class so that PersonService.java only works with objects of this class? Or would it be better for PersonService.java to work directly with objects from class PersonEntity.java? If I do it this way it is to maintain the principle of single responsibility, so that each layer only works with objects of its scope.

If the answer is that PersonModel.java is necessary to maintain the principle of single responsibility of each layer. Would something change if JpaRepository were used? If I ask this question it is because in many tutorials and examples I see that when JpaRepository is used, the services work directly with the entities. In this case, shouldn't we create a class that represents the business object for the services?

EDIT: In the answer to this question (Spring Entities should convert to Dto in service?), the architecture that makes sense in my head would be reflected, but surely it is not the most correct thing. The conclusion I come to is that each layer would use its own kind of objects. Copy / paste of the answer:

Typically you have different layers:

  • A persistence layer to store data
  • Business layer to operate on data
  • A presentation layer to expose data

Typically, each layer would use its own kind of objects:

  • Persistence Layer: Repositories, Entities
  • Business Layer: Services, Domain Objects
  • Presentation Layer: Controllers, DTOs

This means each layer would only work with its own objects and never ever pass them to another layer.

Thanks in advance.

Mr. Mars
  • 762
  • 1
  • 9
  • 39
  • 1
    The answer you added from other post somewhat supports my suggestion, that is you have presentation/boundry layer that solely deals with DTOs and delegates the mapping between DTO <-> Entity to an AutoMapper (e.g. `MapStruct`, or your own implementation). – Kenan Güler Mar 31 '20 at 14:33
  • 1
    Domain object and domain entity are by and large the same thing. Anything that has to do with your domain can be classified as a domain object, whereas the domain objects that you want to persist within your database are usually called `entity` meaning that you don't have to persist each of your domain object, but usually you do, and those domain objects are referred as `entity`. – Kenan Güler Mar 31 '20 at 14:35
  • 1
    Please also note that (from my own experience) the DAOs and business service classes both use/access the domain objects/entities - DAOs usually only deal with `entities`, so there is no need an additional encapsulation between a service and DAO / Repository. Your PersonDao deals with entities and the ORM framework, whereas the business services carry out the core business logic using the domain objects/entities. – Kenan Güler Mar 31 '20 at 14:59

1 Answers1

1

From what I understand your question is particularly about the layers and their useage within the logic tier. (Thus the presentation and data tiers are not part of the question).

About the PersonModel

I am not sure, what you mean with the PersonModel and what it actually does, but at first sight I can say you normally would not need something like that, which would just add additional code duplication and maintenance overhead sooner or later.

About the PersonDto

The DTOs, as the name suggests, are really meant to be for transferring data between the client (presentation layer) and your API (controller / boundary layer within the logic tier) which are used to expose "client friendly" presentation of your domain model, to regulate the over- and under-fetching - somehow (thanks to GraphQL this is now almost no longer a problem). So your business service classes don't need to know or deal with the DTOs at all.

Also, as you already mentioned, for the sake of SRP the business or dao classes should not deal with additional data mapping (e.g. Dto <-> Model, Model <-> Entity) in any way. They already fulfill a certain task within the logic tier (cf. boundary layer, service layer).

About the PersonEntity

This is something that normally represents both the real entity from your problem domain and data tier (e.g. database table in a RDBMS or document in a NoSQL). So it's pretty common

  • that the entity classes are named without a suffix such as Entity. Just use the plain name for it, e.g. Person,

  • that the entity classes contain additional annotations (e.g. JPA) to make them visible for the ORM layer (e.g. Hibernate),

  • that the entity classes should not be necessarily anemic and actually contain some additional behavior (probably what you wanted to do with your PersonModel class), e.g.

class Person {
  Date birthday;

  int getAge() { /* calculate age based on the birthday */ }

  boolean isAdult() { /* getAge() >= 18 */ }
}

Wrapping up

Use case: creation of Person entity

Hinflug (outbound flight)

[Client] --> (data: JSON) --> <Deserialization as `PersonDTO`> --> <DTO Validation> --> [PersonController] --> <AutoMapping to `Person` entity> --> [PersonService] --> [PersonDao] --> <ORM and JDBC> --> <Entity Validation> --> DB

Note: <Validation> can also be done within the Controller manually but usually Bean Validation API is used to automate this process in the backgroud. The good thing is you can use the Bean Validation API to validate both your DTOs and the Entities (e.g. with Hibernate Validator).

Rückflug (return flight)

DB --> <ORM and JDBC> --> [PersonDao] --> [PersonService] --> <AutoMapping to `Person` entity> --> [PersonController] --> <AutoMapping `Person` entity to `PersonDTO`>  --> <Serialization of `PersonDTO`> --> (data: JSON) -> [Client]  
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Kenan Güler
  • 1,868
  • 5
  • 16
  • 1
    Thank you very much for your answer. With PersonModel I was trying to say that it is a class that identifies objects that are only the responsibility of the services. That is, something intermediate to PersonDto and PersonEntity to limit their use in services. From what you say, I understand that it only adds redundancy and duplication to the code, because it would not make sense. Perhaps my doubt is given because it may be that the entity that is stored in the database is not the object to be dealt with in the domain (logic) layer. In this case, shouldn't a new class be defined? – Mr. Mars Mar 30 '20 at 23:31
  • @Mr.Mars Like I said, I think, it's OK to use `entity` classes for both the business logic (service) and persisting (DAO / ORM). – Kenan Güler Mar 31 '20 at 00:12
  • 1
    @Mr.Mars About the `PersonModel`: If I understand you correctly, nothing prevents you from creating additional classes to meet your needs; for example you can create classes to implement the `facade` or `strategy` pattern etc., so whatever your domain logic needs. But even in this case `PersonModel` would not be a suitable name. Maybe `SomeUtility` or similar singleton components that you use from various services, controllers, or even DAOs. – Kenan Güler Mar 31 '20 at 00:15
  • Perhaps I have expressed myself wrong. With PersonEntity I am referring to the DAO implementation detail, that is, as close to the database as possible. With PersonModel, it would be the business object of the application (considering the service as well). I understand that with JPA my business object would be the class that was annotated with @Entity. But in the case of DAO, is it necessary to do a mapping first to a class that understands the persistence layer and then another mapping to a class that understands the domain layer? – Mr. Mars Mar 31 '20 at 06:34
  • In your return flight, I mean there should be another class in between PersonDAO and PersonService responsible for mapping tuples fetched from database to objects in a class and for transporting of the information from the DAO to the Service. – Mr. Mars Mar 31 '20 at 06:40
  • 1
    @Mr.Mars In this case, the ORM framework (e.g. Hibernate) is responsible for creating/fetching/mapping of database queries and query results and here the ORM framework uses the domain entities to do so. As I mentioned in another comment, your DAO and business service classes deal with the domain entities. You can also say that you have domain objects that you don't want to persist, in this case only your business services or even the controllers use these objects - really depends on the use case and problem domain. – Kenan Güler Mar 31 '20 at 14:42
  • 1
    Now I got it. Thank you very much for your patience, time and explanations :) – Mr. Mars Mar 31 '20 at 15:27
  • @Mr.Mars if you have a demo app or something, you can upload it on GitHub and I can take a look at it and give you feedback - if you like. Otherwise, buena suerte. Cuidese! – Kenan Güler Mar 31 '20 at 16:11
  • Oh, thank you very much! I am currently in the design phase and have nothing implemented yet. When I have something I will notify you and, if you can, give me some advice. Gracias, amigo! Buena surte :) – Mr. Mars Mar 31 '20 at 16:57