2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
ZOZOTOWN AndroidへのJetpack Composeの導入 (全1記事)
リンクをコピー
記事をブックマーク
高橋啓太氏(以下、高橋):「ZOZOTOWN AndroidへのJetpack Composeの導入」ということで、発表します。まず自己紹介ですが、株式会社ZOZOテクノロジーズ(※取材当時)で「ZOZOTOWN」のAndroidエンジニアをやっています、高橋といいます。2020年の新卒入社で、今年で2年目です。
簡単に、ZOZOTOWNについて紹介させてください。ZOZOTOWNは、日本最大級のファッション通販サイトで、2021年の3月にはコスメ専門モールの「ZOZOCOSME」がオープンしました。
さっそく、今回のテーマとなるJetpack Composeについて簡単に説明していきます。Jetpack Composeとは、宣言的UIのツールキットで、Kotlinのコード上でUIの実装が可能になります。また、XMLを用いた既存のレイアウトとも相互運用可能となっています。つい最近、1.0.0のstableがリリースされました。(※取材当時)
Jetpack Composeでは、Composableアノテーションを付与した関数でUIを定義します。
そんなJetpack Composeについて、ZOZOTOWN Androidへの導入時に行った作業を順に説明していきます。
導入のステップは、大きく分けて3つあります。1つ目は、開発環境の整備。2つ目は、Compose導入時の課題の洗い出し。3つ目は、その課題の解決です。
まず、1つ目の開発環境の整備について説明します。Composeを使用した開発の前に、Android Studio Arctic Foxで既存プロジェクトのビルドを行いました。Android Studio Arctic Foxでは、Jetpack Composeの開発のサポートが強化され、Compose UIのプレビューなどが実装されました。
また、ZOZOTOWN Androidでは、Arctic Foxの導入と同時に、Android Gradle プラグイン 7.0.0へのアップデートと、JDK 11の導入を行いました。さらに、Dagger Hiltのアップデートも行いました。この環境で、一度ZOZOTOWN Androidをビルドし、問題なくビルドできることを確認しました。
Jetpack Compose beta08からはKotlin 1.5が必要となるため、Kotlinのアップデートもしました。アップデートの実施に際しては、リリースノートなどのドキュメントの確認とZOZOTOWN Androidへの影響箇所の調査を行いました。
ドキュメントの確認は、チームメンバーで読み合わせるかたちで行いました。のちほど登場するのですが、Composable内でFlowを利用するために、androidx.lifecycleのアップデートも行いました。
次のステップでは、Compose導入時の課題の洗い出しを行いました。課題を洗い出すため、Composeを使ったプロトタイプ実装とレビューを繰り返し行いました。プロトタイプ実装とレビューによって、大きく2つの課題が明らかになりました。
1つ目が、既存のZOZOTOWN AndroidのUI状態管理方法が、Composeに適していないということ。そして2つ目が、無秩序なComposable作成による、Composableの再利用性・可読性の低下です。
では、その2つの課題の解決に向けて、それぞれどのようなアプローチを取ったのかを説明していきます。
1つ目の課題は、既存のZOZOTOWN AndroidのUI状態管理方法が、Composeに適していないというものですが、この課題の解決に向けて、まずComposeが採用されているプロジェクトの実装を調査しました。そしてそれをもとに、Composeに適した設計を検討しました。
Composeは、公式のページにもあるように、UIの差分更新を自動で行います。なので、開発者は差分を意識してUIにデータを通知する必要がありません。
ここで、既存のZOZOTOWN Androidのうち、今回問題となった部分を説明していきます。ZOZOTOWN Androidでは、アプリケーションの状態に変更があると、ViewModelはその更新差分をFragmentに対して通知します。Fragmentはその内容をもとに、更新が必要なViewの更新を明示的に行います。
プロトタイプ実装とレビューによって、この更新差分を通知する部分が、Composeには適していないということが今回わかりました。
この問題についてコードレベルで説明します。ZOZOTOWNのUIの状態管理には、主に2つのオブジェクトが登場します。1つ目が、ViewDataです。ViewDataは、UIに表示するデータをまとめたデータクラスで、カスタムビュー単位で作成します。
2つ目が、ViewStateです。ViewStateはUIの状態を表すsealed classで、画面単位で作成します。ViewStateはそれぞれ、ViewDataを保持します。ZOZOTOWN Androidでは、ViewStateの切り方について明確なルールがこれまで存在しませんでした。
これらのViewData、ViewStateは、ViewModelの中でこのように扱われます。上から説明していこうと思います。
まずViewModelには、Activity/FragmentにViewStateを通知するFlowまたはLiveDataが定義されています。次に、そのデータの更新と、ViewStateを先ほどのFlowやLiveDataに流すメソッドが定義されています。そして最後に、ViewStateが定義されています。
それぞれのViewStateでは、更新差分のあるViewDataのみを保持しています。これがComposeでは扱いづらいということがわかりました。
先ほども紹介したように、Composeでは、差分を意識してUIにデータを通知する必要がありません。裏を返せば、これを活用するためには、画面全体の状態を1つにまとめる必要があるということです。
その点を踏まえ、UIの状態管理方法を見直しました。さらに、Eventの処理方法についても見直しを行いました。
まず、UIの状態管理方法の見直しについてです。設計を検討するにあたって、事前に参考実装の調査を行いました。そのうちの1つが、tiviというプロジェクトです。tiviは、Jetpack Composeで実装されたプロジェクトで、既存のZOZOTOWNと近いアーキテクチャであるため、今回の設計検討はtiviを参考にして行いました。
参考実装をもとに、まずは画面全体のViewDataを1つのViewStateに統合しました。そして、これまで差分のみを保持していたViewStateを削除しました。
次に、アプリケーションの状態を管理するFlowを用意しました。それらのFlowを、combine、そしてtransformすることで、アプリケーションの状態に変更があった時に、画面全体の状態を持った先ほどのViewStateを作成し、通知することができるようになりました。
そうすることで、Composable側では常に画面の全体の状態を受け取ることができ、ComposeのUIの差分更新を利用できるようになりました。
全体の流れは、このようになります。アプリケーションのStateが変化すると、ViewModelではそれを1つのViewStateにまとめ、Composableに通知します。
次に、Eventの処理方法についてです。ViewModel以下のEventの扱いに関しては、既存のZOZOTOWNと大きく変わる点はありませんでした。既存のZOZOTOWNにもあるのですが、ViewEventという、ユーザーインタラクションによって発生するEventを定義したsealed classを作成しました。ViewEventは、Flow/LiveData、LiveDataの場合はSingleLiveEventでViewEventを通知するようにしました。
ComposableからのViewEventの発行は、このようになりました。ViewEventは、各画面のトップレベルのComposableから発行するようにしました。そうすることで、下層のComposableは、ViewEventへの参照を持たず、ViewEventを意識しないかたちとなりました。これによって、下層のComposableの再利用性を上げることができました。
ここまで説明したViewState、ViewEventについて、ViewEventの発生から UIの更新までの流れはこのようになります。
画面上で、ユーザーインタラクションなどによってEventが発生すると、そのEventはLambdaを介して、上層のComposableへと伝搬されます。そして上層のComposableは、ViewModelに対して、ViewEventの発行を行います。
ViewModelは、ViewEventを受け取るとアプリケーションのStateを更新し、それらの状態を1つのViewStateというオブジェクトにまとめてComposableへと通知します。
ComposableはViewStateを受け取ると、UIの描画に必要なデータを下層のComposableに伝搬します。各Composableは、渡されたデータをもとに、UIの更新が必要だった場合に自動的に差分更新を行います。
このように、UIの状態管理、Eventの処理方法を見直し、1つ目の課題である、既存のZOZOTOWNのUI状態管理方法がComposeに適していないという問題を解決しました。
次に、2つ目の課題についてです。今後、チームでComposeを使用した開発を進めていくと、無秩序にComposableが作成され、Composableの再利用性・可読性が低下する懸念がありました。
そこで、ReactなどWebフロントの宣言的UIフレームワークではどのようにUIの要素を分割しているのか、事例を調査し、チームでの開発に備えたComposable設計ルールの検討を行いました。その調査の中で登場したのが、Atomic Designです。
Atomic Designは、主にWebフロントの世界で用いられるデザインシステムで、堅牢性の高いUI実装を実現できます。Atomic Designでは、コンポーネントと呼ばれるUIの要素を、Atoms、Molecules、Organisms、Templates、Pagesに分類し階層化します。
Atomic Designで定義されるコンポーネントの階層構造は、このようになっています。PagesはTemplatesへの依存を持ち、TemplatesはOrganismsへの依存を持ち、OrganismsはMoleculesやAtomsへの依存を持つというように、上層のコンポーネントが下層のコンポーネントへの参照を持ちます。
逆に下層のコンポーネントは、上層のコンポーネントに依存できません。これにより、下層のコンポーネントの変更による上層のコンポーネントへの影響を抑えることができます。
ZOZOTOWN Androidでは、このAtomic Designをベースに、Composable設計ルールを制定しました。それぞれのコンポーネントについて、ZOZOTOWN Androidでどのように定義したかを説明していきます。
まずAtomsですが、Atomsは機能的に分割できる最小のUI要素です。ZOZOTOWN Androidでは、Text、Button、Row、Columnなど、Composeで提供されているComposable、また吹き出しやアイコンなど、ZOZOTOWN Android独自に作成したComposableのうち、それ以上分割できないものをAtomsとしました。
命名規則というよりは方針なのですが、すべてのアプリケーションで利用できるように可能な限り抽象的な名前としています。
次に、Moleculesです。Moleculesは、ユーザーに対して目的・動機を提供する最小のUI要素です。ZOZOTOWN Androidでは、TextやRowなどのAtomsを組み合わせて作成したComposableです。
命名に関しては、ユーザーが何を実現したいのかを表す名前とします。右の例だと、これはドロップダウンメニューです。ドロップダウンメニューは、Moleculesとして定義しています。
Organisms。Organismsは、独立して成立するコンテンツです。ZOZOTOWN Androidでは、Atoms、Molecules、そしてほかのOrganismsを組み合わせて作成したComposableを、Organismsと定義しています。命名に関しては、そこに表示する情報自体を表しました。
そして、Templates。Templatesは、ページのコンテンツ構造を明確にするオブジェクトです。ZOZOTOWN Androidでは、画面全体のレイアウトを管理し、各UI要素に必要なViewDataを分配する役割を持ったComposableがTemplatesとなっています。Templatesは、1画面に対して1つ作成することとしました。
命名に関しては、頭に画面名がきて、サフィックスにScreenがくるかたちにしました。
そして、Pagesです。Pagesは、実際のデータを画面に反映するオブジェクトです。ZOZOTOWN Androidでは、ViewModelへの依存、つまり動的なデータへの関心を持つComposableをPagesとしています。
また、先ほどのViewEventのところでも出てきたように、ViewModelに対してViewEventを発行するComposableも、このPagesです。
また、1つ下のレイヤーにあるコンポーネントであるTemplatesに、実際のデータを提供する役割も、このPagesのComposableが担っています。
命名に関しては、Templatesと同じように、画面名そしてサフィックスにScreenとなります。引数が違うかたちです。
ZOZOTOWN Androidのデバッグメニューの例では、このようになっています。TextやButtonは、Atoms。SpinnerはMolecules。そして、それらを束ねたものが、Organisms。画面全体がTemplates、またPagesとなります。
以上のように、Composable設計ルールを制定することで、2つ目の課題である、無秩序なComposable作成による、Composableの再利用性の低下、また可読性の低下という問題を解決しました。
まとめです。まず、ZOZOTOWN AndroidへJetpack Composeを導入しました。Compose導入のための課題を洗い出し、それぞれ解決していきました。
1つ目は、UIの状態管理、Eventの処理方法の見直しです。そして2つ目が、Atomic DesignをベースにしたComposable設計ルールの制定です。
今後の課題は、いくつかあります。1つ目は、UIの状態管理方法のルール化です。今回検討したUIの状態管理方法は、まだルール化まで至っていません。今後はチームでよりスムーズに開発を行っていくため、今回の検討内容をルールに落とし込んでいきたいと考えています。
2つ目は、より複雑な画面でのStateの扱いです。今後は、より大きく複雑な画面でComposeを使用して開発していくことを検討しているため、UIの状態管理に関して、今回検討した設計ではカバーできないユースケースの登場が考えられます。そういったユースケースへの対応も考えていきたいと思っています。
3つ目は、Composable設計ルールのブラッシュアップです。今回制定したルールを、実際にチームで運用して、よりZOZOTOWN Androidに適したかたちに変えていこうと考えています。
最後に、デザイナー・エンジニア間のユビキタス言語としてのAtomic Designの活用です。Composableの設計だけでなく、デザイナーとエンジニア間の共通言語として、Atomic Designを活用し、デザインに関するコミュニケーションをよりスムーズにしていきたいと考えています。これらの課題についても、今回のプロトタイプ実装とレビューを繰り返して行ったように、実装と検証を繰り返して改善していこうと考えています。
以上です。ありがとうございました。
関連タグ:
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05