Categories
Software Development

DTOs and ViewModels: when and how to use them

A simple, easy-to-use technique that helps keeping code-coupling low, enabling you to evolve your Domain model without introducing breaking changes.

It is not unusual to come across Entity classes being used directly as API outputs, data for Views, query results or as a means to exchange information between parts of a system. You generally see code like this:

Which is bad, because it creates coupling between your Domain model and the various consumers of your application. Suppose you have a Customer entity, modeled as follows:

And an API endpoint that returns this Customer:

Generating a response like this:

But Models Evolve…

Then the business people come up with a new requirement, which is to keep the Customer’s birth date so that special offers can be sent to them on their birthday. In addition, the Customer will now be ranked as Basic, Intermediate or Advanced, whereas before they could either be advanced or not (as denoted by the IsAdvanced property). Your entity now looks like this:

And as such your API response will be automatically reshaped into the following, as soon as the updated version goes live:

Which is a problem, because generally, when you have a published API with people using it, you can’t simply change the response format of your endpoints; you have made a commitment to maintain backward compatibility, which means you should keep everything working even in the face of constant changes in your system.

With this modification to the Entity we introduced breaking changes in the API: the IsAdvanced field no longer exists in the Customer entity, having been replaced by the Level field.

Depending on the business, this can also pose privacy issues, because now consumers of this API will have access to the date of birth of all customers. It may also represent a security breach if the Entity is used on Create/Update endpoints, because Model Binding mechanisms will pick up information for every matching field, even for those that shouldn’t be changed like that:

You may be tempted to solve this problem by adding validations or clearing the fields before sending the Entity to be persisted, but this logic would then need to be replicated to other places of the system that accept input from the outside world, and there’s always the chance that you or someone else will not remember to do all the necessary validations every time, not to mention the fact that validations are Business Rules and should not be delegated to classes outside the Domain.

ViewModels to the rescue

You can solve the problems above by employing ViewModels.

By creating intermediate objects for transfering data to and from your Domain, you decouple Entities from the outside world and gain the ability to evolve them independently.

Benefits of this approach:

  • Properties can be added, removed or have their names changed without breaking anything for cunsumers;
  • Theses changes will all turn into compilation errors, which can be easily fixed before commiting the code;
  • Framework-dependent validation attributes have been removed from the Entity class;
  • Consumers of the API can no longer see or modify fields they shouldn’t;
  • No confusion regarding which piece of data is used in each context, as each context has a model tailored to its specific needs.

Deep dive

So far we’ve talked about ViewModels and left DTOs out. It’s time to bring clearer definitions for each one.

DTO is a class that contains only data, without any kind of behavior (methods, logic). It is a simplified form of representing the information of an entity or even aggregated data of several entities. While an Entity is modeled to represent the operations related to the business problem it is solving, DTOs are much leaner and represent a modulated portion of the data. You will typically have DTOs in the middle layers of the application, the ones that sit between the Domain layer and APIs or Web Clients.

ViewModel is a Model for a View. It’s like a DTO, however specialized for a presentation, which can be the result of an API call or the page in a Web Application. It generally accepts a DTO as input and adds information and methods specifically targeted to the View in question. In the case of a page in a Web Application, it may contain logic to show or hide a field, formatting functions and other things directed to the final presentation of the information, which in turn helps avoid Spaghetti Code in Views.

When to use ViewModels and DTOs

It is always worth remembering that code is not an asset, it’s a liability. All code you write must now be tested, maintained and updated. The less code the better, and DTOs and ViewModels do introduce one more step in the flow of development because they need to be translated, mapped from one side to another. So, this is not a technique you should use in every single case.

I would recommended it for projects with medium to high complexity, and those which tend to be maintained and updated for a reasonable amount of time. In the case of small systems focused on CRUD operations, which are basically a thin layer on top of a database, DTOs and ViewModels are an unnecessary complication.

Conclusion

ViewModels and DTOs are techniques that help us decouple Entities from other classes and layers in the application. As such, we are able to evolve Domain classes without worrying about breaking existing functionality. Any breaking changes, if any, should appear at compile-time, and you can fix them before deployment.

Lower coupling results in less effort to meet new requirements or to refactor the codebase. It also results in fewer bugs because modifications cause little or no impact on other parts of the system, since each workflow uses its own set of classes to represent the required information.

Summary Card

What Use specialized classes to transfer data to and from the Domain
Why
  • Decouple Domain Entities from the other layers
  • Reduce overall coupling related to data contracts
  • Gain the ability to evolve your Domain model independently from the rest of the application
  • Less effort and bugs when introducing new features
  • Remove dependencies in Domain classes from framework-specific attributes
  • Reduce chances of introducing security breaches and privacy issues
When
  • Medium and high-complexity systems
  • Projects that may stay around for a long time, with new features every once in a while
  • Not for really small projects, and/or those CRUD-focused
Where
  • Entering or leaving the boundaries of your Domain/Business layer
  • Data models for presenters
How
  • Create a data-only class that is specialized to an input or output
  • In the case of ViewModels, it is highly recommended to have one per View
How much
  • Complexity is low-to-none for new projects
  • Complexity can be high if refactoring highly coupled systems
  • Small (but existing) cost of mapping between classes
  • Really pays off in the long run

By Phillippe Santana

Passionate about writting code that people can understand, I'm a software developer, a project manager, an entrepreneur, and people/culture enthusiast. Find me on [Linkedin](https://www.linkedin.com/in/phillippesantana/) and on [Medium](https://medium.com/@phillippesantana).