-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
どこまでResult/Eitherを使うべきか?思考 #42
Comments
try/catchのデメリット可読性が落ちる(いちいちチェックしてるし) |
あー、いわゆるユースケース駆動開発本にある「雨の日」みたいなケースをResult/Eitherの左型として扱うのかな。。?
そうなってくると、全てのエラー定義にはUnexpectedはありえなくなりそう。。 それは例外としてthrowして上で必要な箇所(多分一番上)でハンドリング
|
もし 検査例外・非検査例外とかで区分するのではなく、 |
これがもし、例外が存在しない言語なら、Unexpectedを定義する必要があるかも |
Rust/Goでいうpanicは not (Java/Kotlinだとthrow) それをある程度仕組みで検知できそうか。。?もしかしたらinfra層だけになるかもしれない? |
Resultみたいな仕組みが無い言語において、 |
仮にそうだとすると、RubyとかJavaにおいて、 |
「良いコード・悪いコード」では いやこれをチェック例外として投げればなんとかなるかもだけど、それの使い分けが難しいなー
的な? |
ドメインエラーって言葉は一般的じゃなかったので、どこかで修正が必要そう ドメインモデリングされたエラー、エラーモデル? ==== -> ビジネス例外 として記述する 言葉のチョイスは「プログラマが知るべき97のこと」 21:技術的例外とビジネス例外を明確に区別する ==== 例外設計における大罪 p.29 https://www.slideshare.net/t_wada/exception-design-by-contract -> 準正常系 |
Against ROP-1
引用元 解釈エラーが起きた場所などを解析したいなら、そこはResultを使うべきではない
これが結果として一致しそう (例外があればしょうがないけど、panic的なやつがあればよいか) |
Against ROP-2
引用元 解釈
特に後者は、そうなんだよな。。 |
Against ROP-3
引用元 解釈
|
Against ROP-4
引用元 解釈
|
Against ROP-5
引用元 解釈
んー、んー、んー 正しいそうな感じはするけど、ハンドリングしたいなー。。。それを抽象化するのはいい気がするんだよなー(Failedとして抽象化して上に渡せばよくない?そうするとスタックトレースがなー、スタックトレースを読み解きたくないなー)
それはそうかもしれない。。 try/catchのデメリットとして
と書いた 無いなら、無いで読みやすいではある |
アプリのエラー(大体データ不整合、それが永続化前or永続化後でログレベルは変わるだろうけど) と システムのエラー を分けようということだとは思う |
Against ROP-6
引用元 解釈
(この辺はビジネスロジックエラーを定義はするが、ロジックとしてはInfra層にもっていけば良さそうな感じはする) そうなると、インフラ層が返すエラー型は純粋なビジネスロジックエラーがいいかなー。。? |
Against ROP-7
引用元 解釈
|
Against ROP-8
引用元 解釈
嫌だ NULLにNULL以上の別の意味をもたせてしまうから駄目であって、それを検知する術が人の技術に依存するなら、まずそれをやめたい 宣言的パラダイムを導入することで、考慮漏れを機械的に発見できる方が、中長期的に見て保守性が高いと信じている あーでもNULLを宣言的にハンドリングを強制できるなら、ありなのかな? NULLも論理型の一つ的な?それはNULLか?Noneにならない? |
あ、今気づいた。。。 Domain Modeling Made Functional by Scott Wlaschin 著者と記事書いた人が同じじゃん |
引用元 例外設計における大罪の29p 解釈特になし ビジネス例外を準正常系と言い換えるか |
大罪1:無視 参考 |
解釈過剰防御への対策である「契約による設計」 アプローチとしては ドメインルールが保証された、ドメインオブジェクトであることが契約の事前条件でなかろうか つまり、引数の型チェック。その型は基本ドメイン固有型である。ことを保証するとなんとなりそう Rubyだとどうすべきかな。。?全部事前契約は出来てる前提??いや例外として投げちゃだめな場合多そうだな? チェックが必要か?謎い。。 Stringプリミティブな場合。。どうしようか 内容によるか |
引数として渡した値・オブジェクトは全て事前条件を満たしたと見るべきか? |
あー、ドメイン固有型じゃなくても事前条件を満たしているかをチェックしてもいいのか そしてそれを、早期リターンしてもよいと |
Rubyだと毎回メソッドに begin/end で事前条件のチェックが必要か? Rails(OSS)とかではそうなってるようには見えない。。つまり契約プログラミングはしていない?それともしている? |
いやもう、Rubyでは一旦考えを放棄 |
入門例外:Haskellの例外
引用元 https://qiita.com/Kokudori/items/3a953c00012408f76ab9#haskell%E3%81%AE%E4%BE%8B%E5%A4%96 解釈あれ?まさにこういうことをやれということでは。。? |
自分なりのまとめ(仮)
自分が指す言葉
※UCDD本:UseCaseDrivenDevelopment本:ユースケース駆動開発実践ガイド 契約プログラミング的な文脈
優先度
参考 |
テストの文脈でよく使われる、正常系と異常系について難しくしている原因:自分が指している「準正常系」と「異常系」をまとめているところだと思った NG
OK
要は「異常系」ってひとくくりにしてはいけない 経験的な話見てきたテストで「異常系」って書いてあるやつほとんどが「準正常系」な気がする 最終的にお客さんから見ると「準正常系」と「異常系」は同じになりやすい。。ここが辛いところかもしれない。。 蛇足の蛇足この辺考えてたら、JSTQBの世界に入った。。 |
ドメインに固有の型のエラー ケースと無効な状態を表現する例題:銀行口座からの出金(WIthdrwal) F# type MoneyWithdrawalResult =
| Success of amount:decimal // OK
| InsufficientFunds of balance:decimal // 残高不足
| CardExpired of DateTime // カードの有効期限切れ
| UndisclosedFailure // 原因不明の失敗 Kotlinで表現すると? パターン1 sealed interface MoneyWithdrawalResult {
data class Success(val amount: Long) : MoneyWithdrawalResult
data class InsufficientFunds(val balance: Long) : MoneyWithdrawalResult
data class CardExpired(val date: Date) : MoneyWithdrawalResult
object UndisclosedFailure : MoneyWithdrawalResult
} パターン2 sealed interface MoneyWithdrawalResult {
sealed interface Ok : MoneyWithdrawalResult {
data class Withdrawn(val amount: Long) : MoneyWithdrawalResult
}
sealed interface Error : MoneyWithdrawalResult {
data class InsufficientFunds(val balance: Long) : Error
data class CardExpired(val date: Date) : Error
object UndisclosedFailure : Error
}
} ん、、、普通だ パターン1、2の書き方ができることにあとになって気づいたけど、これだとArrowって不要になる? |
3つ目重要とか書いてある Kotlinとかでいうと 「try/catch という定型句を減らすことができる」という解釈をした |
取得した記事が「お気に入り済み」か「お気に入りではない」の区別をする時、 ログイン済みのユーザーが存在していることが前提となっている この時、渡されたユーザーIDが存在しているor存在していないことを型で表現したいが、とても難しいと考える 仮に「存在しなかった時」それは
どちらか?少なくとも「2. 技術的例外」にしたくない感じがある では「1. ビジネス例外」か?と聞かれると、ぐぬぬ感ある とりあえず今は「ビジネス例外」とする。。。 |
ビジネス例外 -> 準正常系 ってすると後者感ある ぐぬぬ |
https://twitter.com/j5ik2o/status/1468515811438788610 ErrorとDefect(欠陥)は異なる Resultで返す == リカバリ 仕様として欠陥扱いせず、Errorとしてハンドリングしたい => 設計の段階で精査 |
panic!すべきかするまいか on The Rust Programming Language 日本語版 これはpanicで良い例 use std::net::IpAddr;
let home: IpAddr = "127.0.0.1".parse().unwrap(); |
Error, Defect, Fault, Failureの定義と解釈 これでも
準正常系(ビジネス例外)と異常系(技術的例外)と2分類は全然していない。。(全部3つに近い) こちらも3つにするべきか |
アイディア
|
ISTQBより
実際にテストする時。。(理想形として) Success:単体テストする、E2Eする |
arrow.core.Either 使い方メモと、初めてのKotlinコードリーディング > 2. Either#fx UZABASEさんのテックブログにて少し古いらしいが Arrow.kt のEitherの使い方で、左型をExceptionにしている。。。 そしてEither.fxっていうのを使ってtry/catchを完全に消している? ただ、bindで早期リターンまがいなやつができるのは魅力的 Scalaのforがそんな感じじゃなかったっけ ムム、(技術的例外)異常系と(ビジネス的例外)準正常系の扱いについて、振り返り・再検討するべきか 🤔 UZABASEさんはNewsPicksの課金基盤でArrow.ktを利用しているらしい 👍 |
4種類ほしくなってきた。。。 正常系:OK
Kotlinのデストラクタがもっと強力になってほしすぎる |
Java/Kotlinで書くと、非検査例外をどこまでtry/catchするのか、むしろ全くしないほうがいいのか、全部するのか
過剰防御するのかしないのか
オリジナル?(F#)
Railway Oriented Programming
Against Railway-Oriented Programming
その他資料
t_wadaさん: 例外設計における大罪
tasuwoさん: 例外設計における大罪
Kokudoriさん: 例外 Advent Calendar 2014
途中で終わったらしいが、とても勉強になる(コメント含めて)
かとじゅんさん: Rustで真に安全なプログラムを書く方法
コメントまで勉強/参考になる
kawasimaさん: 例外設計
Microsoft: 例外処理
Microsoft: エラー管理
プログラマが知るべき97のこと: 21番:技術的例外とビジネス例外を明確に区別する
Bertrand Meyer 著: オブジェクト指向入門 第2版 原則・コンセプト
セキュア・バイ・デザイン 安全なソフトウェア設計の第9章: 安全性を考えた処理失敗時の対策
The text was updated successfully, but these errors were encountered: