Chapter 03無料公開

Composable Architecture

Yasuhiro Inami
Yasuhiro Inami
2020.09.23に更新

それでは続きまして Composable Architecture の話をしたいと思います。
すでに何度か、 Harvest との類似点について触れていますが、
今日の発表では時間の都合上、大事なポイントだけに絞って端折って解説します。


Composable Architecture の概要はざっくりこの通りです。
基本構成は Harvest と多くの点で共通していて、主な違いとしては、

  1. マルチStore方式を採用していること
  2. Swift Case Paths という独自のPrism実装

を導入しています。

ちなみにご存知の方も多いと思いますが、このフレームワークは元々オープンソースアプリ Kickstarter-iOS で有名な Brandon Williams さんと Stephen Celis さんの2人が開発したもので、最近は Point-Free というチームで、Swiftのチュートリアル動画配信などの方面で活躍されています。


Composable Architecture の概要を掻い摘んでお話しすると、
先ほどの図のようなView階層に、今度は 各々のViewに対してStoreが紐付いています
正確には ViewStore というラッパーです。

Harvest の場合とは異なり、

  • 子のView階層はStoreの代理的な部分参照ではなく、部分データをコピーで持ち、それぞれが独立のStoreとして振る舞う
  • リアクティブに同期を取る

が異なります。


それでは、子階層のViewがアクションを発行するとどうなるでしょうか?
実はこの場合、直接最上位のStoreに送られるのではなく、一つ上の層に送り、それが伝搬していく という違いがあります。
これは、Elm Architecture とは異なり、どちらかというと React に近い世界観 です。


その後、最上位で状態を更新して、 下流にリアクティブに伝搬 していきます。
このフローによって、それぞれのStoreが同期を取るようになっています。


ただし、ここでひとつ注意点があって、一階層上にアクションを発行するということは、
それだけでやはり Reducer を通した状態更新が行われるということです。
そしてそれが下流に伝搬するロジックも持ち合わせています。


つまり、中央のViewに対しては上位層からの差分レンダリングと、
自身の Reducer 計算後のレンダリングの二重にレンダリングが起きるリスク
をはらんでいます。
そこで、 ViewStore というラッパーを使うことによって、内部で removeDuplicates 処理を行い、重複問題を解決している というのが一連の流れになります。

この辺りは、Harvest に比べるとやや複雑な構造ではないかと個人的に思いますが、
何か他の利点があってのことかもしれないので、ここではそれ以上の話は踏み込みません。


さて、Multi-Store の話はこのくらいにして、次は Case Paths という素晴らしいテクニックについて紹介したいと思います。
これは簡単にいうと、「struct における WritableKeyPath」 に対する 「enum における CasePath」 という位置付けで、今日の話でいうところの、Prism の部分に相当します
記号としては、WritableKeyPath がバックスラッシュを使うなら、CasePath は逆向きの、通常のスラッシュを使います。
これは自前の prefix func を実装して実現しているもので、スラッシュの向きが逆なところが双対な感じがあって、個人的にセンスが良いと思います。


では実際に、CasePath の型の中身を見てみましょう。
すると、 embedextract という2つの関数 を必要としていることが分かります。
まさにこれは Prism そのもの です。
なので、CasePath を理解するためには、まず Optics を学ぶと理解がとても捗ります。

そして、CasePath の一番の特徴として、通常の Prism では2つの関数が必要になるのに対して、
CasePath では prefix func / を使うことで、1つの関数のみで定義できてしまいます。
これは、内部で魔法(いわゆるリフレクション) が使われていて、これにより Optics まわりのボイラープレートになりがちなコードについて、コード自動生成が必要なくなるというメリットがあります。


というわけで、以上の2点が私から見た Composable Architecture の大きな特徴になります。
より詳しい話は、別のセッションで @yimajo さんが、より深堀りして下さっていると思いますので、ぜひこちらのトークも参照してみてください。