Photoruction工事中!

Photoructionの開発ブログです!

DTOクラスの基本

はじめまして、BPOチームでエンジニアやってますkazuです🦌

最近業務で、DTOクラスを教えてもらったので理解を深めようと思い記事にしてみました。

そもそもDTOクラスとは

DTO(Data Transfer Object)とは、システム間やレイヤー間(例:UIとビジネスロジックビジネスロジックとデータベースなど)でデータを転送する時に用いられるオブジェクトのこと。

APIやDBから受け取ってきた生のデータを扱いやすい形に変換して、一貫した形式でアプリケーション内部に受け渡しができる。

特徴

  • ロジック(ビジネスロジックドメインロジック)を持たない
  • プロパティを保持するシンプルなクラス
  • 入力値の以上や型揃えの不備を発見しやすくなる

つまり、あくまで「データの運搬がメイン」のオブジェクトで、ビジネスロジックドメインロジックのような業務ルールや制約などの処理に含まれず、純粋にデータのやり取りを担うことを目的としている。

なぜ、DTOを使う必要があるのか

1. レイヤー間の依存を減らす

例えば、ドメインオブジェクト(エンティティ)をUI層に直接渡すと、UI層で余計なフィールドやメソッドを操作できてしまい、依存関係が複雑になったりする。

DTOを挟むことで、UI層に必要な情報だけを切り出し、UI層とドメイン層の結合度を下げることができる。

2. データのまとまりを担保する

データをひとつのオブジェクトにまとめることで、転送やシリアライズが簡単になり、データの受け渡しを行う関数やAPIの引数/戻り値を整理しやすくする。

3. セキュリティやバリデーションのしやすさ

データチェックやバリデーションをDTOクラスの生成過程で扱いやすくなる。

DTOがよく使われるシュチュエーション

Webアプリケーションのリクエスト/レスポンス

マイクロサービス間通信

  • マイクロサービス同士が通信する際、ServiceA → DTO → ServiceBのようにデータ転送をする

レイヤードアーキテクチャ

上記のような間で、Entityをそのまま渡すと密結合になるため、DTOを介して疎結合に保つ。

サンプルコード

class OrgDTO {
  constructor(contents) {
    this.orgId = this.parseIntValue(contents["orgId"]);
    this.email = contents["email"];
    this.name = contents["name"];
  }

  parseIntValue(value) {
    return value ? parseInt(value, 10) : null;
  }
}

function main() {
  // サンプルデータ(外部から取得する想定のデータ)
  const contents = {
    "orgId": "1",
    "email": "aaa@example.com",
    "name": "test"
  };

  // DTOクラスのインスタンスを生成
  const result = new OrgDTO(contents);
  console.log("result", result);
}

main();

例えば、このように入力値の orgId が文字列として与えられる場合、parseIntValue 関数を利用して文字列型を Int 型に変換することができます。このように、生のデータをアプリケーション層で扱いやすい形に整形することで、コードの可読性と保守性を大きく向上させることができます。

また、データの取り扱いに役割を限定することで、ドメインロジックやビジネスロジックとの結合度を下げることができ、システム全体の見通しが良くなります。結果として、その後の処理でデータを扱う際に余計な手間が減り、開発効率が向上しそうです。

まとめ

  • DTOクラスは、「データをやり取りするだけ」のオブジェクト
    • ロジックを持たず、転送用フィールドとアクセサだけを持つのが基本
  • レイヤー間の依存度を下げ、コードの可読性を上げるために利用
    • 疎結合を保ち、メンテナンス性を高めるのに役立つ
  • Webアプリやマイクロサービス、レイヤードアーキテクチャで使われることが多い
    • リクエスト/レスポンスやDBとのやりとりなど
株式会社フォトラクションでは一緒に働く仲間を募集しています

www.wantedly.com