Android Meetup イベントレポート
2021/8/5 (木) に ZOZOテクノロジーズ × サイバーエージェント × GMOペパボ のコラボで各社の取組や昨今の Android 事情をワイワイ話すイベント が開催されました。GMO ペパボからは @tick-taku、@mune がそれぞれ minne Android 実装の裏側をお話させていただきました。
発表内容をレポートにまとめてみましたので、ぜひ読んでいただけると嬉しいです!
minne はどうアーキテクチャを選択したか
と言う事でこんにちは!minne 事業部で Android アプリをもくもくしている @tick-taku です。今はチームで色々と開発の舵取りをしていますが、やりたい事とやらないといけない事が多すぎてパンクしそうです…
今回のイベントでは、現在の minne では アーキテクチャをどう考えてどう選んだかについて話しました。
minne は長い歴史のあるサービスで、その時その時に良いと思った技術をどんどん取り入れて成長してきました。アーキテクチャもその1つです。
特にモバイルアプリ (クライアントアプリ) ではやろうと思えばだいたいなんでも出来てしまうため、しっかりと設計をしておかないと実装のバラツキや可読性の低下などからアジリティがみるみる下がっていきます。その実装において一定の秩序を強制できるのがアーキテクチャです。アプリケーションに合ったアーキテクチャを採用する事でアジリティ向上に繋がるので、時間をかけてしっかりとしたアーキテクティングを行う必要があると考えています。
前半はアーキテクチャを採用するメリットと、minne が採用してきたオーソドックスなアーキテクチャパターンの紹介を個人的な採用基準と共に解説しています。この辺りはスライドに書いてあるのと色んなところで解説されてたりするのでここでは割愛します。
と言うところで、それらの歴史やパターンを踏まえた上で今の minne はどうアーキテクチャを採用しているかと言う話をしました。各コンポーネントを少しだけ補足します。
MVVM
昨今の Android は公式である Google が様々な OSS (Jetpack ライブラリ) を開発し提供してくれています。minne でも Jetpack ライブラリを導入する事によってかなりの実装コスト削減に繋がる ため、積極的に採用しています。
その Jetpack ライブラリの中の Android Architecture Component (AAC) が MVVM と親和性が高く、ほぼ Google が MVVM をサポートしてくれていると言っていいと思います。おかげで、最近の Android アプリ開発は Jetpack を用いた MVVM での開発にのっかっておくと開発がしやすくなっています。
- ライフサイクルがサポートされている ViewModel
- ライフサイクルフレンドリーな UI へのデータオブザーバー LiveData
- UI コンポーネントをデータソースにバインドする DataBinding
- etc…
なので minne でも MVC から MVP と進んできていて、MVVM に舵を切ることになりました。
Repository
スライドで紹介しているアーキテクチャパターンはプレゼンテーションレイヤーの責務の明確化とプレゼンテーションレイヤーとモデルレイヤーの分離までしか担ってくれておらず、モデル内の責務に関しては特に明確化されていません。ビジネスロジックと一言で言っても UI に関係しない部分とざっくりひとまとめになっているためデータアクセス、バリデーション、キャッシュなど様々な種類のロジックが無秩序になってしまいます。それらを少しでも責務を分離させ役割に集中させるため、minne ではデータアクセスに関するロジックにデザインパターンの1つである Repository パターンを採用しています。
Repository パターンを採用した理由は大きく3つです。
- データアクセスの再利用
- プレゼンテーションレイヤーからデータ取得先の関心を分離
- データアクセスに用いたクライアントライブラリの依存関係の解決
ここで minne で Repository を採用して一番良かったと感じているのはライブラリの依存関係の解決です。
現在 minne ではネットワーク API を REST から GraphQL に移行しています。(詳しくは @mune が解説してくれています!) REST では Retrofit2、GraphQL では apollo-android を使用しているため、それぞれのライブラリの依存関係がプレゼンテーションレイヤーに漏れていると移行時に変更差分がアプリケーションのほぼ全体に渡ってしまいます。が、Repository の外に流すデータやエラーはアプリで独自にモデル化することによってライブラリの依存関係をブロックしているため変更箇所がその中だけで収まります。
データアクセス周りは Android アプリの外側の要因によって頻繁にアップデートされていく物なので、なるべくフットワークを軽くしておきたいところではあります。そういった場合に Repository パターンは非常にメリットがあると感じました。
UseCase
Repository では、採用した理由からデータアクセスをするだけにとどめています。そのため、データアクセス以外の純粋なビジネスロジック (例えばバリデーションなど) を担当するレイヤーが必要になりました。そこで UseCase です。
アプリの規模によっては Repository がビジネスロジックを担当したり、ViewModel に書いていたりするかもしれません。minne はそこそこ大きめのアプリケーションのため、 ViewModel に書くと FatViewModel になってしまうため UseCase を採用しています。(そもそも ViewModel はプレゼンテーションレイヤーなのでビジネスロジックを書くべきではないと思います。)
UseCase に関してはこちらの図がとても理解しやすく参考にさせていただきました。
上からそれぞれ、プレゼンテーションレイヤー、ビジネスロジックレイヤー、データアクセスレイヤーに分かれているためアプリのデータが追いやすく、それぞれの責務が明確になっているため機能変更時にどこを変更すればよいのかパッとわかるため、見積もりや実装が速になります。また UseCase ごとにマルチモジュールにできるためビルド時間の短縮も期待でき、テストも書きやすくなりました。
まとめ
現状大部分がまだリアーキテクチャできていない現状ですので必死に移行しているところです…ただ今回のアーキテクチャの採用前と採用後で、機能変更時に見積もりの正確さが上がり実装コストもかなり抑えられている気がします。
今回のお話には載せていませんが、基本的には Dagger 等を用いて DI していく事になるため Repository や UseCase が Singleton になることによって無駄なインスタンスの生成を防いだりすることも期待できるかもしれません。
今回のお話がアプリの実装方針で迷っている方の助けになれば幸いです!
minne Android における GraphQL の取り組み
こんにちは、minne事業部 マーケットグループ所属の @mune です! 業務では、Androidアプリ開発を担当しています。
今回のイベントでは、プロダクトに GraphQL を導入した背景や、それによって変化した開発体制について話しました。
GraphQL
GraphQL とは Facebook 製のクライアント / サーバー通信のための言語使用です。GraphQL はクエリ言語とスキーマ言語から成っており、問い合わせ言語という点で SQL と似通っている部分があります。
- Query(SELECT)
- Mutation(INSERT,UPDATE,DELETE)
- Subscription(リアルタイムにデータの更新情報を受け取る)
スキーマにおいては、GraphQL API の型システムを定義します。これはクライアントがアクセスできる、かつ存在し得るデータの完全な集合を意味します。GraphQL はこのスキーマをもとにレスポンスを生成しています。資料にもある通りGraphQL では、クエリとレスポンスデータの構造がほぼ同じであり、レスポンスを想像しながらクエリが書けるので非常にわかりやすいです。
REST と GraphQL
GitHub v3 REST API と v4 GraphQL API を題材として、REST における課題を紹介し、GraphQL であればクライアント主導で柔軟にレスポンスを受け取れることを話しました。実際 minne でも検索周りは GraphQL API で利用できるようになっており、検索結果数だけが欲しい!!! といった場面で非常に強力であると感じました。REST だと検索結果数だけを返すエンドポイントを新しく作るか、不要なデータを受け取る覚悟で既存エンドポイントにリクエストするかで悩みそうです。
Apollo GraphQL Client
minne では GraphQL で HTTP クライアントを実装するために Apollo GraphQL Client を採用しています。 スキーマとクライアントからのリクエスト情報をもとに自動でクライアントが利用する型をもつモデルを生成してくれます。発表では詳細に説明ができませんでしたが、公式 Tutorial と根本的に同じことをしていますので、ご参考ください。
新 Web API 開発スタイル
minne では GraphQL を導入するにあたって、サーバーサイドと各クライアントサイド(iOS、Android、Webフロント)から1名ずつ代表者を決め、合計4名で「GraphQL会」を発足し、導入を促進していました。minne は Web API のバージョンが複数存在するので、今後の開発のお約束などについて話し合いをしたり、エラーハンドリング、ページネーション、命名規則など考えられることは、導入前にみんなで固めました。導入後は資料の図(p.56)にある通り、いわゆるスキーマ駆動の Web API 開発で Web API の開発者・利用者で同時に実装が進められるので開発効率が向上しました。そして開発者、利用者が設計から参加するため、検証時の認識のズレも以前の体制と比べたら相対的に起きにくいことが言えると思います。
まとめ
以前は、Web API の設計がサーバーサイドの開発者に依存していて、Web API の実装がある程度進まないとクライアントの実装に着手しづらいなど、Web API 開発者と Web API 利用者との関わり方が単方向的なものになりがちであったという課題がありました。
GraphQL を導入したことによって、技術的な課題を解決できたことはもちろんですが、 サーバーサイド・クライアントサイドのエンジニアが集まって GraphQL の導入からをいっしょに促進して、サーバーサイド・クライアントサイド関係なく双方向なやりとりが活発になるより良い体制を築けたことが一番良かったことだと思っています。