$30 off During Our Annual Pro Sale. View Details »

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

umsys
September 25, 2023

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

umsys

September 25, 2023
Tweet

Other Decks in Programming

Transcript

  1. ZOZOTOWNアプリでの

    Jetpack Compose取り組み事例

    2023/09/25

    After DroidKaigi 2023

    株式会社ZOZO

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android1ブロック

    Androidアプリエンジニア

    内山 雅由
    Copyright © ZOZO, Inc.
    1

    View Slide

  2. © ZOZO, Inc.
    株式会社ZOZO

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android1ブロック 

    Androidアプリエンジニア
    内山 雅由

    ● ハリネズミを飼っていました

    ○ またお迎えしたいものです...

    ● 車の運転とゲームが大好きです

    ● ポケモンカードに最近ハマっています


    2

    View Slide

  3. © ZOZO, Inc.
    https://zozo.jp/

    3
    ● ファッションEC

    ● 1,500以上のショップ、8,900以上のブランドの取り扱い

    ● 常時95万点以上の商品アイテム数と毎日平均2,900点以上の新着 商品
    を掲載(2023年6月末時点)

    ● ブランド古着のファッションゾーン「ZOZOUSED」や

    コスメ専門モール「ZOZOCOSME」、靴の専門モール

    「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン

    「ZOZOVILLA」を展開

    ● 即日配送サービス

    ● ギフトラッピングサービス

    ● ツケ払い など


    View Slide

  4. © ZOZO, Inc.
    4
    https://zozo.jp/zozomat/


    ● 自宅にいながら簡単に高精度な足の3D計測ができる計測マット

    ● 計測したデータをもとに、自分の足型と靴の“相性度” を表示

    ● NIKEやCONVERSEなど5,587型以上のアイテムに対応

    (2022年12月末時点)


    View Slide

  5. © ZOZO, Inc.
    5
    https://zozo.jp/zozoglass/

    ● 自宅で簡単・高精度にご自身の顔の肌の色を計測できるフェ
    イスカラー計測ツール

    ● ECにおけるコスメ購入時の課題であった「色選び」に関する不
    安や悩みを解消

    ● 肌の色を構成する成分、ヘモグロビン量とメラニン量を画像か
    ら推定

    ● コスメ専門モール「ZOZOCOSME」で取り扱うベースメイクの一
    部に対応

    ● 計測者数128万人を突破(2022年12月末時点)

    View Slide

  6. © ZOZO, Inc.
    6
    Jetpack Compose
    導入していますか?

    View Slide

  7. © ZOZO, Inc.
    7
    実際のところ、
    Jetpack Composeをどこまで導入するか
    悩みませんか?

    View Slide

  8. © ZOZO, Inc.
    8
    今回はZOZOTOWNアプリの
    1機能リニューアル対して
    ほぼ全面的にJetpack Compose※を
    導入した事例をご紹介します
    ※以降、Composeと表記します

    View Slide

  9. © ZOZO, Inc.
    9
    ZOZOTOWNにおける
    Composeの扱い

    View Slide

  10. © 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

    View Slide

  11. © 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

    View Slide

  12. © 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

    View Slide

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

    View Slide

  14. © ZOZO, Inc.
    14
    部分的導入のパターン
    Activity
    既存Fragment
    AndroidView
    既存Fragment
    AndroidView
    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

    View Slide

  15. © ZOZO, Inc.
    15
    部分的に導入するパターン
    ● メリット
    ○ 小さな改修案件でも無理なくCompose化が可能
    ○ 移行のリスクが最小限に抑えられます
    ● デメリット
    ○ 既存のAndroidViewとComposeの両方を管理する必要があります
    ○ 場合によっては繋ぎ込みのためにワークアラウンド実装することも
    ○ アプリケーションの状態を既存の
    AndroidViewと共有することで
    予期せぬ互換性の問題が生じる恐れがあります

    View Slide

  16. © ZOZO, Inc.
    16
    ほぼ全面的導入した機能の紹介

    View Slide

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

    View Slide

  18. © ZOZO, Inc.
    18
    UI設計の話
    ※Composeにフォーカスした話なのでUI以外は割愛します

    View Slide

  19. © ZOZO, Inc.
    19
    全体設計
    ● BottomSheetScaffold
    ○ 画面のベース実装
    ● FABタップでbottomSheetを展開
    ○ sheetContent
    ■ ランキング画面
    ○ bottomSheet
    ■ 絞り込み条件設定画面
    1 2 3
    4 5 6

    View Slide

  20. © ZOZO, Inc.
    1 2 3
    4 5 6
    20
    全体設計
    ● LazyVerticalGrid
    ○ 商品リストを実装
    ● NestedScrollConnection
    ○ 商品リストのスクロール量に応じ
    てヘッダーを縮小する
    1 2 3
    4 5
    4 5
    6

    View Slide

  21. © ZOZO, Inc.
    21
    全体設計
    ● Navigation Compose
    ○ 絞り込みモーダル内での遷移
    ※Navigation Composeを採用するにあたって技術調査を
    行いました
     詳しい内容に関しては、こちらのテックブログから
    ご確認いただけます。
    https://techblog.zozo.com/entry/20220630-meetup-report

    View Slide

  22. © ZOZO, Inc.
    Fragment
    22
    UI全体設計
    BottomSheetScafold
    sheetContents
    LazyVerticalGrid
    ItemCell
    (商品表示)
    Compose
    (絞り込み条件設定モーダル)
    ItemCell
    (商品表示)
    ItemCell
    (商品表示)

    View Slide

  23. © ZOZO, Inc.
    23
    いざ!実装開始!

    View Slide

  24. © ZOZO, Inc.
    24
    さて、
    どのような結果に至ったでしょうか?

    View Slide

  25. © ZOZO, Inc.
    25
    ZOZOTOWN Androidチームで
    推し進めているコードメトリクスの計測を使って
    評価してみました

    View Slide

  26. © 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
    ※自動生成されるコードは除いています

    View Slide

  27. © ZOZO, Inc.
    27
    循環的複雑度について

    View Slide

  28. © ZOZO, Inc.
    28
    循環的複雑度(Cyclomatic Complexity)
    ● 循環的複雑度はメソッドの複雑度を示すメトリクス
    ○ 大まかにはif文やfor文などの分岐やループによって数値が増加

    ○ 計測することで、バグの混入リスクが高いメソッドを検出可能

    数値の目安には決められたものはありませんが、一般的には下表のように言われています。

    数値 複雑度とバグ混入リスク
    〜10 シンプルな構造でバグの混入のリスクは低い
    11〜20 やや複雑で中程度のバグの混入リスクがある
    21〜50 複雑でバグの混入リスクが高い
    51〜 テスト不可能な状態でバグの混入リスクが非常に高い

    View Slide

  29. © 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周りのクラスを消せたことが大きく寄与していそう
    ※自動生成されるコードは除いています

    View Slide

  30. © 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の可読性故に、ランキングリニューアルに携わっていなかった人でも不具合修正を
    担えたことが大きいと考えています
    ※自動生成されるコードは除いています

    View Slide

  31. © 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を作成することで
    対処していく予定です
    ※自動生成されるコードは除いています

    View Slide

  32. © 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関数を分けることが主流ですが、循環的複雑度を低く保つためには
    別の方法を模索する必要がありそうです
    ※自動生成されるコードは除いています

    View Slide

  33. © ZOZO, Inc.
    33
    開発を終えて

    View Slide

  34. © 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閉じる
    ○ などなど...
    ● 既存仕様の取りこぼしが多数発生しました
    ● 想定より多くの実装時間がかかりました

    View Slide

  35. © ZOZO, Inc.
    35
    ポジティブな結果
    ● 開発者体験が良かった
    ○ ほぼ全面的導入を試みた実装が初だったので、楽しみながら実装ができた
    ○ 軽い操作確認はPreviewのインタラクティブモードで即座に確認できた
    ○ 以前の方法では複雑になりがちだった UI実装が簡単にできた
    ■ AnimatedVisibility
    ■ LazyColumn / LazyRowなど
    ● 不具合修正が容易になった
    ○ リリース後に不具合がいくつか発覚したが、修正スピードがいつもより速かった
    ● 後につながる知見を大量に得た
    ○ AndroidViewでできたことがそのままできると思い込まない心構え
    ○ Modifierの適用順序が与える影響
    ● アーキテクチャー面での再検討し直しは発生しなかった
    ○ AndroidViewやJavaとの共存を考えなくて良いことが大きかったと考えています

    View Slide

  36. © ZOZO, Inc.
    36
    今後の展望

    View Slide

  37. © ZOZO, Inc.
    37
    今後の展望
    ● 引き続きCompose化を推し進める方針
    ○ デリバリー重視のプロジェクトでは部分的に Compose化
    ○ クオリティ重視のプロジェクトではできるだけ全体的に Compose化
    ○ 可能ならAndroidViewをComposeにリプレイスすることを前提として追加改修に望む
    ● 循環的複雑度が増大しないように Atomic Design以外での関数切り分け粒度を 検討

    ● 今後のランキング画面改修時のデータを計測し、
    メンテナンス性などを評価する

    ● 今回得た知見を元に、これからのComposeライフを全力で楽しむ!

    View Slide

  38. View Slide