DTO pattern VS Anemic Model Antipattern

Tanya Maslova
Version 1
Published in
7 min readFeb 1, 2023

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 antipattern. What is it and where does it come from?

Photo by Markus Spiske on Unsplash

Anemic model

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.

The fundamental horror of this anti-pattern is that it’s so contrary to the basic idea of object-oriented design; which is to combine data and process together. (Martin Fowler, 2003)

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.

Rich Model

Photo by Ben Hershey on Unsplash

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:

Rich Pet entity model

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.

DTO (Data Transfer Object). Where does it fit in all this?

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.

Conclusion

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.

In the case of model that resides in presentation layer, a DTO, where we want a lightweight POJO to transfer the information, it is important to keep it lightweight and not have business logic related to business domain.

About the Author

Tanya Maslova is a Senior Java Developer at Version 1.

--

--