Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Multi-module design of Kauche Android
Search
sintario
July 13, 2022
Technology
360
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Multi-module design of Kauche Android
sintario
July 13, 2022
More Decks by sintario
See All by sintario
導入動線のテコ入れでテコ入れが必要になった話
sintario_kauche
0
130
Other Decks in Technology
See All in Technology
AI駆動開発をチームに根付かせる - 「1行も書かない」チームがHarnessを育てた1年 -
kenichirokimura
6
3.2k
tamachi.goを支える技術
rymiyamoto
0
110
マイナンバーカード本人確認の実装比較(OAuth/OIDC Numa (Immersion) Workshop 2026) / 20260825 numa-12
oidfj
PRO
0
320
RapidCopy2 Matrix I/Oエンジンによるファイルコピーソフトウェアの設計と実装
kengosawa2
1
470
VPCでもFloatingIPを使いたいんだ
y_kotani
1
120
OAuth SPIFFE Client Authentication(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
330
1000⼈規模のClaude Enterprise運⽤を「Oktaのグループ」と「Slack」に集約する
sansantech
PRO
0
480
ブラウザで変わるID連携(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
340
:syncing_time:
sksat
3
830
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
3.2k
サーバー常駐型の 簡易障害調査AI エージェントを作ってみた話
masayoshi
1
270
NANDでも描画したい!
nichica906
3
800
Featured
See All Featured
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
210
How to Ace a Technical Interview
jacobian
281
24k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
220
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.8k
Git: the NoSQL Database
bkeepers
PRO
432
67k
So, you think you're a good person
axbom
PRO
2
2.1k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Typedesign – Prime Four
hannesfritz
42
3.1k
Transcript
© KAUCHE, Inc. Multi-module design of Kauche Android
© KAUCHE, Inc. Table of Contents - 自己紹介 - Kauche
のざっくりした紹介 - Kauche Android の歩みと選択 - 初期スタートアップなりの取捨選択 - 生産性を高めるために気がついたらマルチモジュールになっていた話 - Kauche に今も残る課題 - まとめ
© 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年)
© KAUCHE, Inc. カウシェのざっくりした紹介
© KAUCHE, Inc. イベントにご参加いただいているので もちろんご存知とは思いますが
© KAUCHE, Inc. “誰かと一緒に”を楽しむ、 シェア買いアプリ
© KAUCHE, Inc. シェア買い価格で 購入 シェア買い開始! メンバーを募集 アプリ内や SNSにシェア 24時間以内に
2人以上集めると成功! 失敗したら返金!
© KAUCHE, Inc. Kauche 1.0.0 (MVP) リリース前の開発中の貴重なスクショ 最初は検索すらない強気のECアプリ - 商品一覧
- 商品詳細 - 決済画面(shopify, custom tabs) - グループ詳細 - 使い方ガイド - 設定
© KAUCHE, Inc. Architecture overview - 在庫管理・陳列・決済を shopify で 実現
- カウシェのサーバーがシェア買いグ ループを実現 - shopify の rate limit が厳しい、アプ リから直接 SDK 経由で叩く - BFF がアプリ側にいるような構成 customer API by Kauche storefront API by shopify Product Group, Product ID Product ID
© 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 - その他全部
© 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 っぽく階層分割したもの
© KAUCHE, Inc. 購入履歴が追加されたあとあたりの app の nav_graph.xml - 頑張って平坦に並べてもグチャグ チャしてきたのが目に見えて...
- そもそも全部明示的につないでおく 必要ホントにあるか?
© KAUCHE, Inc. 1つ画面追加でもこんななので 今後の生産活動に支障があるのでは? という気がしてきた
© KAUCHE, Inc. 組織の課題も踏まえて進み方を考える - まだまだ何にもない、これから作るもののほうがモリモリ - 求められているのは Try First
をモリモリできる生産性 - どんどん作る・失敗しても作り直す・捨てるコードもあって当たり前 - Android は社員が自分一人、 iOS は専任正社員が実質いない - 潤沢な人的リソースがあったときにスケールするアーキテクチャはまだいらない - 複業メンバーに活躍してもらうことを前提に最適化する - 本業が他にある人には 1日 2 - 3 時間使ってもらえたらいいほう - 長考に陥らないようにしたい - 明快であること - 作るものをできるだけ減らす - 関心の分離 - やることを小さくする - 影響範囲を小さく - 開発にハマれること(サービスの魅力+書き心地+チャレンジ精神) - (結果的に自分自身の生産性をも引き出すこと)
© KAUCHE, Inc. で、整備したこと 1. Feature Flags 導入 2. Jetpack
Compose 導入 3. Feature modules 導入
© KAUCHE, Inc. Feature Flags - 作りかけでもどんどん merge できるようにする -
細切れの時間で作っている人が epic ブランチを長期保持するような開発は非現実的 - develop ブランチに入っていれば常勤社員がビルド通るように非同期保守できる - (複業メンバーの経験値から、 PRを小さくする実践力は期待できる前提) - どんどんPRレビューしてどんどん merge する進捗感が煽る生産意欲 - release blocker にさせない - 理想形は目指さない - ABテストフレームワークとの統合とか贅沢言わない - 遠隔操作できるのが理想だが、そこまでなくてもいい - アプリ上で ON/OFF できる UI 作るのも最初はいらない - FF自体が信頼できるか、を検証する工数もタダではない - kill switch としての Feature Flags があればよい - ON/OFF 切り替えできれば十分
© KAUCHE, Inc. この程度のもので十分 JIRA の番号くらい埋めておけばまあ足りるでしょと
© KAUCHE, Inc. 一番かんたんな使い方 Fragment#onCreateView で作り分ける
© KAUCHE, Inc. Jetpack Compose だと UI 潰しもかんたん Compose Preview
もできるし
© KAUCHE, Inc. 恒久化( flag removal )もかんたん
© KAUCHE, Inc. Jetpack Compose 導入 - エンジニアのやる気と生産性を引き出す - 宣言的
UI 便利だよ、楽だよ、楽しいよ - 新しいものが触れているよ - 複業でチャレンジできているよ、を嘘にしない - 案外リプレイスに(外の世界では)推進力いる - すでにお金を稼いでいるアプリにおける、やらなくても動き続けるのになんでやるの?への説得 - 稼いでないアプリではなおさら - 機能開発を優先されるとコード改善が延々進まない無間地獄 - そもそも投資的エンジニアリングへのやる気が必要 - カウシェのバリューの体現という後押し - Try First - Enjoy Working - For Team
© KAUCHE, Inc. 安全な Jetpack Compose migration Feature Flags と
ComposeView を組み合わせて使う - ViewModel はちゃんとデザインしていれば流用できる - 元の Fragment の機能を温存したまま UI を丸々入れ替える形で作る - migration も進むし検証終わるまで隠蔽もできるし、エンジニア主導の技術転換もこっそり進めや すい
© KAUCHE, Inc. XML の中身一部だけ Jetpack Compose migration もできるよ
© KAUCHE, Inc. デザイン資産の蓄積 再利用性の高いデザイン資産を作っていくのが容易 - プレビューと合わせて作るので、部品単独で見て触って把握できる。 探し回り工数の圧縮。 - 似たような画面の生産工数の圧縮
© KAUCHE, Inc. マルチモジュール化 : feature modules導入 - app に全部
feature 実装が集まると嬉しくないことを緩和したい - すべてのクラスが原則見えてしまうので何でもできすぎる - 探しものに時間がかかるようになる - あとから解消がむずかしい依存の発生を回避しにくくなる - 作業領域の交差 - namespace の奪い合い - 生産的な意味で「させない」構造を作る - 余計なものを見えなくする - 探せる範囲を小さくする - 依存できなくする - 作業の交差を小さくする - feature ごとに固有の package
© KAUCHE, Inc. module 分割 - analytics - クライアントログとか -
navigation - (一部の)画面遷移実装 - deeplink 定義 - core - repository interfaces - data classes - その他データ状態仕分け便利クラス LoadState とか - design - Composable 関数で定義した再利用性の高い共通 UI - feature_foo_bar - いわゆる feature module - 原則新機能を作るときには新しくモジュールを立てる
© 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
© KAUCHE, Inc. 例: feature_mission - ユーザーアクティビティに対して報酬 クーポンを付与する活性化策 - v1.33.0,
May 25, 2022. - feature flag を入れて実装して実は一ヶ月前 くらいには Android が先行して完成していた - 達成判定はバックエンド - ミッション詳細・報酬詳細は web - アプリ側は実質ミッション一覧画面のみ - 未達ミッション、残時間カウントダウン - 達成後の報酬受取 - 流入経路が複数ある・増えうる
© KAUCHE, Inc. feature_mission : nav_mission.xml host fragment を用意して deepLink
を設定
© KAUCHE, Inc. app: nav_graph.xml - nested graphにする。 - action
書かない(ほとんど明示的接続をしない) - 画面間でオブジェクトを渡さないといけないときだけ app 側で <fragment> と action を書く
© KAUCHE, Inc. host fragment - app の nav_graph で規定された
deepLink や一般的な web への遷移を扱うため navigator を app で実装して DI - host fragment は fragment の navigation を差し込むための皮、画面は実質 Jetpack Compose 実装
© KAUCHE, Inc. MissionListScreen の中身の抜粋 - 概略さらさら読める作り - viewModel.state に応じて
loading, error, list, 空 を出し分けるだけ - 依存を限定したことで簡素化・標準化 - MissionViewModel / MissionUseCase あたりにビジネ スロジックが集まるが、そっちもやることほとんどない薄 い実装 - 圧倒的にあっという間に開発終わる - 保守も楽
© KAUCHE, Inc. 2022年の夏を迎えて : 今も残る課題感 1. client-side BFF 問題
2. grpc-gateway で GET を使うとおいしくない 3. いつ Fragment をすべて駆逐できるか
© KAUCHE, Inc. 課題: Client-side BFF - BFF がアプリ側にいるような構成 -
つまりアプリ側に分厚いロジックが ある - APIデータ合成ロジックはアプリケー ション側で気にしたくない customer API by Kauche storefront API by shopify Product Group, Product ID Product ID
© KAUCHE, Inc. 課題: Improved architecture…? customer API by Kauche
storefront API by shopify Product Group, Product ID Product ID UseCase getGroupDetail GroupDetail 明瞭さや 再利用性を高めることは できるかもしれないが 順番に2API呼ぶしかないのが解決してない
© KAUCHE, Inc. 課題: grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway - gRPC を RESTful
JSON API として呼べるようにしてくれる - カウシェアプリからのリクエストは現況 RESTful の方を使ってい る
© KAUCHE, Inc. 課題: grpc-gateway における GET GET だとリクエストパラメタをクエリストリング(文字列)にする必要がある →
protobuf でせっかく文字列以上の意味のある型を定義しているのに台無し
© KAUCHE, Inc. 対策 一律 POST を最近採択した - 取得系の API
を含めてすべての RPC で POST を使う - リクエストパラメタは body となるので proto の型をそのまま使って Retrofit に @Body で指定できるようになる - 一律でPOSTを使う際、エンドポイント名にRPC名をそのまま用いる - RESTful で GET /foos のようなリスト取得だったものを単純に POST に変えるとリソース生成とエンドポイント衝突が起き てしまうため - つまり grpc-gateway を RESTful API 提供の手段ではなく JSON API の提供手段と割り切る あるいは、アプリが gRPC を直接しゃべるという方向性も?
© KAUCHE, Inc. 課題: Fragment の駆逐 正直 Fragment ある方がまだ便利なこともあるのでもうしばらくは Fragment
併用で - Fragment の中に Composable 関数を定義すれば Context とか Activity とかも不都合なく取得 できる - Jetpack Compose だけで閉じない(機能が足りない)こともまだあるので
© KAUCHE, Inc. 残る課題感とどう向き合うか - 通信・全体アーキテクチャ - architect yuki.ito join!
大きな解決を目指していく - Android 固有の課題 - プラットフォームの成熟を待つ - Google の new release を追いながら - Try を止めない
© KAUCHE, Inc. まとめ - カウシェとそのアーキテクチャのご紹介をしました - 気になる商品を誰かと買うシェア買いの最小構成要素は意外とシンプル - 一方で、2
API servers 併用の複雑性 - カウシェ Android が生産性を引き出すために行ったマルチモジュール化をご紹介しました - 複業主体のチームでは 短い時間で迷いなく安全に成果を積み上げられる技術採択 がおそらく正解 - Feature Flags: 変更を安全に隠す - Jetpack Compose: UIの資産化、生産時間効率を高める - マルチモジュールと deep link navigation: 関心範囲を限定する・柔軟な呼び出し - 残課題はありますが Try First を続けていきます カウシェではモバイルアプリエンジニアを積極採用中です ご興味あれば弊社採用ページをぜひ御覧ください https://enjoy-working.kauche.com/