6
会計 freee の基本的な構成
主に今回注目している部分について
会計 freee
Rails App
Web
フロント
Private API
Controller
Service
モバイル
アプリ
3rd Party
Client
Public API
Controller
Admin
Controller
Model
銀行等
人事労務 freee
Rails App
マイクロサービス
Slide 7
Slide 7 text
7
会計 freee の基本的な構成
ある1つの機能について、各チームの担当領域
会計 freee
Rails App
Web
フロント
Private API
Controller
Service
モバイル
アプリ
3rd Party
Client
Public API
Controller
Admin
Controller
Model
銀行等
人事労務 freee
Rails App
マイクロサービス
会計チーム
モバイルチーム
API チーム
いくつかの
チーム
14
モジュラモノリス
Rails Engine を使った場合の単純な例
Rails App
機能 A
Rails Engine
Model
Controller
機能 B
Rails Engine
Model
Controller
Slide 15
Slide 15 text
● Backend API というものを新しく定義して導入する
● Controller などは Backend API を利用する立場と定義する
● Backend API の内側をモジュラモノリスにおけるモジュールと定義する
● この単位でモジュラモノリス化を進めていく
15
会計 freee ではどうするか
会計 freee
Rails App
Module
Model
Service
Controller API
Slide 16
Slide 16 text
● Backend 内部の API の意味(Web API とは別物)
● Service のインタフェースを明示的にしたもの
● 現時点では Protobuf を採用
○ マイクロサービス化したときにそのまま gRPC に流用可能
○ API に ActiveRecord を登場させないという意思
16
Backend API
Slide 17
Slide 17 text
● ある機能に属するテーブルに対応する ActiveRecord Model は、その機能の
Backend API を実装する Service 内でだけ使用可能
● 機能をまたいで ActiveRecord Model の関連を作らない
● ある機能Aの Backend Service 内部から別の機能Bに属するテーブルを読み書きす
る場合は、Bの Backend Service を経由する
● (超汎用的なテーブルなど例外はある)
17
Backend API と共に導入する制約
Slide 18
Slide 18 text
18
Backend API と共に導入する制約
ある機能に属するテーブルに対応する ActiveRecord Model は、
その機能の Backend API を実装する Service 内でだけ使用可能
会計 freee
Rails App
機能 A
Model A
Service A
機能 B
Service B
これもダメ
Controller
これはダメ
Slide 19
Slide 19 text
19
Backend API と共に導入する制約
機能をまたいで ActiveRecord Model の関連を作らない
会計 freee
Rails App
機能 B
Service B
機能 A
Model A1
Service A
Model A2 Model A3
Model B1
Model B2
これはダメ
Slide 20
Slide 20 text
20
Backend API と共に導入する制約
ある機能Aの Backend Service 内部から別の機能Bに属するテーブルを読み書きする場合
は、Bの Backend Service を経由する
会計 freee
Rails App
機能 A
Model A1
Service A
Model A2 Model A3
機能 B
Service B
Model B1
Model B2
OK
API B
Slide 21
Slide 21 text
● 機能と ActiveRecord Model の対応関係を設定ファイルとして用意
● DB 操作時に、現在のコンテキストから操作して良い Model なのかを判別
● development/test 環境でエラーにすることで強制力を持たせる
● 許容される関連かどうかは Model の関連を辿ったものと設定ファイルを比較すること
で検知し、CI で常にチェックする
21
どうやって制約をつけるか
Slide 22
Slide 22 text
● Private API を Web フロントエンドとモバイルアプリ両方から利用していたのをやめる
● モバイルアプリ向けに Mobile API を新設する
● 各チームが Controller のオーナーになり、他チームに影響を与えずに Web API を変
更していけるようにするため
22
Backend API と一緒に行う変更
Slide 23
Slide 23 text
23
Mobile API を新設
会計 freee
Rails App
機能 A
Model A1
Service A
Model A2 Model A3
Web
フロント
モバイル
アプリ
3rd Party
Client
Private API
Controller
Public API
Controller
Admin
Controller
API A
Slide 24
Slide 24 text
24
Mobile API を新設
会計 freee
Rails App
機能 A
Model A1
Service A
Model A2 Model A3
Web
フロント
モバイル
アプリ
3rd Party
Client
Private API
Controller
Public API
Controller
Admin
Controller
Mobile API
Controller
API A
Slide 25
Slide 25 text
25
Mobile API を新設
会計チーム
モバイルチーム
会計 freee
Rails App
いくつかの
チーム
機能 A
Model A1
Service A
Model A2 Model A3
Web
フロント
モバイル
アプリ
3rd Party
Client
Private API
Controller
Public API
Controller
API チーム
Admin
Controller
Mobile API
Controller
API A
Slide 26
Slide 26 text
26
Backend API 導入後の図
会計 freee
Rails App
機能 B
Service B
機能 A
Model A1
Service A
Model A2 Model A3
Model B1
Model B2
Web
フロント
モバイル
アプリ
3rd Party
Client
Private API
Controller
Public API
Controller
Admin
Controller
Mobile API
Controller
API A API B
Controller が Service A に直接依存しないように描かれているが、API A の存在を強調するためにそう描いているだけで実際には Service A に
直接依存する。A から B についても同様。実際の構成要素のうち説明に関係のないものは省いている。
Slide 27
Slide 27 text
● Service 実装より前にインタフェースを作ることになるため、Service 実装中でもモバ
イルアプリや Public API を並行で作れるようになる
○ これを行いたいのが発端だった
● 機能実装の影響範囲がはっきりする
● Web API の変更が各チーム内で完結する
27
Backend API 導入でどう良くなるか
Slide 28
Slide 28 text
● ActiveRecord が制限され、Rails Way から大幅に外れる
● Backend Service の外側では ActiveRecord を前提としたライブラリが使えなくなる
○ 例えばシリアライズのための ActiveModel::Serializer
○ 普通なら Model で関連を定義して preload を書いて終わりなデータ取得が面倒に
なる
● つまり、レールを自分たちで考え、作る必要がある
28
Backend API 導入のデメリット
Slide 29
Slide 29 text
● JSON シリアライズ時に ActiveRecord と Serializer は何を司っているのか
● Serializer
○ Model のシリアライズ後の構造を定義
○ Model をその構造に変換
● ActiveRecord
○ Model のデータを取得
○ 他の Model との関連を定義
29
脱 Rails Way の例
Serializer を使わないならどうするか
Slide 30
Slide 30 text
● JSON シリアライズ時に ActiveRecord と Serializer は何を司っているのか
● Serializer
○ Model のシリアライズ後の構造を定義
○ Model をその構造に変換
● ActiveRecord
○ Model のデータを取得
○ 他の Model との関連を定義
30
脱 Rails Way の例
Serializer を使わないならどうするか
ViewModel
ViewModelBuilder
Fetcher
Slide 31
Slide 31 text
● ViewModel
○ 構造を定義するのみ
● ViewModelBuilder
○ Model を ViewModel に変換する
○ 変換時に必要になる関連先 Model とそれを取得する Fetcher を定義する
■ Builder は定義するだけで、具体的な取得方法は知る必要がない
■ ActiveRecord は使わないけど preload のような動きを実現
● Fetcher
○ Backend Service を用いて関連先 Model を取得する
31
脱 Rails Way の例
コードレベルで解説する時間枠がないので、詳しくはいずれ freee Developers Blog にて紹介
する