AnDeriensのブログ

個人的なブログです

リポジトリ層のinsert/update処理の返り値

永続化処理の返り値が、値orFalseになるのはいい実装といえるか?

単純なUserモデルの値を永続化する処理を考える。 このメソッドで、どういった値を返すのが適切なのかいまいち答えが出ない。

たまに、成功したら保存したオブジェクト、失敗したらfalseが返ってくる処理を見かけることがあり、これがいい実装なのかということもよくわからないので、一度落ち着いて考えてみようと思った。


とりあえず、暫定的に自分のなかで出している答えは以下。(サンプルコードはささっと書いているだけなので、動作確認等していません。)

<?php

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
   // 省略
}

class UserRepository
{
  public function save(array $values): ?User
  {
    // 保存処理
    $user = (new User())->fill($values);
    $result = $user->save();

    // 結果を返す
    if ($result) {
        return $user->fresh();
    } else {
        return null;
    }
  }
}

ほかに考えられる選択肢はおそらく二つ。

  1. 成功時: 保存されたオブジェクト, 失敗時: null(上記サンプルのパターン)
  2. 成功時: 保存されたオブジェクト, 失敗時: false
  3. 成功時: true, 失敗時: false

それぞれの特徴は以下になると思われる。

1.

  • 保存されたオブジェクトを再利用しやすい
    • 特に関連テーブルがあって、外部キーにサロゲートキーを使用している場合は必要になると思う。
  • 返り値の型が定義できる。2.だとUser|falseになってしまい、タイプヒンティングを実装できない。

2.

    1. であげた、型が定義できないというデメリットはある。
  • 処理の失敗という意味をよく表現するのは, falseを返す方に思える。
  • つまり、1.は保存処理と取得処理をしてしまっており、責務をもちすぎなのではないか。
  • だとすれば、2.の処理も同じ問題を抱える。
  • ただし、同じく「オブジェクトを再利用しやすい」というメリットも残る。

3.

  • 2.であげた問題点を解決する方法。すなわち、保存処理のみをしており、保存処理が成功したか失敗したかを返す。

まとめ

自分としてはオブジェクトの再利用をしたいことが多いので、1.がよいのではないかと思っています。 2.は中途半端だしあんまりよくなさそう。

3.を使うとしたら、データが独立しているログ系の処理に使うのがいいかもしれない。

というわけで、タイトルにある問いについてはNoと答えることができるように思う。

補足

あまり詳しくないが、3のような、状態遷移が受理された/受理されなかったのみを出力する機械を「有限オートマトン」と呼ぶそう。言われてみれば、この処理をリソースの状態遷移と考えることはできると思う。 とりあえずここまで。