DTO – Data Transfer Objects

This post is part of my Dev rules of thumb series. In them, I leave you with a poster with a few rules I follow for each concept, which you can print out and scatter around your office, and a brief explanation of what that pattern is about. You can also find a PDF of the poster at the bottom of this post, for better quality printing.However, please remember, a dev rule of thumb is a Principle with broad application that is not intended to be strictly accurate or reliable for every situation.

DTOs

Data Transfer Objects (DTOs) are objects used only to pass some data around as a whole, as opposed to several individual variables.

This makes the client code simpler, as it only needs to deal with one conceptual unit of code, and methods receiving the data will have fewer parameters and better typed ones.

Since the goal is simply to move data around, they don’t really need any business logic, only the minimal logic necessary for client code to create such DTOs with an initial set of data, and to be able to later retrieve their data.

So, a DTO is created with a set of data and is passed around. Would it make sense for the emitter of the DTO to send a set of data and for the consumers to receive a different set of data?! No. It would completely defeat the purpose of a DTO. So a DTO should never be changed, it must be immutable.

I usually prefer to have no validation within the DTOs, and leave that to the object receiving the DTO, unless the language is loosely typed, in which case I will validate the types. Usually, as long as the properties types are correct the DTO is in a valid state. However, a DTO might be in a valid state for a receiver, but in an invalid state for another receiver. It’s the receiver that must validate if it can perform its logic with that set of data, or not.

Despite not used with persistence in mind, they do need to be serializable so that, if needed, they can be put in a queue and sent to other applications. For this reason, they can not contain complex data structures, namely circular references, objects who might be connected to several other objects in a huge data graph that could yield a huge payload, or entities which could, on deserialization, be considered by an ORM as a new entity instead of a new version of an entity the ORM already has in cache.

Martin Fowler, who wrote about the DTO pattern in his book “Patterns of Enterprise Application Architecture“, has mentioned that “their whole purpose is to shift data in expensive remote callsin an article from 2004. However, in the same article he also mentions “One case where it is useful to use something like a DTO is when you have a significant mismatch between the model in your presentation layer and the underlying domain model.” which is not necessarily a “remote” scenario. Furthermore, at the end of the same article, he gives yet another use case for DTOs: “communicating between isolates in multi-threaded applications” (again, not a remote scenario). I believe that what Martin Fowler intents to alert against is the overuse of DTOs, always using DTOs to move data through every layer of the application brings unnecessary boilerplate and blurs the expressiveness of the domain representation.

Personally, I mostly think of DTO when I have a query object that returns some data that a template needs. Its a purely presentation need, there is no domain need involved, and it is local (fits the 2nd scenario Martin Fowler refers to).

Nowadays, I often use Envelopes, Commands and Events, which I see as specializations of DTOs. They are DTOs with a specific role (maybe remote, maybe not). So I only refer to them as DTOs when explaining to other developers what they are.

Back in 2004, we were still very much tied to a layered architecture style, where objects could know about persistence and serialization mechanisms, so the pattern would include in a DTO a method to serialize such objects. This is still valid in such an architecture style. However, nowadays we also use concentric layered architecture styles like Clean Architecture. In such scenario the DTO is unaware of any serialization mechanism and thus does not need a serialization method.

Here’s a simple example of a DTO:

<?php
final class CreatePostalCodeCommand
{
private string $postalCode;
private string $locality;
private float $latitude;
private float $longitude;
private string $administrativeArea;
public function __construct(
string $postalCode,
string $locality,
float $latitude,
float $longitude,
string $administrativeArea
) {
$this->postalCode = $postalCode;
$this->locality = $locality;
$this->latitude = $latitude;
$this->longitude = $longitude;
$this->administrativeArea = $administrativeArea;
}
public function getPostalCode(): string
{
return $this->postalCode;
}
public function getLocality(): string
{
return $this->locality;
}
public function getLatitude(): float
{
return $this->latitude;
}
public function getLongitude(): float
{
return $this->longitude;
}
public function getAdministrativeArea(): string
{
return $this->administrativeArea;
}
}
An example of a DTO

9 thoughts on “DTO – Data Transfer Objects

  1. One of the reasons to use a DTO is not using several variables; so, here I see one problem: what if a service needs to be extensible and be used by several controllers or use cases in different layers? These controllers / use cases should use that DTO which lives in another layer. I see a problem here. What if we pass an array to our inner classes instead of DTO? It’s more flexible, right?

    What’s your thoughts about the idea of passing arrays?

    Like

    1. The DTO is specific to that service, its single purpose is to reflect the method signature, so it should live next to it, not in another layer. Whatever can use the service can also use the DTO.

      Arrays reduce typing, suppose your service is expecting 10 integers and the array contains 10 numeric strings, or whatever else? Typing will make mistake obvious, an array will not.
      When absolutely needed, I type it with Psalm array shapes, makes it less bad, but still not ideal.

      Like

  2. You spoke of specializing your DTO’s and basically spliting them up into Envelope, Command and Event objects. By Envelope are you referring to the Envelope/Letter pattern which can be used to change an object’s class at runtime? And if so, could you elaborate a bit more on what that would look like?

    I’m imagining a Query object that can be changed into a format that the Command takes to be passed back to the application layer ie. the Application Service and/or Repository.

    Thanks!

    Like

    1. I would say they are different things, with different purposes, although i do see why you made the relationship.

      A protobuffer is a serialisation language. Using it, we can have a Java application serialise an object into text, save it to a file or send it to rabbitMQ, and have a C++ application read that text and deserialise it into an object. This way we can pass objects around between different applications.

      A DTO is simply an object to pass data around, inside the same application.

      Like

Leave a comment