2024.12.10
“放置系”なのにサイバー攻撃を監視・検知、「統合ログ管理ツール」とは 最先端のログ管理体制を実現する方法
Scala ZIOをバッチ処理で使ってみた (全1記事)
リンクをコピー
記事をブックマーク
リチャード伊真岡氏:「Scala ZIOをバッチ処理で使ってみた」という発表をします。リチャード伊真岡と申します。マーベリック株式会社というところで働いています。
今日一番大事なことを最初に言おうと思います。発表の内容はどうでもいいので、私の名前だけ覚えていってもらえば満足です。
(会場笑)
ということで大事なことは済んだので、本題に移っていきたいと思います。
Scala ZIOの話なんですけど、この人はScalaのZIOというライブラリの作者でJohn De Goesさんという人です。
この関数型の最大のメリットの1つのtestabilityの話をブログでしているんですね。「"Functional programming ordinarily gives us the incredible ability to easily test our software."」。けっこう強いステートメントですね。
もう1人のDaniel Spiewakさん。
関数型界隈ですごく有名な方で、この人もすごく強いことを言っています。「"I would argue that the whole point of functional programming in general is testing"」と、かなり強いことを言っています。
というわけでみなさんもご存知かと思いますが、純粋関数はtestabilityが高い。インプットはだいたいアウトプットが出てくるだけなので、テストを書く時にはその予測されるアウトプットと比べればよいと。
ただ、実際のプログラムは副作用が入ってくるので「副作用はテストをするのが難しいですね」という話になります。
副作用を含むコードがあって、副作用と純粋関数呼び出しが混ぜこぜになるとテストはやりにくいので、ここで関数型のテクニックを使いましょう!
そうすると、ZIOもこの流れに沿うんですけど、descriptionとinterpreterの分離ということでいきます。
色分けをすると、descriptionというのはScalaでやるとfor文をよく使うんですけど、プログラムを実際に走らせるコードじゃなくて、「こういう処理をします」という記述、descriptionだけをやります。
この部分はfor文を通過しただけではプログラムがは走らないんですね。このfor文をprogramDescriptionというvalに束縛して、unsafeRunというところに渡して初めてプログラムが走るというテクニックを使って書きます。
上のほうでプログラムを記述するdescriptionである木構造のようなものを作っています。それで、それを走らせて初めて副作用が発生するということです。
ちょっとここで動くから見てもらいたいんですけど……。
(アニメーションが流れる)
こういう木構造が出てきて、これをランタイムと組み合わせると初めて動きます。いいでしょう?
(会場笑)
次のスライドに行くかな? 行かない?
(会場笑)
ごめんなさい。次のスライドに行きますね。動画に凝り過ぎてスライドが……つい動かしたくなっただけです。ごめんなさい。これ1時間半ぐらい掛けて作ったんです。
(会場笑)
つい動かしたくなっちゃいました。ごめんなさい(笑)。
こういうdescriptionとinterpreterを分離してコードを書くテクニックで、Free MonadやTagless Finalと呼ばれるテクニックがあります。ZIOもその流れに沿っています。
なんですけど、とくにTagless Finalについて、ZIOの作者の人のJohn De Goesさんがちょっと批判をしているんですね。
「テストはそんな簡単じゃないよ、綺麗にならないよ」と。testabilityが良くならないという話をしていました。
なぜかと言うと、さっき言ったようにdescriptionを関数型で記述する、つまりツリー構造のデータを作ってもそのツリー構造が期待したアウトプットと比較できないわけですね。
例えばprintln、出力をするというコードが含まれる副作用を書いたとして、期待されるコードと動作とどう比較するかみたいなことがあって、それが比較できない。それでこういう話のブログを書いて「ちょっと問題がありますよ」みたいな話をしています。
そこで「ZIOが良いんじゃないか」という話をこの作者の人がしています。
Tagless Finalなどに比べてtestabilityが向上するんじゃないかという話をしていて、かつ、非関数型プログラマにも馴染みやすいというのは、このZIOというライブラリの大きな開発動機の1つになっています。
これを我々マーベリックがバッチ処理のところで使ってみたという話をしていきます。
ZIOの入門みたいなところで、こういう戻り値型がたくさん出てくるわけですね。R、E、Aとありまして、右からいきます。
右のAが、処理が成功したときに返ってくる型です。次の真ん中のEはFailure Type。これはThrowableであったり、それを継承したものであったり、処理が失敗したときのExceptionが起こったときに投げられる型です。最後の左はEnvironment Typeと、ZIOの中では呼んでいます。ZIOってDependency Injectionを関数型と組み合わせることができて、そのDependency Injectionを表す型になります。ちょっとこれは後で説明します。
それで、我々が誇る素晴らしいプロダクトの「Cirqua」というものがあります。
Cirquaはインフィード広告と呼ばれるプロダクトです。
せっかくなのでプロダクトの動きを見ていきます。スマホとかでWebページを表示すると、広告が表示される領域があるんですね。ここで読み込まれた広告配信サーバに要求を送って、広告が返ってきます。
広告が表示されたあとにクリックされたら、その後トラッキングサーバというところにそのクリックされたというのが送られて、広告主ページでさらに商品を買うなどのユーザーの行動が継続されたら、それもトラッキングサーバに送られます。
トラッキングサーバというのは、そういうユーザーの行動を逐一計測しております。当然計測したらデータ処理の処理フローに流すわけですね。
最終的には、AWSのAthenaを使ってクエリを走らせて集計しています。このAthenaのクエリはバッチ処理で走らせておりまして、このバッチ処理のコードはCirquaという我々のプロダクトの中では独立しています。独立をしているので、ZIOという新しいライブラリを試すのにも良いだろうということで、我々はまずはここから導入をしてみました。
それで、さっき言ったZIOの戻り値型のEnvironment Type、ここはDIを使います。ここをうまく使いこなすことがキーになってくる感じなんですね。ここを説明していきます。
DIを使っていくので、まずはDIすべきコンポーネントを特定していきましょう。
今回はいくつか例を挙げていますけど、ConfigであったりAWSを使うのでS3であったり、あるいはデータベースでAthenaとか、そういうDIとして使うコンポーネントを特定します。
ZIOのブログとしても例として出てくるんですけど、cake patternを使ってDIをやっていきます。
cake patternを少し紹介します。サービスと呼ばれるトレイトを作って、それを囲むコンポーネントと呼ばれるようなトレイトを付けます。
そのプロダクションの実装とテストの実装を作っていきます。
ちょっとZIOのはいろいろあるんですけど、だいたいこんな感じでやるのがcake patternです。S3の場合だったらS3のコンポーネントとか、AthenaとかConfigとかいろいろなコンポーネントを積み重ねて、右のコードにあるextendsでwithとやって、cakeが層のように重なっていくのでcake patternと呼ばれています。
僕的にはどちらかと言うとおまんじゅうに見えるので、おまんじゅうっぽく「アッタカイヨー」という感じですね。
あんまりウケない。
(会場笑)
これはバッチ処理の中のコードです。
ちょっと省略してあまり詳細を載せていないですけど、loggerの処理を呼び出してデータベースコンポーネントの処理を呼び出す。1つ1つのコンポーネントがさっき言ったDIで使うコンポーネントですね。それで、Athenaのコンポーネントを呼び出している。
この戻り値型、普通は書かないところは書かなくてもいいんですけど、あえて書くとさっき言ったようなコンポーネントで重なったcakeがEnvironment Typeになっているわけですね。
Throwableだったりのエラーの型があって、最後のBatchResultというのが成功したときに返ってくる型です。この1つ1つの構文の中の処理がまたfor文で入れ子構造になっていて、こういうかたちで書いていくことができます。
ちなみに「cake patternはアンチパターンじゃないのか」と言う人がScala界にはよくいるんですけど、ZIOの作者によると、右下の小さい構文に入ってくるとwithでくっついているcakeの層が薄くなるので、小さいfor文の中を見ればそんなに依存性が大きくなくてリファクタリングもしやすい。だから「そんなにアンチパターンじゃないだろ」というのが作者の見解です。
ここまでの話の中でEffect(副作用)が発生するところはDIを使うと。DIを使ってテストをするのでtestabilityが向上するという話をしたんですけど、ちょっとここで私はよくわからなくなりました。というのは、関数型プログラミングでtestabilityが向上するという話で2番目に出てきたDaniel Spiewakさん。
これは動画の中から抜き出したんですけど、この人、testabilityの向上の話をしているのはAlgebraic Laws、代数的規則と言ったらいいんですか? その話をしていて、別にDIの話とかはしていないんです。
プログラムが満たすべきルールを型クラスが満たすべきルールとして定義しているみたいな話があったんですけど。
これはすごいツッコミ待ちのスライドなので、ぜひ強い人からツッコんでほしいんですけど。
そういう型クラスが満たすべきルールを、うまく数学的に定義して、いい感じにテストをしようみたいな話をしていたはずなので、これはTagless FinalとかZIOがその副作用に対する数学的規則を定義できないという意味では、ZIOはTagless Finalと変わらないので、これでZIOによってTagless Finalよりtestabilityが向上するというのがよくわかりませんでした。
この話は実はZIOの作者の人もしていて「"Tagless-final type classes do not,in general, have algebraic laws."」。代数的規則はTagless Finalでは成り立たないという話をしています。
ここまではわかるんですけど、私がこの先でわからなかったのは「Tagless FinalでZIOに変えて使ってもこれは一緒だから、なぜtestabilityが向上するのかわからなかった」という話なんですね。
今までの話で出てきたことをまとめます。
ZIOはおもしろいライブラリだと思うんですけど、testabilityという1点に関してはちょっとTagless finalとFree Monadに比べて良いところがあるというのを理解できませんでした。なのでツッコミというか教えてくれる人がいたらうれしいなという感じなんですけど。
なので、ZIOでどうやってテストをうまく書くかというと、DIの使い方とかモックの使い方となると、それは関数型のメリットなんだろうか。関数型のメリットではなくて、それぞれのDIの使い方とかテクニックとかそういう話になってしまう気がしました。
テストという点から離れると、ZIOには他にもメリットがたくさんあるライブラリなので、非関数型プログラムよりも馴染みやすくて、それ以外のメリットあるという話ならZIOの導入の動機にもなるということで、ここでZIOの他のメリットを……まとめる時間がなかったので、すみません。ここでトークを終わります。
(会場笑)
ありがとうございます。
(会場拍手)
関連タグ:
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
2024.12.09
10点満点中7点の部下に言うべきこと 部下を育成できない上司の特徴トップ5
2024.12.09
国内の有名ホテルでは、マグロ丼がなんと1杯「24,000円」 「良いものをより安く」を追いすぎた日本にとって値上げが重要な理由
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.12.10
職場であえて「不機嫌」を出したほうがいいタイプ NOと言えない人のための人間関係をラクにするヒント
2024.12.12
今までとこれからで、エンジニアに求められる「スキル」の違い AI時代のエンジニアの未来と生存戦略のカギとは
PR | 2024.11.26
なぜ電話営業はなくならない?その要因は「属人化」 通話内容をデータ化するZoomのクラウドサービス活用術
PR | 2024.11.22
「闇雲なAI導入」から脱却せよ Zoom・パーソル・THE GUILD幹部が語る、従業員と顧客体験を高めるAI戦略の要諦
2024.12.11
大企業への転職前に感じた、「なんか違うかも」の違和感の正体 「親が喜ぶ」「モテそう」ではない、自分の判断基準を持つカギ