Slide 1

Slide 1 text

© KAUCHE, Inc. Multi-module design of Kauche Android

Slide 2

Slide 2 text

© KAUCHE, Inc. Table of Contents - 自己紹介 - Kauche のざっくりした紹介 - Kauche Android の歩みと選択 - 初期スタートアップなりの取捨選択 - 生産性を高めるために気がついたらマルチモジュールになっていた話 - Kauche に今も残る課題 - まとめ

Slide 3

Slide 3 text

© KAUCHE, Inc. Self-introduction sintario as a service - 社歴 - Oct. 2020 複業で join - July 2021 正社員に - July 2022 Product unit, Social UX team - それ以前 - ex-mercari, ex-DeNA, ex-JustSystems - A mobile-app engineer - Android 主に書く - iOS 最近はちょっと書く - 直近だと6月リリースの超シェア買い祭(タイムセール)を Android と iOS 両方 泣きながら 実装した者です - A remote contributor - ほぼ出社してません(交通費精算回数数えたら 5回 / 1年)

Slide 4

Slide 4 text

© KAUCHE, Inc. カウシェのざっくりした紹介

Slide 5

Slide 5 text

© KAUCHE, Inc. イベントにご参加いただいているので もちろんご存知とは思いますが

Slide 6

Slide 6 text

© KAUCHE, Inc. “誰かと一緒に”を楽しむ、 シェア買いアプリ

Slide 7

Slide 7 text

© KAUCHE, Inc. シェア買い価格で 購入 シェア買い開始! メンバーを募集 アプリ内や SNSにシェア 24時間以内に 2人以上集めると成功! 失敗したら返金!

Slide 8

Slide 8 text

© KAUCHE, Inc. Kauche 1.0.0 (MVP) リリース前の開発中の貴重なスクショ 最初は検索すらない強気のECアプリ - 商品一覧 - 商品詳細 - 決済画面(shopify, custom tabs) - グループ詳細 - 使い方ガイド - 設定

Slide 9

Slide 9 text

© KAUCHE, Inc. Architecture overview - 在庫管理・陳列・決済を shopify で 実現 - カウシェのサーバーがシェア買いグ ループを実現 - shopify の rate limit が厳しい、アプ リから直接 SDK 経由で叩く - BFF がアプリ側にいるような構成 customer API by Kauche storefront API by shopify Product Group, Product ID Product ID

Slide 10

Slide 10 text

© KAUCHE, Inc. Kauche 1.0.0 - core - data class の寄せ集め - ユーティリティ関数とか - api - customer API client - api_java - customer API は protobuf で定義されている - protobuf から生成されたモデルクラス - design - デザイン定数とか - shopify - storefront API client - app - その他全部

Slide 11

Slide 11 text

© KAUCHE, Inc. Android app’s architecture (初期) - Single Activity, Fragments, ViewBinding, Jetpack Navigation - 購入経路が商品詳細とグループ詳細の 2系統ある - custom tabs で開いた shopify の決済画面からアプリに戻すため launchMode=singleTask にしておいて url scheme で戻 る - url scheme で戻ったあと LocalBroadcastReceiver で購入元画面に更に制御を戻す - MVVM の中身を clean architecture っぽく階層分割したもの

Slide 12

Slide 12 text

© KAUCHE, Inc. 購入履歴が追加されたあとあたりの app の nav_graph.xml - 頑張って平坦に並べてもグチャグ チャしてきたのが目に見えて... - そもそも全部明示的につないでおく 必要ホントにあるか?

Slide 13

Slide 13 text

© KAUCHE, Inc. 1つ画面追加でもこんななので 今後の生産活動に支障があるのでは? という気がしてきた

Slide 14

Slide 14 text

© KAUCHE, Inc. 組織の課題も踏まえて進み方を考える - まだまだ何にもない、これから作るもののほうがモリモリ - 求められているのは Try First をモリモリできる生産性 - どんどん作る・失敗しても作り直す・捨てるコードもあって当たり前 - Android は社員が自分一人、 iOS は専任正社員が実質いない - 潤沢な人的リソースがあったときにスケールするアーキテクチャはまだいらない - 複業メンバーに活躍してもらうことを前提に最適化する - 本業が他にある人には 1日 2 - 3 時間使ってもらえたらいいほう - 長考に陥らないようにしたい - 明快であること - 作るものをできるだけ減らす - 関心の分離 - やることを小さくする - 影響範囲を小さく - 開発にハマれること(サービスの魅力+書き心地+チャレンジ精神) - (結果的に自分自身の生産性をも引き出すこと)

Slide 15

Slide 15 text

© KAUCHE, Inc. で、整備したこと 1. Feature Flags 導入 2. Jetpack Compose 導入 3. Feature modules 導入

Slide 16

Slide 16 text

