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
760
マルチテナントにおけるイベント計測の話
r4wxii
September 19, 2024
Tweet
Share
Featured
See All Featured
Fontdeck: Realign not Redesign
paulrobertlloyd
81
5.2k
What's in a price? How to price your products and services
michaelherold
243
11k
How to train your dragon (web standard)
notwaldorf
87
5.6k
A better future with KSS
kneath
236
17k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
We Have a Design System, Now What?
morganepeng
49
7.1k
Atom: Resistance is Futile
akmur
261
25k
A designer walks into a library…
pauljervisheath
202
24k
What's new in Ruby 2.0
geeforr
341
31k
Practical Orchestrator
shlominoach
186
10k
Building a Scalable Design System with Sketch
lauravandoore
459
32k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2k
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を開発 しているという意識
▪ うまく抽象化して実装できるとよい ◦ マルチテナント設計を意識した開発はとても楽しい