51

I am working on RCP application, I'm new to this application.

Spring beans are used to write business logic to save/fetch entities.

But, instead of sending entities directly to client we are converting to DTOs and populating client. While saving, we again are converting DTO to entity and saving.

What's the benefit of these conversions? Can someone explain?

3
  • 1
    What's the benefit of these conversions? decoupling the persistence data model from the data model (representation) offered to the consumers. The benefits of decoupling has been widely discussed in S.E. However, the aim beneath DTOs is to gather in a single response as many info as deemed necessary for clients to save calls to the server. What makes the communication client-server smoother.
    – Laiv
    Commented Jun 28, 2018 at 13:02
  • 2
    Possible duplicate of Is it good practice to use entity objects as data transfer objects?
    – Dherik
    Commented Jan 15, 2019 at 11:05
  • Your example is nice. When you are the client (views...) is painful to change, but the biggest problem is when the system already have integrations of 3th party, that is impossible to change (contract, fees...). If your system will have third-party integration, ever use DTO. Commented Jan 30, 2019 at 17:09

1 Answer 1

116

Whenever a developer asks "what's the point of doing this?", what they really mean is "I see no use case where doing this provides a benefit". To that end, let me show you a few examples.


All examples will be based on this simple data model:

A Person entity has five properties: Id, FirstName, LastName, Age, CityId

And you can assume that the application uses this data in many varied ways (reports, forms, popups, ...).

The entire application already exists. Everything I mention is a change to the existing codebase. This is important to remember.


Example 1 - Changing the underlying data structure - Without DTO

The requirements have changed. The age of the person needs to be dynamically retrieved from the government's database (let's assume based on their first and last name).

Since you don't need to store the Age value locally anymore, it therefore needs to be removed from the Person entity. It's important here to realize that the entity represents the database data, and nothing more. If it's not in the database, it's not in the entity.
When you retrieve the age from the government's web service, that will be stored in a different object (or int).

But your frontend still displays an age. All the views have been set up to use the Person.Age property, which now no longer exists. A problem presents itself: All views that refer to the Age of a person need to be fixed.


Example 2 - Changing the underlying data structure - With DTO

In the old system, there is also PersonDTO entity with the same five properties: Id, FirstName, LastName, Age, CityId. After retrieving a Person, the service layer converts it to a PersonDTO and then returns it.

But now, the requirements have changed. The age of the person needs to be dynamically retrieved from the government's database (let's assume based on their first and last name).

Since you don't need to store the Age value locally anymore, it therefore needs to be removed from the Person entity. It's important here to realize that the entity represents the database data, and nothing more. If it's not in the database, it's not in the entity.

However, since you have an intermediary PersonDTO, it's important to see that this class can keep the Age property. The service layer will fetch the Person, convert it to a PersonDTO, it will then also fetch the person's age from the government's web service, will store that value in PersonDTO.Age, and passes that object.

The important part here is that anyone who uses the service layer doesn't see a difference between the old and the new system. This includes your frontend. In the old system, it received a full PersonDTO object. And in the new system, it still receives a full PersonDTO object. The views do not need to be updated.

This is what we mean when we use the phrase separation of concerns: There are two different concerns (storing the data in the database, presenting data to the frontend) and they need a different data type each. Even if those two data types happen to contain the same data right now, that might change in the future.
In the given example, Age is a difference between the two data types: Person (the database entity) doesn't need an Age, but PersonDTO (the frontend data type) does need it.
By separating the concerns (= creating separate data types) from the beginning, the codebase is much more resilient to changes made to the data model.

You might argue that having a DTO object, when a new column is added to the database, means you have to do double work, adding the property in both the entity and the DTO. That is technically correct. It requires a bit of extra effort to maintain two classes instead of one.

However, you need to compare the effort required. When one or more new columns are added, copy/pasting a few properties doesn't take all that long. When the data model changes structurally, having to change the frontend, possibly in ways that only cause bugs at runtime (and not at compile time), takes considerably more effort, and it requires the developer(s) to go hunting for bugs.


I could give you more examples but the principle will always be the same.