© KAUCHE, Inc. Feature Flags - 作りかけでもどんどん merge できるようにする - 細切れの時間で作っている人が epic ブランチを長期保持するような開発は非現実的 - develop ブランチに入っていれば常勤社員がビルド通るように非同期保守できる - (複業メンバーの経験値から、 PRを小さくする実践力は期待できる前提) - どんどんPRレビューしてどんどん merge する進捗感が煽る生産意欲 - release blocker にさせない - 理想形は目指さない - ABテストフレームワークとの統合とか贅沢言わない - 遠隔操作できるのが理想だが、そこまでなくてもいい - アプリ上で ON/OFF できる UI 作るのも最初はいらない - FF自体が信頼できるか、を検証する工数もタダではない - kill switch としての Feature Flags があればよい - ON/OFF 切り替えできれば十分

Slide 17

Slide 17 text

© KAUCHE, Inc. この程度のもので十分 JIRA の番号くらい埋めておけばまあ足りるでしょと

Slide 18

Slide 18 text

© KAUCHE, Inc. 一番かんたんな使い方 Fragment#onCreateView で作り分ける

Slide 19

Slide 19 text

© KAUCHE, Inc. Jetpack Compose だと UI 潰しもかんたん Compose Preview もできるし

Slide 20

Slide 20 text

© KAUCHE, Inc. 恒久化( flag removal )もかんたん

Slide 21

Slide 21 text

© KAUCHE, Inc. Jetpack Compose 導入 - エンジニアのやる気と生産性を引き出す - 宣言的 UI 便利だよ、楽だよ、楽しいよ - 新しいものが触れているよ - 複業でチャレンジできているよ、を嘘にしない - 案外リプレイスに(外の世界では)推進力いる - すでにお金を稼いでいるアプリにおける、やらなくても動き続けるのになんでやるの?への説得 - 稼いでないアプリではなおさら - 機能開発を優先されるとコード改善が延々進まない無間地獄 - そもそも投資的エンジニアリングへのやる気が必要 - カウシェのバリューの体現という後押し - Try First - Enjoy Working - For Team

Slide 22

Slide 22 text

© KAUCHE, Inc. 安全な Jetpack Compose migration Feature Flags と ComposeView を組み合わせて使う - ViewModel はちゃんとデザインしていれば流用できる - 元の Fragment の機能を温存したまま UI を丸々入れ替える形で作る - migration も進むし検証終わるまで隠蔽もできるし、エンジニア主導の技術転換もこっそり進めや すい

Slide 23

Slide 23 text

© KAUCHE, Inc. XML の中身一部だけ Jetpack Compose migration もできるよ

Slide 24

Slide 24 text

© KAUCHE, Inc. デザイン資産の蓄積 再利用性の高いデザイン資産を作っていくのが容易 - プレビューと合わせて作るので、部品単独で見て触って把握できる。 探し回り工数の圧縮。 - 似たような画面の生産工数の圧縮

Slide 25

Slide 25 text

© KAUCHE, Inc. マルチモジュール化 : feature modules導入 - app に全部 feature 実装が集まると嬉しくないことを緩和したい - すべてのクラスが原則見えてしまうので何でもできすぎる - 探しものに時間がかかるようになる - あとから解消がむずかしい依存の発生を回避しにくくなる - 作業領域の交差 - namespace の奪い合い - 生産的な意味で「させない」構造を作る - 余計なものを見えなくする - 探せる範囲を小さくする - 依存できなくする - 作業の交差を小さくする - feature ごとに固有の package

Slide 26

Slide 26 text

© KAUCHE, Inc. module 分割 - analytics - クライアントログとか - navigation - (一部の)画面遷移実装 - deeplink 定義 - core - repository interfaces - data classes - その他データ状態仕分け便利クラス LoadState とか - design - Composable 関数で定義した再利用性の高い共通 UI - feature_foo_bar - いわゆる feature module - 原則新機能を作るときには新しくモジュールを立てる

Slide 27

Slide 27 text

© KAUCHE, Inc. feature module の build.gradle.kts - analytics, core, design, navigation にのみ依存OK - repository などは DI で app から差し込まれる - 他の feature module に依存するのはナシ - navigation-compose と navigation-fragment を併用 - 既存 app 実装をできるだけ活かしつつ、 new feature を実装資産化 する - プロフィール作成画面 - アイコン選択画面は navigation-compose

Slide 28

Slide 28 text

© KAUCHE, Inc. 例: feature_mission - ユーザーアクティビティに対して報酬 クーポンを付与する活性化策 - v1.33.0, May 25, 2022. - feature flag を入れて実装して実は一ヶ月前 くらいには Android が先行して完成していた - 達成判定はバックエンド - ミッション詳細・報酬詳細は web - アプリ側は実質ミッション一覧画面のみ - 未達ミッション、残時間カウントダウン - 達成後の報酬受取 - 流入経路が複数ある・増えうる

