Slide 1

Slide 1 text

GO BEYOND TOGETHER Chief Creative Officer BABY NAIL EXILE EXILE THE SECOND 三代目 J SOUL BROTHERS from EXILE TRIBE GENERATIONS from EXILE TRIBE THE RAMPAGE FANTASTICS from EXILE TRIBE BALLISTIK BOYZ from EXILE TRIBE 劇団EXILE DEEP SQUAD DOBERMAN INFINITY Dream Ami Dream Shizuka Happiness 伶 PKCZ DJ DARUMA m-flo MIYAVI Crystal Kay JAY’ED Leola MABU Girls² iScream Lucky² PSYCHIC FEVER ACTOR MODEL ATHLETE AMAZING COFFEE kotlin-resultを用いて 鉄道志向なエラーハンドリングを 試みる Yoshikane Fumitaka, @black_bracken CA.aab #2

Slide 2

Slide 2 text

GO BEYOND TOGETHER 自己紹介 R 吉兼 史崇 (わらびF R @black_bracke5 R CL事業本部でAndroi# R 最近はGlanceでウィジェットを書いています

Slide 3

Slide 3 text

GO BEYOND TOGETHER agenda Kotlin標準ライブラリのResult michaelbull/kotlin-result 鉄道志向プログラミング(ROP)とは bindingを使った構文糖 技術の選定と注意点

Slide 4

Slide 4 text

GO BEYOND TOGETHER Kotlin標準ライブラリのResultのおさらい ˆ 例外をキャプチャし、成功or失敗したことを1クラスで値として表現すx ˆ Result = T | Throwablr ˆ エラー側の型をジェネリクスで持たなu ˆ (Androidなどに限らない) Kotlinに向けた、成功と失敗のいずれかの型として有– ˆ kotlinx.coroutinesのContinuation#resumeWithなどで利用されていx ˆ sealed classではない (1.7 時点; Result.Failureをvalueに入れたvalue class‘ ˆ onSuccess, onFailureなどのメソッドを使う前8 ˆ ドメイン固有のエラー状態を表現する必要があるなら、Resultの代わりに独 自にsealed classで定義することが推奨されている

Slide 5

Slide 5 text

GO BEYOND TOGETHER michaelbull/kotlin-result V Result型を提供するライブラリ (Eitherh V エラー側の型を持g V OkもしくはErr型 (sealedh V 標準のResultと同様のメソッドを持g V 加えてflatMapを持g V エラー型の上限に制約がなq V Exceptionに制限されなq V bindingという機x V 後述

Slide 6

Slide 6 text

GO BEYOND TOGETHER agenda Kotlin標準ライブラリのResult michaelbull/kotlin-result 鉄道志向プログラミング(ROP)とは bindingを使った構文糖 技術の選定と注意点

Slide 7

Slide 7 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) s 正常処理に主軸を置いたエラーハンドリングへのアプローq s 関数型プログラミングの一部を簡単に砕いたもp s 複数のエラー状態も型を保R s Scott Wlaschinが提 s Domain Modeling Made Functionalの著者 s 正常な処理に主軸を置くとž s 手続き的な記述では、各処理毎に問題があればそれぞれエラーハン ドリングを行い、早期リターンや例外の送出を行² s ロジックを正常なルート(= happy path)に集中して記述することで 可読性を高められないだろうか?

Slide 8

Slide 8 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) t 簡単のために以下のような具体例(ユースケース)を考えw ur 現在のユーザを取得し認可されているか確b –r ユーザーIDをもとにデータを取e Dr 取得したデータを保d vr 取得したデータを返’ t まず手続き的 t エラーハンドリングなし

Slide 9

Slide 9 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) @ エラーハンドリングをしていG @ 本質的な処理よりエラーハンドリ ングの方が多い エラーハンドリンr @ (re) throi @ retura @ etc

Slide 10

Slide 10 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) User#isAuthorized() SampleUsecase#invoke() on success on failure RemoteRepository#fetchInfo() LocalRepository#save() Output Input 手続き的

Slide 11

Slide 11 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) User#isAuthorized() SampleUsecase#invoke() on success on failure RemoteRepository#fetchInfo() LocalRepository#save() Output Input User#isAuthorized() SampleUsecase#invoke() on success on failure RemoteRepository#fetchInfo() LocalRepository#save() Output Input 手続き的 鉄道志向 エラーが起きても連結できれば良い

Slide 12

Slide 12 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) D 前提: 関数合成についG D 複数の関数を組み合わせることで新たな1つの関数に合成する function1(apple): Banana function2(banana): Cherry

Slide 13

Slide 13 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) D 前提: 関数合成についG D 複数の関数を組み合わせることで新たな1つの関数に合成する

Slide 14

Slide 14 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) D 前提: 関数合成についG D 複数の関数を組み合わせることで新たな1つの関数に合成する fun newFunction(apple): Cherry = function2(function1(apple))

Slide 15

