Have fun learning about Test-Driven Development with JitterTed's TDD Game

Naming Conventions for DTOs

DTOs, DBOs, Views, Requests, and more

Originally published on . Last updated on .


This article comes from a question asked in my Discord. If you want to discuss topics like this, come and join us, it’s free!

Naming Conventions

Today, someone asked me about naming conventions for Data Transfer Objects (DTOs). I primarily use DTOs to carry information from my “domain” to and from the outside world. DTOs are a core part of the Hexagonal Architecture that I use for organizing code. (You can watch my video on the topic on YouTube[1].)

Somewhere there needs to be code that transforms (or translates, or “maps”) the internal domain objects into strings and numbers that can be sent to (or received from) the outside world. Some folks put that code in separate mapper classes, but I prefer to put it directly in the DTO.

I usually use a static from() method that converts a Domain object to the DTO, like this:

public static UserProfileDto from(UserProfile userProfile) {
return new UserProfileDto(userProfile.getId(),
userProfile.name(),
userProfile.phoneNumber().asRaw(),
userProfile.email(),
userProfile.role().name());
}

The downside to using from() is that it can look odd when using it in a stream-map context, like this:

List<UserProfileDto> dtos = userProfiles.stream()
.map(UserProfileDto::from)
.collect(Collectors.toList());

but I’ve gotten used to it. The alternative is to use toDto(), but I don’t think that’s clearer. I no longer name my DTO classes with a Dto suffix, unless I can’t think of anything more descriptive. These days I create objects with names like MemberView for something displayed in a browser (see below), or CreateMemberRequest for an incoming request[^translated] to create a member.

[^translated:] This kind of DTO is often translated from a web form or JSON automatically by a framework, such as Spring.

public static MemberView from(Member member) {
return new MemberView(member.getId().id(),
member.firstName(),
member.githubUsername(),
String.join(",", member.roles()));
}

Persistence with DBOs

When I need to transform a DTO back into a domain object, I’ll create an asDomainObject() instance method, like this:

UserProfile asUserProfile() {
return new UserProfile(id,
name,
new PhoneNumber(phone),
email,
Role.valueOf(role));
}

Often the DTO comes from a database or other persistence mechanism. I mostly use ORMs like Spring Data JPA or JDBC, where my naming convention for objects stored in the database is now Dbo (DataBase Object) as the suffix (e.g., UserProfileDbo or MemberDbo). This makes it clear that the DBOs match the structure of the database and are not Domain Objects. It also helps me differentiate them from other DTOs.

Setters & Getters

The rest of the DTO consists of getters and setters to allow libraries (such as Spring and Jackson) to access the DTO’s properties programmatically[2]. This is, in fact, a standard that goes way back to the JavaBean specification defined in 1997. Having getters and setters in domain code, however, is a no-no, which I’ll talk about in future articles.


  1. This video is a bit dated, but my course on Refactoring to Hexagonal Architecture goes into detail about this. ↩︎

  2. Records can be used instead, with some exceptions, as of Java 14. See MemberView for an example. ↩︎


Make Your Code More Testable™️

Don't miss out on ways to make your code more testable. Hear about new Refactoring techniques, improving the Test-Driven Development process, Hexagonal Architecture, and much more.

    We respect your privacy. Unsubscribe at any time.