why dto is anti pattern?
A few weeks ago I was working on a bug. The issue was whenever business support people tried to edit some ticket seat trait (e.g. aisle seat, parking pass) using our internal tool, some value for the ticket seat trait became null when changes are saved. I work at StubHub, a secondary ticket marketplace, in case you wonder why I'm talking about tickets and seats.
Upon investigation, I found out that this value being nulled-out was a new column added to our ticket seat trait table. What caught my eyes was the convoluted way data from this table is exposed to the user:
By the time you read this, you probably have guessed it why the values are null: some one forgot to update the code that does the conversion between the different models when the new column was added to the persistent model. I was pretty upset when I saw this. NOT that I'm mad at the person who forgot to update the conversion code. I wouldn't blame him/her at all. I probably would have made the same mistake because there's no easy way to detect this type of errors. What drove me nuts was the use of the intermediary classes that does nothing but making the code bloated and fragile. What a classic example of misuse of the Data Transfer Object (DTO) pattern!
And that's not all. I searched through our code and counted. We have around 2500 DTOs in all the projects!
Data Transfer Object, also know as "Value Object", originated from the book "Core J2EE Patterns: Best Practices and Design Strategies":
In Martin Fowler's P of EAA catalog, he defines DTO as the following (notice that he uses Value Object for a different concept):
It may not be obvious from the above descriptions, but the problem the DTO pattern tries to address is: method calls to EJB objects can be remote, hence expensive. So instead of making multiple calls across the network, DTO is used to fetch all needed data in one call to reduce the network chattiness and improve the performance.
Here is more detailed explanation of the DTO pattern:
http://www.oracle.com/technetwork/java/transferobject-139757.html
Yesterday's pattern has become today's anti-pattern. EJB is something from the past that's no longer used any more. With Spring/Hibernate or JPA, entity objects are just POJOs, there's no performance overhead when you pass them between layers. But people continue to use DTO for the wrong purpose. In the example at the beginning of this article, using DTOs adds not benefits but extra cost of maintenance.
Some people may argue that DTO can act as a layer of abstraction so that changes to the entity object won't break upper layers that consume the object. In my opinion, that's exactly what you should not do. It's better to have the problem blowup in your face right away rather than having subtle bugs in production which are much more difficult to find and much more costly to fix. In the example above, if there weren't any DTOs between layers, the bug wouldn't exist at all since any modification to the entity object will be immediately available to the consuming layers. If the changes are not compatible with the consumers, the source code simply won't compile, which is a good thing because it's much easier to catch and fix. If we don't have control of the consumers and are worried that consumers will be broken by the changes, we can simply version our library.
Adam Bien has an article that goes even further by declaring that PREMATURE ENCAPSULATION IS THE ROOT OF ALL EVIL. He argues that any abstraction is leaky. Layers of abstraction makes the source code dominated by infrastructure code which hides the core logic. The result is bloated code that's difficult to understand and maintain.
Don't use Data Transfer Object unless you have a strong case for it. One such case maybe for performance reason. If using DTO can avoid multiple round trips that are expensive (remote calls, database visits, etc.), go ahead and do it. That is what DTO was originally introduced for: to improve performance and workaround older versions of J2EE's shortcomings. What has changed is that those shortcomings no longer exist so cases when you need DTO has gone down to almost never.
When in doubt, leave it out. You'll thank yourself later for staying away from DTOs. And your colleagues will appreciate it as well.
In my exciting journey as a software engineer, I came across entity classes where I expected some sort of behaviour related to what these classes represented, but could not find it. Instead, the behaviour was deviously hidden in a huge service or utils class. And I also came across some classes that I would not expect any behaviour, yet there it was, in plain sight. I am sure that you have come across this as well. These unexpected encounters prompted me to write on this particular topic — where we would expect a behaviour related to business logic and where we wouldn’t.
This little blog describes what “Anemic model anti-pattern” is and what “DTO pattern” is .
Anemic model is a model that represents a business domain but does not have any business logic associated with it. That is, it is an entity class that contains only data with getters and setters for that data, but sadly has no behaviour. In a simple CRUD application where there is not much business logic to deal with, this is not a problem at all. However, in more complicated applications this could be an issue. When I see these sort of classes I always feel a bit sorry for them. In my weird imagination they appear to be neglected by their creator and stripped of the knowledge that they should have. They cannot do anything on their own and need some service (usually extremely big) to do things or to communicate/change their state.
Anemic model anti-pattern usually comes from a desire/urge to put all business logic into services especially when we have multilayer architecture and we are using SpringBoot application with `@Service` annotation.
To demonstrate anemic model antipattern I am going to pretend that we are designing and developing a game about looking after pets. The game will be simple. We need to feed the pet and exercise it. If we don’t feed the pet, then the poor thing will become ill. In that case we take the pet to the vet. If we overfeed the pet and not provide enough exercise then the pet will become naughty and misbehave.
Our entity class Pet will contain energyLevel field that would indicate whether the pet needs feeding or exercise. Unfortunately for Pet, we are going to implement Anemic model antipattern and hence the pet’s behaviour will be placed in a OwnAPetService.class.
The unlucky OwnAPetService will have all the knowledge about the EnergyLevelenum, what should happen to the energy level of a pet when we exercise it, how the behaviour of the pet changes depending on the energy level. In addition to that, it should also know when to persist the entity. As you can see, with Anemic model antipattern single responsibility is not popular. The service is taking care of a lot of things at the same time.
When the pet is not feeling well and the energy level is low, as a good owner we want to contact the vet for the vet to fix our pet. So we will have VetService. VetService needs to have similar knowledge about the pet — EnergyLevel and change status of the pet accordingly. So we will have code repetition in these two services. We could create a Utils class or another service to change pet behaviour. Then at least this code will not be duplicated:
But then we create additional dependencies on PetUtils. And what if we want different kind of pets that would have different statuses based on the energy level. For example, we might have a cat that will have happy status when the energy level is high and a pony that will be naughty when the energy level is high. Changing status of the pet in that case will be difficult. If we keep this logic in the PetUtils class then we will have to check the type of the pet there. What if we have to have new Status such as HUNGRY and a new EnergyLevel such as VERY_HIGH ? All of those changes will require us to modify Services and PetUtils because the business domain logic for Pet model is spread across those classes. And therefore we can forget about Open and Close principle because we are changing these classes, not extending them. Similarly, Dependency Inversion principle is quietly collecting dust somewhere outside our code because our classes have dependency on concrete classes that hold the knowledge of Pets business domain, not an abstract class.
In addition, the services will be a nightmare to unit test because we will have to mock static PetUtils, and test not only what the service is doing, but also what happens to the model.
Lets see what happens when we make our anemic entity a rich entity instead. Our Pet will be an abstract class and Cat, Dog, Horse or any other pet type will be its child classes that will implement the changeStatus()method in their own way.
Pet will have all the knowledge about its status and energy levels and how it is going to change its status as well as what happens to the energy levels when it is being exercised or fed. The business logic for pet is encapsulated in the Pet class. The service that would be using Pet will not have to know anything about those enums and all the business logic that changes the pet status.
Here is what our rich Pet model looks like:
Here is our OwnAPetService with the rich Pet entity:
And here is our VetService with the rich Pet entity:
As you can see both services are more readable than those in the anemic model example. The only knowledge these services have is what to call on the model to achieve a desired result. They do not need to know about what is happening under the hood of the pet domain. They do not have to know the type of the pet they are dealing with. They are dependant on an abstract class that contains the knowledge of Pet business logic.
If we want more types of pets with different behaviour we can extend Pet class without affecting anything else. Similarly, if we want different statuses or energy levels implemented differently by different types of pets we can do so without affecting any services by extending Pet and overriding behaviour where necessary.
With the rich model unit testing also becomes easier. We unit test the business logic of the business entity model on the model only. And we unit test the service behaviour without having to test what is happening to the model.
So we have established that a business entity model should have business logic associated with it. However, not all models should have business logic. In the case of DTO — which acts as just a transfer object between processes, we should not have any business logic. This is a pattern where a POJO, a light weight object, carries an information between the processes in order to reduce network overhead. For example, a DTO can be a JSON returned by an API call. Or it could be a parameter received by the API from a client.
DTO is not a business entity. DTO stays in the presentation layer and decouples presentation layer from business domain. DTO can consist of several business entity models depending on what is needed on the presentation layer.
Imagine in our game we want to see all our pets that we are taking care of. Our Pet API will return a list of pets to the UI. This is where a DTO will come in.
Lets look DTO that our API will return to the UI:
And PetDto:
We can have a mapper that would build DTO from an entity:
And we can call this mapper in the controller to return the DTO to UI.
As you can see PetDto and PetsOwnedDto are light weight objects that return only what is required by the presentation layer.
Whereas business domain entity models, like Pet, will have information required for business layer.
Ironically, DTO is a kind of anemic model. However, this is a sacrifice we might want to make if we want the DTO to not be aware of the business entities. For example, the same DTO can be used in different APIs and may contain data from different sources.
This blog attempted to demonstrate where we should place business logic in a model and where we should not.
In the case of model that resides in business layer it is important for the model to be rich and have knowledge about the business logic it represents. This blog highlighted disadvantages of anemic model that defeats some SOLID principles as well as OO design, makes unit testing challenging, and code difficult to maintain.
If using inheritance is a means of reducing code duplication, I'm a little reluctant to have DTOs inherit from anything at all. Inheritance implies an is-a relationship between child class and the parent.
Using audit fields as an example, would you say the following statement is true?
It sounds kind of funny to me when I read it out loud. Inheritance in DTOs becomes problematic, because you introduce coupling between classes where each class usually represents a concrete idea or use case. DTOs sharing a common parent class implies the class hierarchy will evolve at the same time, and for the same reasons. This makes these classes harder to change without having a ripple effect cascading to classes where the new fields might not be applicable.
You'll notice this happen more often for DTOs that serialize and deserialize data from sources you have no control over, like a web service owned by another company or team.
That being said, I've found cases where processing a DTO can be abstracted away. Audit fields are a good example. In these cases I've found interfaces to be a much more robust solution than a concrete parent class, for the simple fact a DTO can inherit from multiple interfaces. Even then I keep the interface as tightly focused as I can and only define the minimal methods to retrieve or modify a small subset of fields:
Now if we go back to our is-a test:
The statement makes more sense. With the use of interfaces it becomes easier to utilize polymorphism in the classes that process DTOs. Now you are free to add and remove interfaces as you see fit to aid in processing the DTOs without affecting the serialization and deserialization to and from their source format. Because interfaces are being used you can modify the classes to reflect structural changes in the data, and have additional methods that make the DTO more palatable to the classes processing them.
Going back to audit fields, you have one web service call a property creatorId and another one calls it createUserId. If both DTOs inherit from the same interface, then processing both of them becomes easier.
Let's say you have a sales staff web service. By coincidence the property names in the XML response match the Auditable interface, so nothing extra is needed in this class:
The customer web service returns a JSON response and two fields are named differently than what is defined in the Auditable interface, so we add a couple of getters and setters to this DTO in order to make it compatible:
More Questions
- What is your citizenship if you live in the philippines?
- Could you suggest How does blood pressure change after eating??
- What is srt climbing?
- Why is lvt so expensive?
- How to diagnose borderline intellectual functioning?
- What are the symptoms of low blood pressure?
- What are xp practices in agile?
- Iih when to go to hospital uk?
- How to create cloudformation stack in aws?
- How to use aws cloud shell?