Slide 15 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) p 各メソッドがResultを返すようにすれば、それらを合成して1つのユースケースに出来そ™ p 関数の連結になるので、正常なルート(=処理の実態)に集中して記述でき– p エラーが発生しても、型から分かるのでバイパスするような形にすればO8 p そのユースケースもResultで返してあとでハンドリング User#isAuthorized() SampleUsecase#invoke() on success on failure RemoteRepository#fetchInfo() LocalRepository#save() Output Input

Slide 16

Slide 16 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) i 実際にこれに合わせてプログラムを書いてみI i 残念ながらコンパイルは通らなƒ i fetchInfoはUserIdを受け取るのであって、Resultを受け取る訳ではなƒ i 変換も出来ない

Slide 17

Slide 17 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) i 実際にこれに合わせてプログラムを書いてみI i 残念ながらコンパイルは通らなƒ i fetchInfoはUserIdを受け取るのであって、Resultを受け取る訳ではなƒ i 変換も出来ない 型が合わない

Slide 18

Slide 18 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) ‚ 型が合わない理g ‚ fetchInfo()などのメソッドは、Resultを返すことで出力が2路線に対応し` ‚ しかし入力は1路線(正常値のみ)にしか対応していなh ‚ エラーを受け取り、その時には何もせずただ後ろにエラーを返したh ‚ しかしメソッドすべてが引数にResultを受け取るのは非現実的では? この路線に対応する必要がある Result Result Result T

Slide 19

Slide 19 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) もし正常な値なら  その値をもう1段ネストした形に変形して潰して返す もし異常な値なら  何もせずそのまま返す もし異常な値なら  何もせずそのまま返す ...ようなメソッドがResultにあれば対応可能 Result.func(f: (T) -> Result): Result

Slide 20

Slide 20 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) G ListのflatMapが同じような機能を持ってい‚ G map: (T) -> Rを受け取り、ListをListに変w G 空なら何もしなR G flatten: List>をListに変w G flatMap: (T) -> Listを受け取り、ListをListに変換

Slide 21

Slide 21 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) G ListのflatMapが同じような機能を持ってい‚ G map: (T) -> Rを受け取り、ListをListに変w G 空なら何もしなR G flatten: List>をListに変w G flatMap: (T) -> Listを受け取り、ListをListに変換 G Resultにもありまp G map: (T) -> Rを受け取り、ResultをResultに変w G flatMap: (T) -> Resultを受け取り、Resultを Resultに変換 G flatMaœ G 入れ子構造に変換して、変換後に潰p G Listであれば空なら何もしなR G ResultであればOk型でなければ何もしなR G (...monadic!)

Slide 22

Slide 22 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) User#isAuthorized() SampleUsecase#invoke() on success on failure RemoteRepository#fetchInfo() LocalRepository#save() Output Input

Slide 23

Slide 23 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) 5

Slide 24

Slide 24 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) 5

Slide 25

Slide 25 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) f エラー型につい™ f 今回は例のために文字列にしてい` f 実際はドメイン固有なエラーを表現出来たほうが良r f sealed interfaceでUsecase/Repository等にそのエラーを定y f mapEitherなどを使ってレイヤー毎にエラー型の変換を行i f やり過ぎると無意味なボイラープレートになる

Slide 26

Slide 26 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) g 実装とエラーハンドリングをより分離するアプロー‘ g 成功と失敗のレールで処理を連結すy g flatMapでResultの結果を連結して関数を合成すy g エラーの種類も型を保ったまま伝播すy g Androidでの適用範囲 g (← Usecase) ← Repository ← DataSource

Slide 27

Slide 27 text

GO BEYOND TOGETHER agenda Kotlin標準ライブラリのResult michaelbull/kotlin-result 鉄道志向プログラミング(ROP)とは bindingを使った構文糖 技術の選定と注意点

Slide 28

Slide 28 text

GO BEYOND TOGETHER 鉄道志向 (Railway Oriented Programming) 6 省略

Slide 29

Slide 29 text

GO BEYOND TOGETHER 技術の選定と注意点 m 鉄道指向プログラミングの採用についx m Kotlinのエラーハンドリングにおける銀の弾丸ではな’ m KEEPでは、標準ライブラリとしてROPは採用しな’ m 不必要なケースで使うとそれは例外の再発明にな2 m 想定できないエラーは例外で扱G m エラーの内容が本当に利用する時に必要か考えるこu m 各エラー毎にドメインモデル(sealed class)が必要かf m 目的と手段を履き違えないよう

Slide 30

Slide 30 text

GO BEYOND TOGETHER 技術の選定と注意点 d CLで跋扈するデータ型た` d Arrow-kR d Try (removed in latest$ d Optio% d Kotlin-stdli# d Result d ライブラリの選定は慎重l d 用途に対して適切e d 特にデータレイヤ(~=ドメイン層)など でも使われる場v d 自前で定義しても良i d KMMへの移行に合わせて排除

Slide 31

Slide 31 text

LIVE CAST ONDEMAND PROGRAM LIVE STREAMING COMMUNITY ありがとうございました V 参考資d V https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.m4 V https://github.com/michaelbull/kotlin-resulg V https://github.com/swlaschin/RailwayOrientedProgramminT V https://fsharpforfunandprofit.com/ropX V https://fsharpforfunandprofit.com/posts/recipe-part2X V https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/