さまざまな種類の失敗をエレガントに処理するために、メソッドのシグネチャを知りたいです。
この質問は、Scala でのエラー処理に関して私がすでに持っていた多くの質問の要約です。ここでいくつかの質問を見つけることができます:
今のところ、次のことを理解しています。
- どちらも、失敗する可能性のあるメソッド呼び出しの結果ラッパーとして使用できます
- Try は右にバイアスされたどちらかであり、失敗は致命的ではない例外です
- IO (scalaz) は、IO 操作を処理する純粋なメソッドを構築するのに役立ちます
- 3つすべてが理解のために簡単に使用できます
- flatMap メソッドに互換性がないため、理解のために 3 つすべてを簡単に混在させることはできません。
- 関数型言語では、通常、致命的でない限り例外をスローしません。
- 本当に例外的な条件に対しては、例外をスローする必要があります。これがTryのアプローチだと思います
- Throwable の作成には JVM のパフォーマンス コストがかかり、ビジネス フロー制御に使用することは意図されていません。
リポジトリ層
今、私が持っていると考えてくださいUserRepository
。はUserRepository
ユーザーを格納し、メソッドを定義しますfindById
。次の障害が発生する可能性があります。
- 致命的な失敗 (
OutOfMemoryError
) - データベースにアクセスできない/読み取れないための IO 障害
さらに、ユーザーが見つからない可能性があり、Option[User]
結果につながります
リポジトリの JDBC 実装、SQL を使用すると、致命的ではない例外 (制約違反など) をスローできるため、Try を使用することは理にかなっています。
IO 操作を扱っているので、純粋な関数が必要な場合は IO モナドも意味があります。
したがって、結果のタイプは次のようになります。
Try[Option[User]]
IO[Option[User]]
- 他の何か?
サービス層
ここで、以前に定義されたリポジトリを使用するUserService
メソッドを提供するビジネス層 を紹介しましょう。updateUserName(id,newUserName)
findById
次の障害が発生する可能性があります。
- サービス層に伝搬されたすべてのリポジトリ障害
- ビジネス エラー: 存在しないユーザーのユーザー名は更新できません
- ビジネス エラー: 新しいユーザー名が短すぎます
結果のタイプは次のようになります。
Try[Either[BusinessError,User]]
IO[Either[BusinessError,User]]
- 他の何か?
ここでの BusinessError は例外的なエラーではないため、Throwable ではありません。
for 内包表記の使用
メソッド呼び出しを結合するために for-comprehension を使い続けたいと思います。
for-comprehension で異なるモナドを簡単に混在させることはできないので、すべての操作に対してある種の統一された戻り値の型を使用する必要があると思いますよね?
現実世界の Scala アプリケーションで、さまざまな種類の障害が発生する可能性があるときに、どうやって for 内包表記を使い続けることができるのだろうか。
今のところ、for-comprehension は私にとっては問題なく機能します。すべて返されるサービスとリポジトリを使用していますEither[Error,Result]
が、さまざまな種類の障害がすべて溶け合っており、これらの障害を処理するのは一種のハッキーになります。
for-comprehension を使用できるように、異なる種類のモナド間の暗黙的な変換を定義していますか?
失敗を処理する独自のモナドを定義しますか?
ちなみに、近いうちに非同期 IO ドライバーを使用する予定です。したがって、戻り値の型はさらに複雑になる可能性があると思います。IO[Future[Either[BusinessError,User]]]
私のアプリケーションは空想的ではありませんが、何を使用すればよいか本当にわからないため、アドバイスを歓迎します。これは、クライアント側に表示できるビジネス エラーを区別できる API にすぎません。技術的なエラー。私はエレガントで純粋な解決策を見つけようとします。