Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ZOZOTOWNアプリでのフルCompos実装取り組み事例

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for umsys umsys
September 25, 2023

 ZOZOTOWNアプリでのフルCompos実装取り組み事例

Avatar for umsys

umsys

September 25, 2023
Tweet

More Decks by umsys

Other Decks in Programming

Transcript

  1. © ZOZO, Inc. 株式会社ZOZO
 ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android1ブロック 
 Androidアプリエンジニア 内山

    雅由
 • ハリネズミを飼っていました
 ◦ またお迎えしたいものです...
 • 車の運転とゲームが大好きです 
 • ポケモンカードに最近ハマっています 
 
 2
  2. © ZOZO, Inc. https://zozo.jp/
 3 • ファッションEC
 • 1,500以上のショップ、8,900以上のブランドの取り扱い 


    • 常時95万点以上の商品アイテム数と毎日平均2,900点以上の新着 商品 を掲載(2023年6月末時点) 
 • ブランド古着のファッションゾーン「ZOZOUSED」や 
 コスメ専門モール「ZOZOCOSME」、靴の専門モール 
 「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン 
 「ZOZOVILLA」を展開
 • 即日配送サービス
 • ギフトラッピングサービス
 • ツケ払い など

  3. © ZOZO, Inc. 4 https://zozo.jp/zozomat/ 
 
 • 自宅にいながら簡単に高精度な足の3D計測ができる計測マット 


    • 計測したデータをもとに、自分の足型と靴の“相性度” を表示 
 • NIKEやCONVERSEなど5,587型以上のアイテムに対応 
 (2022年12月末時点)
 

  4. © ZOZO, Inc. 5 https://zozo.jp/zozoglass/ 
 • 自宅で簡単・高精度にご自身の顔の肌の色を計測できるフェ イスカラー計測ツール
 •

    ECにおけるコスメ購入時の課題であった「色選び」に関する不 安や悩みを解消
 • 肌の色を構成する成分、ヘモグロビン量とメラニン量を画像か ら推定
 • コスメ専門モール「ZOZOCOSME」で取り扱うベースメイクの一 部に対応
 • 計測者数128万人を突破(2022年12月末時点) 

  5. © ZOZO, Inc. 10 ZOZOTOWNおけるComposeの扱い • 新しく開発するUIはComposeで実装する方針 ◦ 複雑なUI実装が簡素化され、 UIに関する不具合を抑えることを期待

    ◦ 開発スピードアップを期待 ◦ 描画パフォーマンス向上を期待 ◦ ベース実装がSingle Activity + Fragmentの構成なので、全面的な Compose化は困難 ▪ Fragment上にsetContentでUIをすべてCompose実装する「ほぼ全面導入」 • できたらやりたいが中々踏み切れていない ▪ 既存のxmlにComposeViewでComposeを乗せる「部分的導入」 • ほとんどは既存実装に部分的導入をしています • Atomic DesignをベースとしたComposable設計ルール ◦ 無秩序なComposable作成を防止 • 社内勉強会でCodelabを通じて学習 ◦ 現在はComposeに関する章は全て学習完了しています 引用:https://techblog.zozo.com/entry/zozotown-android-jetpack-compose
  6. © ZOZO, Inc. 11 ZOZOTOWNおけるComposeの扱い • 新しく開発するUIはComposeで実装する方針 ◦ 複雑なUI実装が簡素化され、 UIに関する不具合を抑えることを期待

    ◦ 開発スピードアップを期待 ◦ 描画パフォーマンス向上を期待 ◦ ベース実装がSingle Activity + Fragmentの構成なので、全面的な Compose化は困難 ▪ Fragment上にsetContentでUIをすべてCompose実装する「ほぼ全面導入」 • できたらやりたいが中々踏み切れていない ▪ 既存のxmlにComposeViewでComposeを乗せる「部分的導入」 • ほとんどは既存実装に部分的導入をしています • Atomic DesignをベースとしたComposable設計ルール ◦ 無秩序なComposable作成を防止 • 社内勉強会でCodelabを通じて学習 ◦ 現在はComposeに関する章は全て学習完了しています 引用:https://techblog.zozo.com/entry/zozotown-android-jetpack-compose
  7. © ZOZO, Inc. 12 ほぼ全面的導入のパターン Activity 既存Fragment 新規Fragment AndroidView Compose

    override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setContent { RankingComposeView() } } } 1 2 3 4 5 6
  8. © ZOZO, Inc. 13 ほぼ全面的導入のパターン • メリット ◦ 既存コードとの共存を考えなくて良い ▪

    コードベースがよりシンプルになりやすい ▪ 今後のメンテナンスが楽に ◦ 事例が少ないCompose全面導入の開発で知見を得られる ▪ 社内外問わず、部分的導入を試みる事例が大半 ▪ 流行りの宣言的UIを使用した機能設計経験も得られる • デメリット ◦ 既存のUI実装は再利用できない ▪ AndroidViewをComposeに乗せる方法もあるが、それでは本末転倒 ▪ 既存仕様を取りこぼす可能性 ◦ 既存仕様全体を把握する必要がある
  9. © ZOZO, Inc. 14 部分的導入のパターン Activity 既存Fragment AndroidView 既存Fragment AndroidView

    <androidx.compose.ui.platform.ComposeView android:id="@+id/composeView" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> binding.composeView.setContent { RankingRefineComposeView() } 1 2 3 4 5 6
  10. © ZOZO, Inc. 15 部分的に導入するパターン • メリット ◦ 小さな改修案件でも無理なくCompose化が可能 ◦

    移行のリスクが最小限に抑えられます • デメリット ◦ 既存のAndroidViewとComposeの両方を管理する必要があります ◦ 場合によっては繋ぎ込みのためにワークアラウンド実装することも ◦ アプリケーションの状態を既存の AndroidViewと共有することで 予期せぬ互換性の問題が生じる恐れがあります
  11. © ZOZO, Inc. 17 ランキング機能リニューアル 【大まかな仕様要件】 • ViewPagerでのカテゴリ切り替え廃止 ◦ ベースの実装を崩す必要がある

    • 絞り込み条件設定機能が追加 ◦ 元々はカテゴリーと性別でしか 絞り込めなかった ◦ BottomSheetで表示 ◦ 親画面がAndroidViewの場合に導入 できなかったBottomSheetScaffoldを 使えるチャンス 【その他補足情報】 • 1機能丸々リニューアルなので、かなり長めの開発期間が 割り当てられた • あまり改修が入っておらず、かなりレガシーなコード ランキング機能をリニューアルするプロジェクトが発足 1 2 3 4 5 6 4 5 6 1 2 3 4 5 6
  12. © ZOZO, Inc. 19 全体設計 • BottomSheetScaffold ◦ 画面のベース実装 •

    FABタップでbottomSheetを展開 ◦ sheetContent ▪ ランキング画面 ◦ bottomSheet ▪ 絞り込み条件設定画面 1 2 3 4 5 6
  13. © ZOZO, Inc. 1 2 3 4 5 6 20

    全体設計 • LazyVerticalGrid ◦ 商品リストを実装 • NestedScrollConnection ◦ 商品リストのスクロール量に応じ てヘッダーを縮小する 1 2 3 4 5 4 5 6
  14. © ZOZO, Inc. 21 全体設計 • Navigation Compose ◦ 絞り込みモーダル内での遷移

    ※Navigation Composeを採用するにあたって技術調査を 行いました  詳しい内容に関しては、こちらのテックブログから ご確認いただけます。 https://techblog.zozo.com/entry/20220630-meetup-report
  15. © ZOZO, Inc. Fragment 22 UI全体設計 BottomSheetScafold sheetContents LazyVerticalGrid ItemCell

    (商品表示) Compose (絞り込み条件設定モーダル) ItemCell (商品表示) ItemCell (商品表示)
  16. © ZOZO, Inc. 26 コードメトリクス測定結果 計測情報 ランキングリニューアル前 ランキングリニューアル後 総ファイル数 49

    55 Author数 2.79 2.27 コード行数 3635 4901 循環的複雑度 (平均 / 標準偏差 / 最大値) 1.84 / 1.92 / 9.00 2.88 / 4.63 / 43.00 コードメトリクス計測に関してはこちらのテックブログでご紹介しております https://techblog.zozo.com/entry/zozotown-android-metrics-measurement ※自動生成されるコードは除いています
  17. © ZOZO, Inc. 28 循環的複雑度(Cyclomatic Complexity) • 循環的複雑度はメソッドの複雑度を示すメトリクス ◦ 大まかにはif文やfor文などの分岐やループによって数値が増加

    
 ◦ 計測することで、バグの混入リスクが高いメソッドを検出可能 
 数値の目安には決められたものはありませんが、一般的には下表のように言われています。 
 数値 複雑度とバグ混入リスク 〜10 シンプルな構造でバグの混入のリスクは低い 11〜20 やや複雑で中程度のバグの混入リスクがある 21〜50 複雑でバグの混入リスクが高い 51〜 テスト不可能な状態でバグの混入リスクが非常に高い
  18. © ZOZO, Inc. 29 コードメトリクス測定結果 計測情報 ランキングリニューアル前 ランキングリニューアル後 総ファイル数 49

    55 平均Author数 2.79 2.27 コード行数 3635 4901 循環的複雑度 (平均 / 標準偏差 / 最大値) 1.84 / 1.92 / 9.00 2.88 / 4.63 / 43.00 • 大幅に機能を追加実装したにも関わらず、微増程度で済んでいます ◦ Composeに置き換えるだけだった場合は、激減だった可能性が大 ◦ ViewPagerやRecyclerView周りのクラスを消せたことが大きく寄与していそう ※自動生成されるコードは除いています
  19. © ZOZO, Inc. 30 コードメトリクス測定結果 計測情報 ランキングリニューアル前 ランキングリニューアル後 総ファイル数 49

    55 平均Author数 2.79 2.27 コード行数 3635 4901 循環的複雑度 (平均 / 標準偏差 / 最大値) 1.84 / 1.92 / 9.00 2.88 / 4.63 / 43.00 • 1ファイルあたりの平均Author数です ◦ 実装して7年経つリニューアル前に対し、リニューアル直後も同等の水準 ◦ Composeの可読性故に、ランキングリニューアルに携わっていなかった人でも不具合修正を 担えたことが大きいと考えています ※自動生成されるコードは除いています
  20. © ZOZO, Inc. 31 コードメトリクス測定結果 計測情報 ランキングリニューアル前 ランキングリニューアル後 総ファイル数 49

    55 平均Author数 2.79 2.27 コード行数 3635 4901 循環的複雑度 (平均 / 標準偏差 / 最大値) 1.84 / 1.92 / 9.00 2.88 / 4.63 / 43.00 • 順当に増大してしまいました ◦ アプリケーションの状態がFlowで定義され、それをViewModelで管理しています ◦ ランキング機能全体に対して1つのViewModelで実装したため、やることが多く肥大化しました ◦ 今後は機能全体ではなく、独立して機能する画面パーツごとにViewModelを作成することで 対処していく予定です ※自動生成されるコードは除いています
  21. © ZOZO, Inc. 32 コードメトリクス測定結果 計測情報 ランキングリニューアル前 ランキングリニューアル後 総ファイル数 49

    55 平均Author数 2.79 2.27 コード行数 3635 4901 循環的複雑度 (平均 / 標準偏差 / 最大値) 1.84 / 1.92 / 9.00 2.88 / 4.63 / 43.00 • ViewModelで定義しているEvent発行関数が最大値をマーク(あらゆる箇所から呼ばれる) • その他はバグ混入リスクが一番低い水準を保てています • Composeは関数なので幾分か増大することは想定内 • 現在はAtomic DesignをベースにComposable関数を分けることが主流ですが、循環的複雑度を低く保つためには 別の方法を模索する必要がありそうです ※自動生成されるコードは除いています
  22. © ZOZO, Inc. 34 ネガティブな結果 • Composeの不具合をたくさん踏み抜きました ◦ LazyVerticalGridのスクロールが重い ▪

    当時はスクロール中の clickableがパフォーマンスに影響を及ぼしていた ▪ スクロール中はclickableを無効にするワークアラウンドで対応 ▪ 現在は2023年8月にリリースされたCompose1.5.0で修正されています ◦ NestedScrollConnectionの不具合 ▪ Modifier.offset等でスクロールしたときに onPreFlingが返すVelocity値がおかしい ▪ VelocityTrackerが正しい相対速度を計算できていないことが原因 ▪ 正しい計算を行うVelocityTrackerを作成してonPreFlingで使うようにして対応 ▪ 現在は2022年7月にリリースされた Compose1.3.0-alpha02で修正されています ◦ BottomSheetScafoldとNestedScrollViewの相性が悪い ▪ スクロールしきっていないのに BottomSheet閉じる ◦ などなど... • 既存仕様の取りこぼしが多数発生しました • 想定より多くの実装時間がかかりました
  23. © ZOZO, Inc. 35 ポジティブな結果 • 開発者体験が良かった ◦ ほぼ全面的導入を試みた実装が初だったので、楽しみながら実装ができた ◦

    軽い操作確認はPreviewのインタラクティブモードで即座に確認できた ◦ 以前の方法では複雑になりがちだった UI実装が簡単にできた ▪ AnimatedVisibility ▪ LazyColumn / LazyRowなど • 不具合修正が容易になった ◦ リリース後に不具合がいくつか発覚したが、修正スピードがいつもより速かった • 後につながる知見を大量に得た ◦ AndroidViewでできたことがそのままできると思い込まない心構え ◦ Modifierの適用順序が与える影響 • アーキテクチャー面での再検討し直しは発生しなかった ◦ AndroidViewやJavaとの共存を考えなくて良いことが大きかったと考えています
  24. © ZOZO, Inc. 37 今後の展望 • 引き続きCompose化を推し進める方針 ◦ デリバリー重視のプロジェクトでは部分的に Compose化

    ◦ クオリティ重視のプロジェクトではできるだけ全体的に Compose化 ◦ 可能ならAndroidViewをComposeにリプレイスすることを前提として追加改修に望む • 循環的複雑度が増大しないように Atomic Design以外での関数切り分け粒度を 検討
 • 今後のランキング画面改修時のデータを計測し、 メンテナンス性などを評価する
 • 今回得た知見を元に、これからのComposeライフを全力で楽しむ!