Tell, Don’t Ask は、「聞くな、命じよ」と訳されることがあります。
少し強い表現ですが、要するに、オブジェクトからデータを取り出しすぎず、そのオブジェクト自身に判断させようという考え方です。
一言でいうと
Tell, Don’t Askは、データを外に取り出して判断するのではなく、責務を持つ場所に処理を寄せる考え方です。
データを持っているものが、そのデータに関する判断も持つと、変更箇所がまとまりやすくなります。
Askしすぎる例
function getShippingFee(order: Order) {
if (order.totalPrice >= 5000 && order.customer.rank === "gold") {
return 0;
}
return 600;
}
外側の関数が、注文金額や顧客ランクを聞き出して送料を判断しています。
送料ルールがいろいろな場所に書かれると、変更漏れが起きやすくなります。
Tellに寄せた例
class Order {
constructor(
private readonly totalPrice: number,
private readonly customer: Customer,
) {}
qualifiesForFreeShipping() {
return this.totalPrice >= 5000 && this.customer.isGoldRank();
}
}
function getShippingFee(order: Order) {
return order.qualifiesForFreeShipping() ? 0 : 600;
}
注文に関する判断を Order に寄せました。外側は細かい条件を知りすぎません。
メリット
| メリット | 説明 |
|---|---|
| 変更箇所がまとまる | ルールが散らばりにくい |
| 呼び出し側が簡単になる | 条件式を知らなくてよい |
| 不正な使い方を減らせる | 内部状態を隠しやすい |
| テスト観点が明確になる | 対象の振る舞いを確認できる |
オブジェクトを「データの入れ物」だけにしないのがポイントです。
使いすぎに注意
すべての処理をオブジェクトに詰め込む必要はありません。
たとえば、画面表示の都合、外部API形式への変換、DB保存の都合は、ドメインオブジェクトに入れないほうがよい場合があります。
Tell, Don’t Askは、責務の場所を考えるためのヒントです。
判断基準
- その判断は、どのデータに一番近いか
- 同じ条件式が複数箇所にないか
- 外側が内部構造を知りすぎていないか
- 名前付きメソッドにすると意味が明確になるか
- UIやDBの都合を混ぜていないか
条件式に名前を付けるだけでも、読みやすさは大きく変わります。
まとめ
Tell, Don’t Askは、データを聞き出しすぎず、責務を持つ場所に判断を寄せる考え方です。
同じ条件式が散らばっているなら、その条件に名前を付け、適切なオブジェクトへ移せないか考えましょう。