To summarize

  • Separate responsibilities (concerns) need to work separately from each other. They should not share any resources such as data classes (e.g. Person)
  • Just because an entity and its DTO have the same properties, does not mean that you need to merge them into the same entity. Don't cut corners.
    • As a more blatant example, let's say our database contains countries, songs and people. All of these entities have a Name. But just because they all have a Name property, doesn't mean that we should make them inherit from a shared EntityWithName base class. The different Name properties have no meaningful relation.
    • Should one of the properties ever change (e.g. a song's Name gets renamed to Title, or a person gets a FirstName and LastName), they you'll have to spend more effort undoing the inheritance which you didn't even need in the first place.
    • Although not as blatant, your argument that you don't need a DTO when you have an entity is the same. You're looking at the now, but you're not preparing for any future changes. IF the entity and DTO are exactly the same, and IF you can guarantee that there will never be any changes to the data model; then you are correct that you can omit the DTO. But the thing is that you can never guarantee that the data model will never change.
  • Good practice doesn't always pay off immediately. It might start paying off in the future, when you need to revisit an old application.
  • The main killer of existing codebases is letting the code quality drop, continually making it more difficult to maintain the codebase, until it devolves into a useless mess of spaghetti code that's unmaintainable.
  • Good practice, such as implementing a separation of concerns from the get to, aim to avoid that slippery slope of bad maintenance, in order to keep the codebase maintainable for as long as possible.

As a rule of thumb to consider separating concerns, think of it this way:

Suppose that every concerns (the UI, the database, the logic) is handled by a different person in a different location. They can only communicate by email.

In a well-separated codebase, a change to a particular concern will only need to be handled by one person:

  • Changing the user interface only involves the UI dev.
  • Changing the data storage method only involves the database dev.
  • Changing the business logic only involves the business dev.

If all of these developers were using the same Person entity, and a minor change was made to the entity, everyone would need to be involved in the process.

But by using separate data classes for every layer, that issue isn't as prevalent:

  • As long as the database dev can return a valid PersonDTO object, the business and UI dev do not care that he changed how the data is stored/retrieved.
  • As long as the business dev stores the data in the database, and provides the needed data to the frontend, the database and UI devs don't care if he decided to rework his business rules.
  • As long as the UI can be designed based around the `PersonViewModel, then the UI dev can built the UI however they want. The database and business devs don't care how it is done, since it doesn't affect them.

The key phrase here is since it doesn't affect them. Implementing a good separation of concerns seeks to minimize affecting (and therefore having to involve) other parties.

Of course, some major changes can't avoid including more than one person, e.g. when an entirely new entity is added to the database. But don't underestimate the amount of minor changes that you have to make during an application's lifetime. Major changes are a numerical minority.

14
  • 2
    Comprehensive answer, Thanks. I have questions; Appreciate if you answer: 1- Correct me, if i'm wrong. Business Object or View Object is for transferring data between Presentation Layer and Business Layer and Entity Object is for transferring data between Business Layer and Data Access Layer. and DTO can be used as a dumb BO. 2- Assume that two views need different info of a company then we need two different companyDTOs?
    – Arash
    Commented Nov 6, 2019 at 10:24
  • 4
    @Arash (1) "DTO" is really a catch-all definition for any data class that is used for exchanging between two layers. A business object and a view object are both DTOs. (2) That very much depends on a lot of things. Creating a new dto for every collection of fields you requires is a cumbersome task. There's nothing inherently wrong with simply returning a full company DTO (where reasonable) and then letting the view pick the fields it's interested in. It's a matter of finding the balance between implementing adequate separation of concerns and avoiding overengineering and pointless repetition.
    – Flater
    Commented Nov 6, 2019 at 11:18
  • Now that's make sense to me. Thanks a lot. Flater.
    – Arash
    Commented Nov 6, 2019 at 16:13
  • 1
    @GiladBaruchian: From the answer: "It's important here to realize that the entity represents the database data, and nothing more. If it's not in the database, it's not in the entity." What you're suggesting is to use a DTO but call it an entity. That's just going to lead to confusion and muddying the separation between your persistence and domain/business layer.
    – Flater
    Commented Apr 26, 2020 at 12:41
  • 1
    @Flater i am working on a big application and we have very big and complex object, just because of this concept we are doing so much work and have many bugs because of mapping, and 99% of the time the DTO and entity are exactly the same Commented Apr 27, 2020 at 13:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.