NO IMAGE

適切なコード共通化のための目安になる Tell, Don’t Ask の標語

NO IMAGE

 Tell, Don’t Ask は読みやすく、変更しやすいコードを書くための標語の一つです。DRY (同じコードを繰り返し書かない)、低結合(他モジュールへの依存を少なくする)、高凝集(関連のある情報をまとめる)といった原則を実現するするための足掛かりになります。
TellDontAsk
Tell, Don’t Ask
 この標語に関する悪い例、良い例が次です。

// 悪い例
/** @var User $user */
if(isset($user->address)){
  $streetName = $user->address;
}else{
  $streetName = '通り名がありません';
}

class User
{
  // 何か色々
}
// 良い例
$streetName = $user->streetName();

class User
{
  public funtion getStreetName()
  {
    if(isset($user->address)){
      $streetName = $user->address;
    }else{
      $streetName = '通り名がありません';
    }
    
    return $streetName;
  }
  // 何か色々
}

 悪い例は User インスタンスの変数である $user のプロパティを元にその場で条件分岐を使って変数 $streetName を生成しています。良い例は $user の元クラスである User の中に $streetName の元になるメソッド getStreetName を持っており、それを用いて変数 $streetName を作っています。
 Don’t Ask というのはオブジェクトに対してあれこれと聞いて手元でロジックを組み立てることをするな、Tell はオブジェクトに対してロジックの結果を聞け、ということです。
 Tell, Don’t Ask に従うことによって同じロジックを複数回用いる時、毎回インスタンスからそのロジックの結果を聞くコードを書くことになります。例えば次の様になります。

public function showProfile(User $user)
{
  $streetName = $user->streetName();
  // 何か色々
}

/**
 * @param  array<User>  $users
 */
public function dumpUsers(array $users)
{
  foreach($users as $user){
    $streetName = $user->streetName();  
  // 何か色々
  }
}

 もし悪い例のまま↑の例を実現しようとした場合、別の場所に同じロジックが記述されることになります。こうなると変更漏れを起こしやすくなる他、コードが長くなって読みにくくなります。
 Tell, Don’t Ask はあるロジックの分岐に関わる条件の元になるデータをどのクラスが持つかを判断する基準にも使えます。例は単に $user->address の有無での分岐でしたが、分岐の条件が複雑になった時は便利です。これが働くとあるクラスと他クラスの依存が減り、あるクラスに関わるべきデータが一か所に凝集されます。
 Tell, Don’t Ask は原則の実現のための標語の一つ程度であり、原則のためにより良い方法がある時も少なくなく、破った方がお得な場合がわりとあります。とはいえ何んとなしに好き勝手コーディングするよりは整理されたコードになりやすいので頭の片隅にでも覚えておくと良さそうです。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG