永続化処理の返り値が、値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; } } }
ほかに考えられる選択肢はおそらく二つ。
- 成功時: 保存されたオブジェクト, 失敗時: null(上記サンプルのパターン)
- 成功時: 保存されたオブジェクト, 失敗時: false
- 成功時: true, 失敗時: false
それぞれの特徴は以下になると思われる。
1.
- 保存されたオブジェクトを再利用しやすい
- 特に関連テーブルがあって、外部キーにサロゲートキーを使用している場合は必要になると思う。
- 返り値の型が定義できる。2.だとUser|falseになってしまい、タイプヒンティングを実装できない。
2.
- であげた、型が定義できないというデメリットはある。
- 処理の失敗という意味をよく表現するのは, falseを返す方に思える。
- つまり、1.は保存処理と取得処理をしてしまっており、責務をもちすぎなのではないか。
- だとすれば、2.の処理も同じ問題を抱える。
- ただし、同じく「オブジェクトを再利用しやすい」というメリットも残る。
3.
- 2.であげた問題点を解決する方法。すなわち、保存処理のみをしており、保存処理が成功したか失敗したかを返す。
まとめ
自分としてはオブジェクトの再利用をしたいことが多いので、1.がよいのではないかと思っています。 2.は中途半端だしあんまりよくなさそう。
3.を使うとしたら、データが独立しているログ系の処理に使うのがいいかもしれない。
というわけで、タイトルにある問いについてはNoと答えることができるように思う。
補足
あまり詳しくないが、3のような、状態遷移が受理された/受理されなかったのみを出力する機械を「有限オートマトン」と呼ぶそう。言われてみれば、この処理をリソースの状態遷移と考えることはできると思う。 とりあえずここまで。