Galapagos Tech Blog

株式会社ガラパゴスのメンバーによる技術ブログです。

TCA使ってみます

こんにちは、

AIR Design for Apps事業部iOSチームのコードヒーヨアンです

久しぶりにブログを書きます。

今回のブログは次のアプリの新規作成について、The Composable Architectureを採用したことについて簡単に紹介させていただきたいと思います。

経緯

スルーテストとリリース頻度

弊社ではアプリの新しいバージョンをリリースする前に、検証チームにスルーテストを実施していただいてますが、リリース頻度を上げるには一つのネックになっています。

本来は機能を分けて小さいリリースを繰り返したいが、スルーテストは実装の規模に関係なく、

リリース内容を少なくしても、スルーテストにかかる工数があまり変化しません。小さいリリースと大きいリリースでスルーテストのコストが変わらないのであれば、リリースを大きくした方が時間的とコスト的に有利になります。

Snapshotテスト

この問題を解決するために、スルーテストの一部を自動化して必要な工数を減らせないか調べてみましたが、見つけたのが、アプリの前のバージョンと新バージョンのスクリンショットを自動的に比較して変わったところを教えてくれるSnapshotテストです。スルーテストと同じく、不本意な変化の発見ができますので、スルーテストの一部がSnapshotテストで自動化できると思われます。

Snapshotテストを調べた時にiOSでは主に二つのライブラリーがあります

  • iOSSnapshotTestCase歴史的につわれたライブラリー。フェイスブック製ですが、今はウーバーがメンテしています。
  • Point Free **SnapshotTesting:**比較的に新しい。Swiftで書かれていて、近年こちらの方がはやってる感がありました。Point Freeという会社が提供しています。

SnapshotTestingを調べていたとき、同じくPoint Freeが提供しているThe Composable Architecture(以降TCA)というアーキテクチャーライブラリーに出会って、気になって調べてみました。

TCAとは

The Composable Architecture on Github

TCAはRedux風のアプリ開発フレームワーク

基本的にはそれぞれの画面の状態を表すStateとそのステートの更新を担当Reducerがあり、画面が直接Stateを変更するなく、ReducerにActionを送信して、更新させる。Stateに変更があれば、あわせて画面が更新されるようになります。

外(API、データベーズなどの非同期処理)とのやりとりはEnvironment経由になっていて、Dependence Injectionがかなりやりやすい形になっています。

f:id:glpgsinc:20211224112424p:plain
The Composable Architecture

EnvironmentにAPIのstubとかを作ることで、簡単に画面を単独で実装可能になります。特にSwiftUIの場合はpreviewを使って独立した状態で楽に画面を実装することができます。

Composable Architectureのcomposableは何かというと、複数の画面を繋いでいくときに、それぞれの画面のSateとReducerをcomposeして繋いでいきます。

遷移もとの画面に遷移先のSateを追加し、遷移元の画面のReducerを遷移先のReducerと合わせて両方の画面を含んだユニットのReducerを作ります。こういうふうにComposeして最終的にアプリ全体のStateとReducerが出来上がります。

詳細についてはまた実装経験を積めた後にさせていただこうと思います。

なぜこのプロジェクトでTCAを使おうと思ったのか

Swift UIとUIKit

このプロジェクトは来年秋にリリースを目指す大型案件ですが、それによりOSサポート範囲がiOS 14からになり、SwiftUIなどがやっと使えるようになりました。

ただ問題点としては、現時点でSwiftUIオンリーでアプリを作るのが厳しくて(Deep Linkなどちゃんとできるのか、pull to refreshはiOS 15でSwiftUIに追加されたので、対象範囲のiOS 14でまだ使えないなど・・)、UIKitベーズで、適切なところにSwiftUIを使うことにしようとしています。

そこで、TCAはSwiftUIを考えて作られたので、SwiftUIでかなり使いやすいですが、UIKitでも問題なく使えますので、同じアーキテクチャーで両方使えるところが強いと思います。サンプルコードもSwiftUIでもUIKitでも充実していて、実装時に参考になります。

わかりやすさ

画面単体で作ることができ、画面のReducerだけ見れば画面の状態はどのように更新されるかわかります。Actionを見れば、この画面でどんな操作ができるかわかります。

画面単独で作れるので、アプリ開発初期に、まだAPI機構などが完成していない時期でも画面のレイアウトと動作が単独で作れます。

単体テスト・Snapshotテスト

TCAのライブラリーに単体テストをしやすくするための機能が揃っていて、簡単にReducerなどのテストが書けます。

EnvironmentもDIしやすいので、APIに依存しないテストがかけて、画面での操作も、Actionという形でreducerに送られますので、storeにActionを送信して、更新後のstateの期待値とテスト後のstateを簡単にテストできます。

Snapshotも、ユーザーが画面で操作した時のテストを書きたいので、

画面のコントロールを触らずに、その操作に相当するActionをstoreに送信し、更新された画面のsnapshotを撮れば、操作後のsnapshotが簡単に撮れます。

気になる点

気になる点としては、いろんな画面を繋ぎ込んだ時の、わかりにくくならないかという点と、

Stateの更新のパフォーマンスが低くならない点が一番問題視しているところです。

両方も対策できると思いますので、実装進みながら適切に対応していきたいと思います。