Microservices Meetup vol.9 (FiNC App & Frontend)
FiNCのアプリ/Webフロントエンジニアがクライアントサイド視点でのマイクロサービスを語ります
https://microservices-meetup.connpass.com/event/105174/
「次次回くらいから他社さんと一緒に主催とかも考えているので「マイクロサービスやってるよ」という会社さんはご連絡ください」 @qsona さん談
ウェルカムトーク「マイクロサービスとクライアント: 理想と現実の狭間で」 by @qsona
マイクロサービスの良さ
- 技術異質性
- 回復性
- デプロイ独立
- 小さく独立した組織
これらの特徴はサービスの疎結合によるもの
マイクロサービスにすれば疎結合になるわけではない現実
マイクロサービスを結合する者たち
- 事業計画
- インフラストラクチャ
- フロントエンド
- 営業
- DB結合
- などなど
結合の例) マイクロサービスと営業
- 通常営業スタッフは特定のマイクロサービスに属さない
- しかし属していたら
- サービスに愛着を持つ、理解を深める
- エンドユーザからしたらたまったものじゃない
結合の例) マイクロサービスと横断ビジネス
- 複数のマイクロサービスを横断的に利用するビジネスモデル
- FiNCの例: 特茶スマートアプリ
- 特茶経由のユーザーにチュートリアルやミッション、Push通知を出し分ける
- それぞれがマイクロサービスに対応する
- コミュニケーション経路が複雑
- 責任の所在が曖昧になりがち
- 優先順位付け
- 今回は特茶最優先だったから問題にならなかった
第2部: フロントエンド
フロントエンドで結合
- フロントエンドエンジニアはエンドユーザを強く意識
- フロントエンドは全体をつなぐハブのような存在
どんな取り組みをしてきたか
- バックエンドAPIはリソースを意識する
- BFF: Backends For Frontends
- 積極的に結合を引き受け複雑さに対応
- Microfrontends
- 結合をUI層に移し薄くする
エンドユーザにとっての理想
開発者にとっての理想
それらをつなぎこむ
「クライアントサイドから考えるマイクロサービス」 by @neonankiti
実装コストはほぼ変わらない
マイクロサービスは銀の弾丸ではない
運用の課題と解決
サービス間の差異
- サービスによって同じリソースに対するフォーマットが異なる
- 共有カーネル(DDDの文脈)複数のコンテキストで共有のモデルを持つこと
サブセットのルール
- チーム内で共有
- 変更はチームで合意の上
- テストを通っていること
サービス間の差異の吸収
- 腐敗防止層を設ける
- BFF
そもそも
- サーバーが同一リソースに対して異なるJSONを返すことを想定していない
- ドメインモデルが異なっていた
ドメインはサービス間で共有するべき
これらの問題はマイクロサービスが原因ではない、マイクロサービスはきっかけである
システムの潜在的な課題が明白にされることで「マイクロサービスの課題」のように見えているだけ
iOS/Androidチーム間のコミュニケーション強化→Client Fusion
お互いのチームのことを知るように、コミュニケーションを取るように試みた。設計のシェアなど。
- クライアント全体定例
- 開発メンバーが集って横断的な技術のシェア
- リード定例
- 各チームのTechLeadが集まって情報交換
効果が出た。今ではほぼチーム間齟齬がない。
ただし、関係者が増えたせいで意思決定のスピードが低下
エンジニアのみで集まると「べき論」が多くなってしまう
ビジネスインパクトの最小単位に重点をおいたチーム構築
エンジニアだけではなく、ディレクターやセールス
縦横にスイッチできること
マイクロアプリ
- クライアントアプリ内の分割されたマイクロサービス
- アプリの課題
- WEbとアプリのシームレスな体験ができない
- アプリインストール画面に飛んだり
- アプリサイズ大きい
- 解決すること
- インストールステップの削減
- アプリサイズの削減
- Instant App
- マイクロアプリ≒マルチモジュール
- マルチモジュールのすゝめ
「マイクロサービスとクライアントとコンテキスト境界」 by @takasek
クライアント、サーバー間のコンテキスト境界を設定するか
境界はチーム編成の輪郭に従う
Domainをどのように使うかを定義するUseCase
ドメインモデルのデータをView用に変換するViewModel
クライアント、サーバー間を分離するRepository
コンテキスト境界をどこに置くか:BFFの場合
- クライアントが純粋なビュアーとして機能する
- BFFに集中する
- 分散コンピューティングの原則から外れる
コンテキスト境界をどこに置くか:Repositoryの場合
- 整合性の心配事をドメインあら排除できる
- ビジネスロジック #とは
コンテキスト境界をどこに置くか:UseCaseの場合
- サーバーのコンテキストをクライアントでどのように扱うか=ビジネスロジックであるという認識
- プラットフォームの重複実装
コンテキスト境界をどこに置くか:ViewModelの場合
- ViewModelの責務
- 操作の伝達
- プレゼンテーション状態の保持
- View用データの変換
- 画面間の整合性の担保
- 。。。。。。
- アンチパターンっぽい
コンテキスト境界をどこに置くか:Viewの場合
- いわゆるMicroFrontends
- アプリの場合はViewはマイクロサービスではない
- 画面コンポーネントの整合性を気にしなければならない
クライアントが担保すべき整合性
- ModelとModel
- ModelとView
- ViewとView
質問タイム
Q. リソースを完全に定義したらクライアント、サーバー間で重複定義は不要?
チーム間のコミュニケーションがまだあまり円滑でなかった(※)ときに、完全なリソース定義ができないと判断して重複定義している
※フロント/バック、アプリ/ウェブ、横断的なスキルセットを持つ人がいない、など
Q. BFFがあってもクライアントサイドであんなにレイヤ組むもの?
もともとBFFがなかった頃の名残で、現在アーキテクチャを見直し中
「実践、BFF ~ BFFはFiNCのアプリで何を解決したのか ~」 by @izmeal2000
BFFのおさらいと、導入実例
一般的な定義: MicroservicesのAPI群を集約
FiNC Appにおいてどんな課題を解決しているか
- 通信パフォーマンス
- 集約ロジックの分散
- 些細な挙動変更にも申請が必要
通信パフォーマンス
- 遅い回線で複数回のリクエスト
- BFFでモバイル回線の負荷軽減
集約ロジック
- 集約ロジックの分散
- ほとんど同じ機能の無駄な実装コスト軽減
- 挙動に差分が発生しない
変更に対する疎結合
- 集約ロジックをBFFで持つ
- 挙動変更に耐性
導入実践
マイクロサービスをまたがる機能
- ポイントが貯まるキャンペーン
- ポイントが貯まるライフログ
- ポイントが貯まるミッション
15リクエストが6リクエストになった!!
1リクエストにまとめればもっとよいのでは?
- 全部を待つので遅くなる
- 一部が遅いとすべて遅くなる
- 一部をリトライしたいときにすべてリトライになる
適切な粒度でAPIを設計するのが大事
集約ロジックの共有
1つの機能でも複数のドメインが関連している
ライフログ一つとっても睡眠や、食事でデータ形式が異なる
→BFFでデータ形式を揃える
BFFでのデータ構造を変換するのはありか
- クライアントのインタラクションによるデータ更新がやりにくい
- ケースバイケース
レスポンスによる表示切り替え
- 達成した目標をクライアント側で非表示にしていた
- 実装後にやっぱり表示したいという要望がビジネスサイドから来た
これはBFFでデータを返さないようにしていただけなので、データを返すようにするだけで変更に対応できた
BFFの持ち主
BFFはUIチームの持ち物
フロントエンドエンジニアが開発しやすいようにKotlin + Spring Webflux + protobufで再開発中。
「お礼ポイント投票機能をSPAに実装してMicro Frontendsを実践している話」 by @nobuhikosawai
Micro Frontendsとは
フロントエンドまで提供するマイクロサービス
昨今の開発: マルチクライアント、フロント/サーバー
バックエンドはマイクロサービスとして分かれている
フロントエンドモノリスが多い
UIがないとユーザー価値が提供できない、UIも提供したい
技術スタック
- iframe
- Web Components
- Custom Element
- ShadowDOM, HTML Templates
- CustomEvents
Micro Frontendsの実践
ビジネス背景
- アプリのWEB版がある
- レガシーになってた
- お礼を伝えるピアボーナス機能を作ることになった
- 一度MicroFrontendsを提供すればどんどん追加できる
- 必要に応じてリプレイスも
背景
- SPAはビルドが必要
- ビルドするたびに違うファイル名で提供する
- キャッシュ対策
- 1つのサービスでビルドもindex.htmlの提供もしているなら問題ない
課題
- サービスがUI提供側とビルド側で分かれている
- manifest.jsonで解決できる
- つけたいファイル名とビルドしたファイル名を紐付けるファイル
- いつ取得するか
- ブラウザでページを描画した後か、前か
- 描画後はおそすぎるため、描画前に取得 - index.htmlのみSSRした
認証
- localStorageにtoken持ってた
- Micro Frontendsではどうするか
- 統合レイヤーに合わせる
- ただし、各サービスがlocalStorageが触るのは危険
- とりあえずwindowにgetter関数をはやした
画面遷移
- aタグで遷移するとSPAの遷移ができない
- history apiで行う
- 各コンポーネントで自由に遷移させていいのか
- 親にイベントを投げる
- 親が遷移
- 右クリックが使えない
- Webの体験と整合しない
- 結局Aタグ
- history api
- 親にイベントをなげて遷移するのは一緒?
- 親にイベントを投げる
Micro Frontendsでのコンポーネント間
- CustomEventsを使う
- UI統合レイヤーが制御
- 各サービスドメインごとにまとまった状態を持つ形で提供
- 同一ドメインであればそれが1つの遷移状態として扱う
- ドメイン内のコンポーネントは普通に遷移させる
ReactでShadowDOM使う問題
- ReactとShadowDOMが一緒に使えない?
- Reactのイベントハンドリングの負債が原因らしい
- React Fireという負債返済プロジェクトでも話題に上がっている
考察
- Micro Frontendsは実戦投入可能
- 開発は独立してリリースできるのでチームの独立性を確保
- パフォーマンス問題は残りそう
- SSRがあったほうがいい
- BFFとの違い
- 集約するレイヤーが違う
質問
Q. BFFでSpring WebFlux使っている背景
ノンブロッキングI/Oがほしかったため
Q. 15サービスくらいあったときにBFF無いのがつらそう
意外と大変ではなかった。結合が増えてくると大変だった
BFFの導入は遅らせて正解だったかも、と思っている
Q. 更新系もBFF?
更新系はアグリゲーションしない方針
複数更新時は1つずつ更新リクエストを投げている
スポンサートーク
FiNCがなぜマイクロサービスをやっているか
やりたいこと
- とにかく人々を健康したい
- 意識が高くない人にリーチしたい
必要なこと
- 行動変容
- あらゆるステージの人にサービスを提供していく
なぜマイクロサービス
- 一つのサービスでは達成できない
多く展開するため
-
backend
- RoR
-
client
- React, redux, ...
-
BFF
- ...
飛び入りLT枠