Slide 1

Slide 1 text

プロダクトと⼀緒に成⻑できる MVCフレームワークの使い⽅ 〜 Ruby on Railsを例に 〜 @hiromichinomata

Slide 2

Slide 2 text

MVCが得意なところ苦⼿なところ

Slide 3

Slide 3 text

MVCフレームワークとは • Web開発でよく使われる設計の⼀つ • Model(M), View(V), Controller(C) • データベースの操作、表示、全体制御 • 採⽤例: Ruby on Rails、Django(MVT)、 Laravel、 Blitz.js • 不採⽤例 • リクエストからレスポンスまで⼀つの関数 • Event Sourcing(Lagom)

Slide 4

Slide 4 text

MVCが使われる理由 • ⾼い⽣産性(少なくとも初期では) • Y Combinatorで評価額が⼤きく上がっ た⾔語 https://charliereese.ca/article/top-50-y-combinator-tech-startups (ゲーム、ハードウェア、リプレイス除く) • スタートアップにおいて90%はRailsみ たいなことで実現できる

Slide 5

Slide 5 text

MVC(RDBMS)が使われる理由 • MVCのMはRDBMS(MySQL, PostgreSQL)と密結合 • NoSQLのプロダクトトレンドからのズレ • Web広告の規制: DSPの優先度低下 • ソシャゲ ガチャ規制: 技術⼒ != ⼤量のアクセスを捌く • 機械学習ブーム: パーソナライズ(集計)がより重要に • 位置情報(ARグラス、⾃動運転)が重要になればNoSQL復活するかも?

Slide 6

Slide 6 text

MVCフレームワークでなくても苦⼿なところ • Span of Controlと単⼀名前空間の限界 • ⼈とシステムは連動している(コンウェイの法則) • Span of control: 5-9⼈ • マネジャーが⾒れないならメンバーはもっと⾒れない => 名前空間は分けよう(Railsの機能としてある)

Slide 7

Slide 7 text

MVCフレームワークが苦⼿なところ • ActiveRecord(ORM)はModel: Table = 1:1に特化 • ActiveRecord内で複数テーブルを⼀括操作するのは苦⼿ • 規模が⼩さいとMVC有利 • Controller => Model <=> Table • 規模が⼤きいとドメインモデル(中間概念)優位 • Controller => Repository => Model <=> Table

Slide 8

Slide 8 text

チーム分割と MVCフレームワークの モジュール化

Slide 9

Slide 9 text

分け⽅のルートはどこか • role: User/Company/Admin/API • シンプルだがmodel共通になりがち。認知負荷の減少が少ない • Read/Write: CQRS(Command Query Responsibility Segregation) • GraphQL: Query/Mutation. MVCフレームワークと相性悪い • domain: 似た機能でまとめる • 何度でも適⽤可能(Shopify)だが分割の位置を決めるのが⼤変

Slide 10

Slide 10 text

機能分割単位とデプロイ単位は独⽴ • モノリス: 素のRails. 同⼀名前空間に全て詰める • モジュラーモノリス: Shopify (Rails Engine) • ミニサービス: デプロイ単位が複数モジュール • マイクロサービス: デプロイ単位が1モジュール

Slide 11

Slide 11 text

モノリスファースト • マイクロサービスの提唱者 「モノリスファースト」 • マイクロサービスのドメイン境界決定は熟考が必要 • マイクロサービスのトランザクションは難しい • モノリス => モジュラーモノリス => ミニサービス => マイクロサー ビス

Slide 12

Slide 12 text

地続き感のあるドメイン境界の決め⽅ • ⾛り切ってしまったチームは開発を⽌めてドメインを整理 => 開発を⽌めずActiveRecordパターンから地続きでドメインモデルに移⾏したい • ロールであたりをつける • User: /u/posts, Company: /c/info • BtoCの⽅がCtoCより有利 => CtoCでもロールで整理しておく • /creator/posts, /watcher/search • X: user_infos, O: creator_infos, watcher_infos

Slide 13

Slide 13 text

素のMVCからの切り出し⽅

Slide 14

Slide 14 text

サービスの複雑性の縦軸と横軸 ػೳ" ೝূ ػೳ# ܾࡁ ػೳ$ 幅(機能分割で乗り切る) 深さ(切り出しで乗り切る)

Slide 15

Slide 15 text

デプロイ単位を変えない切り出し⽅ 3FBE 8SJUF %FDPSBUPS4FSJBMJ[FS ୯Ұςʔϒϧ /" 7JFX.PEFM2VFSZ ෳ਺ςʔϒϧ /" 7BMJEBUPS /" ୯Ұςʔϒϧ 'PSN0CKFDU3FQPTJUPSZ ෳ਺ςʔϒϧ ෳ਺ςʔϒϧ 4FSWJDF $PODFSO  

Slide 16

Slide 16 text

デプロイ単位を変える切り出し⽅ • 例えば • 新規事業に既存事業のユーザーが欲しい • 決済は共通なので複数サービスで共⽤したい • レスポンス時間が合計されるので多段が増えると体験悪い • Goなどが有利だがサイト全体CDNをかける(Fastly)などの技も

Slide 17

Slide 17 text

地続きで別サービスに切り出すには(没案) • Active Resourceの場合(あまり使われない) • サービス間通信がORMのAPIと同じまま使えれば地続き • Blackboxでなく密結合 • GraphQLとか?

Slide 18

Slide 18 text

案: 全てのサービスはREST APIとする慣例 • SomeAbcServiceの引数はプリミティブ型とする(gRPCを参考に) • SomeAbcService.run(user_id: 123) => POST /internal/some_abc_service {user_id: 123} • サービスにはActiveRecordのインスタンスは直接渡さない • 設定でendpointは⾃身に向けるか別サーバーに向けるか選べる • HTTPを経由するオーバーヘッドは⼗分⼩さいとする

Slide 19

Slide 19 text

まとめ 開発を⽌めずにプロダクトと共にMVCフレームワークを成⻑させるには • 幅⽅向 • Span of Controlを超えるタイミングでドメインを元にモジュール分割の⾒直 し • 最初からロールごとに設計を整理してあると分割しやすい • 深さ⽅向 • MVCフレームワークデフォルトのディレクトリ構造だけで戦おうとせず都度 適切な切り出しの仕組みを使⽤