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
マルチテナントにおけるイベント計測の話
Search
r4wxii
September 19, 2024
0
950
マルチテナントにおけるイベント計測の話
r4wxii
September 19, 2024
Tweet
Share
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
0
94
Practical Orchestrator
shlominoach
186
10k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
48k
KATA
mclloyd
29
14k
It's Worth the Effort
3n
183
28k
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.4k
Why Our Code Smells
bkeepers
PRO
335
57k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
How to Think Like a Performance Engineer
csswizardry
22
1.2k
Into the Great Unknown - MozCon
thekraken
33
1.5k
Transcript
マルチテナントにおける イベント計測の話 id:r4wxii / @r4wxii 2024/09/19 はてなのモバイル開発大紹介! 1
2 イベント計測
3 イベント計測 • ユーザ・行動の分析や広告効果測定などに活用 される ◦ アプリでの代表例はFirebase • 様々なユーザが利用するアプリの運営に イベント計測は必要不可欠
◦ 当然ジャンプ+(GigaViewer for Apps)でも活用している
4 ジャンプ+ (GigaViewer for Apps)? マルチテナントって?
5 ジャンプ+は GigaViewer for Appsの テナントの1つ
6 • 1つのコードベースで複数のメディアを運営 ◦ 複数のメディア(テナント)、でマルチテナント ◦ 複数のメディアのうちの1つがジャンプ+ GigaViewer for Appsはマルチテナント
GigaViewer for Appsはマルチテナント 7 • マルチテナントであるGigaViewer for Apps ではどうイベント計測している? ◦
メディアによって欲しい情報や利用する計測プラット フォームが異なるため、それぞれに対応するための機能 を持っている
8 それぞれに 対応するための 機能
9 ただ計測プラットフォー ムが異なるだけではない
10 異なるだけ ではないとは • メディアによって計測PF が異なる • あるメディアしか利用し ない計測PFがあれば、 複数メディアが利用する
計測PFもある
異なるだけではないとは • 同一タイミングですべての計測PFにイベント 送信するわけではない ◦ 計測PFによって得意なことが違うので使い分けられている ◦ すべての計測PFに送信されるイベントがあれば、 ある計測PFにだけ送信されるイベントもある 11
12 ふ、複雑…
言い換えると 13
メディアごとに 適切な計測PFへ イベント送信する機能 14
15 今回はどのように 構築したか紹介
まずは方針を考える 16
17 方針を考える 上で前提の話
前提 • GigaViewer for Appsはマルチモジュール ◦ エントリポイントとなるメディアモジュール ▪ そのメディア固有の機能も含まれている ▪
例:ジャンプ+ ◦ 機能ごとのfeatureモジュール ▪ その機能固有の処理が書かれている ▪ メディア固有の処理がなく、単体性が保たれているので どのメディアでも使える ▪ 例:作品詳細、初回無料、ダウンロード 18
前提 • メディアモジュールから欲しい機能の モジュールに依存することでアプリを構成する ◦ 用意した機能の中からメディアが欲しい機能を取捨選択 するイメージ ◦ そのメディアに存在しない機能の混入を防げる ▪
メディア固有の処理が共通部分に含まれないようにしているため 19
20 以上を踏まえて
方針① 21
• メディア・計測PFを意識しないでイベント送信 ◦ 共通機能はどの計測PFを使うか知りたくない ▪ 必要な計測PFというのはメディアの関心なので共通機能に 持ち込みたくない ▪ 大半のイベントは共通機能から送信される ◦
1度の処理で必要な計測PF全てに送信されてほしい ▪ すべてのイベントで毎回計測PFごとに呼び出すのは手間 22 方針①
23 方針②
• 拡張性を持たせる ◦ 今後機能やメディアが増えて、新しいイベント・計測PF も増える可能性があるため ▪ イベント追加はiOSとAndroidのOS間で足並みを揃えたい ▪ 計測PFの追加を楽に行いたい 方針②
24
25 方針を元に 設計を考える
26 Androidを例にして説明 (元の設計は1つなのでiOSも大体同じ)
27 イベントの定義
28 イベントの定義 • 各イベントはyamlに定義 ◦ 定義するものはイベント名, パラメータ, パラメータの型 ◦ yamlを元に各OSの実装に適したコードを自動生成
▪ 自動生成されたものをEventとする ◦ yamlはメディア×計測PFごとに分ける ▪ 共通のものとメディア固有のもので分けたい ◦ 同じyamlをソースにしているのでOS間で定義が揃う
yamlから自動生成 events: - name: example - params: - name: param
type: Parameter 29 data class ExampleEvent( private val param: Parameter, ): Event { override val eventName = “example” override val params = mapOf(“param” to param) }
イベントの定義 • 生成された各計測PFのEventをまとめる ◦ ここは現状温かみのある人間の手作業… ◦ まとめた一塊をEventProxyとする ◦ このEventProxyは同一タイミングで送信される すべての計測PFのEventをもつ
30
イベントの定義 • 例えばあるボタンの押下数を計測したい ◦ メディア1 ▪ AとBという計測PFを利用していて、Aだけでイベント計測したい ▪ どの画面で押下されたかも知りたい ◦
メディア2 ▪ Cという計測PFを利用していて、Cでイベント計測したい ▪ どの画面で押下されたかは不必要 ◦ この場合EventProxyはAとCのEventを持つ 31
イベントの定義 data class TapButtonEventProxy( private val screen: String, ): EventProxy
{ override val platformA: Event? = A.TapButtonEvent(screen), override val platformB: Event? = null, override val platformC: Event? = C.TapButtonEvent(), } 32
33 このEventProxyを 送信処理へ渡すだけで 各計測PFに送信 されたい
34 各地から呼び出す イベント送信処理の実装
35 イベント送信処理 • イベント送信という1つの機能として抽象化 ◦ EventProxyを渡してイベント送信するinterface ◦ この機能をEventTrackerとする • interfaceは共通モジュールに定義、
実装は各メディアモジュールに任せる ◦ メディアごとに実装することでどの計測PFを利用するか というメディア固有の処理を扱える
イベント送信処理 • メディアで実装するEventTrackerの中身 ◦ 実態はイベントの振り分け ▪ EventProxyが持っている送信が必要なEventを取り出す ▪ 取り出したEventを送信先となる計測PF固有の処理へ渡す ▪
実際に計測PFへイベントが送信されるのは渡した先の処理 36
イベント送信処理 • メディア1で実装するEventTracker ◦ EventProxyがAもしくはBのEventを持っていた場合 それぞれの固有処理へ渡す • メディア2で実装するEventTracker ◦ EventProxyがCのEventを持っていた場合Cの固有処理
へ渡す 37
• 呼び出し側の動き ◦ 送信したいタイミングでEventProxyをEventTracker へ渡すだけ ◦ EventTrackerはメディアの実装がDIされるので 共通機能から呼んでもメディア固有の処理が走る ▪ 呼び出し側はEventProxyさえ知っていればいいので
どの計測PFへ送信するか意識しなくてよい 38 イベント送信処理
図にするとこんな感じ 39
40 使用する計測PFを どのように切り替えるか
41 おわかりですね?
メディアごとに依存 モジュールを変える! 42
メディアごとに依存モジュールを変える • 計測PFごとにfeatureモジュールを作成する ◦ 計測PFへイベント送信するという1つの機能として抽象化 ◦ メディアモジュールから依存することでその機能を 使えるようになる ◦ 各計測PFのSDKはこのfeatureモジュールからのみ依存
▪ 計測PF固有の処理がfeatureモジュールに閉じたものになり、 メディア固有ではなくなる 43
メディアごとに依存モジュールを変える • 計測PF固有のイベント送信処理も抽象化し、 共通モジュールにinterfaceで定義する • 各メディアで実装したEventTrackerから 抽象化した処理を呼び出せばよい 44
45 計測PF固有処理のコード class PlatformA @Inject constructor( // 計測プラットフォームの SDKがDIされる private
val sdk: SDK, ): AnalyticsPlatform { override fun track(event: Event) { // SDKを使った計測プラットフォーム固有の送信処理 } }
46 メディアで実装するEventTracker class EventTrackerImpl @Inject constructor( // 本来はメディアが依存する複数の計測 PFがDIされる private
val platform: AnalyticsPlatform, ): EventTracker { override fun track(eventProxy: EventProxy) { // それぞれの Eventを送信する処理 platform.track(eventProxy.event) } }
図にするとこんな感じ 47
似た話聞いたな 🤔 48
49 なにが似ているのか • EventTracker ◦ イベント送信というGigaViewer for Appsの機能として • featureモジュール
◦ 計測PFへイベント送信するという機能として
50 要は
メディアごとに 適切な計測PFへ イベント送信する機能 51
メディアごとに 適切な計測PFへ イベント送信 する機能 52
これで考えることは できたので 53
54 方針に沿っているか
55 方針① • メディア・計測PFを意識しないでイベント送信 ◦ ✅呼び出し側は共通モジュールに定義されている interfaceさえ知っていればいい ◦ ✅EventProxyをEventTrackerへ渡すだけ ◦
❌抽象化したはずのEventProxyがすべての計測PFを 知ってしまっているのが少し気になる ▪ 各Eventのパラメータが多いとEventProxyのパラメータが膨大に なる問題もある
方針② • 拡張性を持たせる ◦ ✅yamlに追記することで管理可能 ◦ ✅計測PFの追加は新たにfeatureモジュールを 作成すればOK ◦ ✅新規メディアはfeatureモジュールに依存するだけ
◦ ❌EventTrackerを実装しないといけない ▪ 計測PF固有の送信する処理も抽象化しているのでメディア毎に 実装しなくてもいいはず… 56
57 まとめ
58 まとめ • ひとことで機能といってもマルチテナントだと 複雑になってしまうことがよくある ◦ メディアの機能開発でもGigaViewer for Appsを開発 しているという意識
▪ うまく抽象化して実装できるとよい ◦ マルチテナント設計を意識した開発はとても楽しい