Advanced 25 min read

DTOs, Wrapper Classes, and Avoiding Overengineering

By the end of this lesson, you'll be able to:

  • Define a DTO (data transfer object) and explain when one is worth introducing
  • Recognize the warning signs of overengineering a simple problem
  • Reflect on this module's patterns as tools to reach for deliberately, not by default

Prerequisites: "Strategy Pattern"

A DTO at the trigger-handler-to-UI boundary

public class TransactionSummaryDTO {
    public String accountName;
    public Decimal currentBalance;
    public Integer transactionCountThisMonth;

    public TransactionSummaryDTO(String accountName, Decimal currentBalance, Integer transactionCountThisMonth) {
        this.accountName = accountName;
        this.currentBalance = currentBalance;
        this.transactionCountThisMonth = transactionCountThisMonth;
    }
}

Rather than exposing the full Bank_Account__c SObject (with every field, including ones a Lightning Web Component (Module 34) has no business seeing) directly to the front end, a DTO exposes exactly the shape a consumer needs — a deliberate, minimal contract between layers.

When a DTO is NOT worth it

If a method's caller and callee are both internal Apex code that already has full access to the same SObject, wrapping that SObject in a DTO adds a translation step with no real benefit — the SObject is the appropriate shape already. DTOs earn their keep specifically at boundaries where the full SObject shape would be excessive, inappropriate, or a security concern (Module 28), not universally.

The overengineering warning, stated plainly

Every pattern in this module — service, selector, domain, dependency injection, factory, strategy, DTO — solves a real problem at a certain scale. Module 42's banking system, at nine lessons, didn't need any of them, and was better for it: Module 41's "don't design for hypothetical future requirements" principle applies here directly. Reach for these patterns when a genuine pain point (Lesson 1) shows up — duplicated queries, untestable logic, a runtime decision scattered across many call sites — not because a pattern exists and feels sophisticated to use.

Exercise

As a comment, explain why Module 42's original BankAccountService.getAccountsFor, returning Bank_Account__c directly, did NOT need a DTO wrapping it.

Show hint

Think about who was calling that method and what they needed.

APEX

DTOs, Wrapper Classes, and Avoiding Overengineering Quiz

1. What is this closing lesson's central caution about the patterns covered in this module?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

A DTO is a simple, dependency-free object used to pass structured data between layers — useful when a layer boundary shouldn't leak an SObject's full shape directly. This closing lesson also steps back to caution against applying every pattern from this module reflexively, even where a simpler approach would do.