Slide 29

Slide 29 text

© KAUCHE, Inc. feature_mission : nav_mission.xml host fragment を用意して deepLink を設定

Slide 30

Slide 30 text

© KAUCHE, Inc. app: nav_graph.xml - nested graphにする。 - action 書かない(ほとんど明示的接続をしない) - 画面間でオブジェクトを渡さないといけないときだけ app 側で と action を書く

Slide 31

Slide 31 text

© KAUCHE, Inc. host fragment - app の nav_graph で規定された deepLink や一般的な web への遷移を扱うため navigator を app で実装して DI - host fragment は fragment の navigation を差し込むための皮、画面は実質 Jetpack Compose 実装

Slide 32

Slide 32 text

© KAUCHE, Inc. MissionListScreen の中身の抜粋 - 概略さらさら読める作り - viewModel.state に応じて loading, error, list, 空 を出し分けるだけ - 依存を限定したことで簡素化・標準化 - MissionViewModel / MissionUseCase あたりにビジネ スロジックが集まるが、そっちもやることほとんどない薄 い実装 - 圧倒的にあっという間に開発終わる - 保守も楽

Slide 33

Slide 33 text

© KAUCHE, Inc. 2022年の夏を迎えて : 今も残る課題感 1. client-side BFF 問題 2. grpc-gateway で GET を使うとおいしくない 3. いつ Fragment をすべて駆逐できるか

Slide 34

Slide 34 text

© KAUCHE, Inc. 課題: Client-side BFF - BFF がアプリ側にいるような構成 - つまりアプリ側に分厚いロジックが ある - APIデータ合成ロジックはアプリケー ション側で気にしたくない customer API by Kauche storefront API by shopify Product Group, Product ID Product ID

Slide 35

Slide 35 text

© KAUCHE, Inc. 課題: Improved architecture…? customer API by Kauche storefront API by shopify Product Group, Product ID Product ID UseCase getGroupDetail GroupDetail 明瞭さや 再利用性を高めることは できるかもしれないが 順番に2API呼ぶしかないのが解決してない

Slide 36

Slide 36 text

© KAUCHE, Inc. 課題: grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway - gRPC を RESTful JSON API として呼べるようにしてくれる - カウシェアプリからのリクエストは現況 RESTful の方を使ってい る

Slide 37

Slide 37 text

© KAUCHE, Inc. 課題: grpc-gateway における GET GET だとリクエストパラメタをクエリストリング(文字列)にする必要がある → protobuf でせっかく文字列以上の意味のある型を定義しているのに台無し

Slide 38

Slide 38 text

© KAUCHE, Inc. 対策 一律 POST を最近採択した - 取得系の API を含めてすべての RPC で POST を使う - リクエストパラメタは body となるので proto の型をそのまま使って Retrofit に @Body で指定できるようになる - 一律でPOSTを使う際、エンドポイント名にRPC名をそのまま用いる - RESTful で GET /foos のようなリスト取得だったものを単純に POST に変えるとリソース生成とエンドポイント衝突が起き てしまうため - つまり grpc-gateway を RESTful API 提供の手段ではなく JSON API の提供手段と割り切る あるいは、アプリが gRPC を直接しゃべるという方向性も?

Slide 39

Slide 39 text

© KAUCHE, Inc. 課題: Fragment の駆逐 正直 Fragment ある方がまだ便利なこともあるのでもうしばらくは Fragment 併用で - Fragment の中に Composable 関数を定義すれば Context とか Activity とかも不都合なく取得 できる - Jetpack Compose だけで閉じない(機能が足りない)こともまだあるので

Slide 40

Slide 40 text

© KAUCHE, Inc. 残る課題感とどう向き合うか - 通信・全体アーキテクチャ - architect yuki.ito join! 大きな解決を目指していく - Android 固有の課題 - プラットフォームの成熟を待つ - Google の new release を追いながら - Try を止めない

Slide 41

Slide 41 text

© KAUCHE, Inc. まとめ - カウシェとそのアーキテクチャのご紹介をしました - 気になる商品を誰かと買うシェア買いの最小構成要素は意外とシンプル - 一方で、2 API servers 併用の複雑性 - カウシェ Android が生産性を引き出すために行ったマルチモジュール化をご紹介しました - 複業主体のチームでは 短い時間で迷いなく安全に成果を積み上げられる技術採択 がおそらく正解 - Feature Flags: 変更を安全に隠す - Jetpack Compose: UIの資産化、生産時間効率を高める - マルチモジュールと deep link navigation: 関心範囲を限定する・柔軟な呼び出し - 残課題はありますが Try First を続けていきます カウシェではモバイルアプリエンジニアを積極採用中です ご興味あれば弊社採用ページをぜひ御覧ください https://enjoy-working.kauche.com/