Slide 1

Slide 1 text

freee 株式会社
 会計 freee バックエンドの今後
 〜 Backend API の導入 〜


Slide 2

Slide 2 text

2016年、freee 株式会社へ入社。
 以降ずっと会計 freee の開発を行なっている。
 社内でも基本ハンネで生きている。
 
 仕事では1つのアプリケーションをオーナーシップを 持ちつつ長く開発運用していくのが好き。長く運用 する前提でコードを書きたい。
 
 逆にプライベートでは興味が行ったり来たり。
 最近は nand2tetris をちまちま進めている。
 @mihyaeru21 ミヒャエル
 freee株式会社
 2

Slide 3

Slide 3 text

3 Mission スモールビジネスを、 世界の主役に。 freeeは「スモールビジネスを、世界の主役に。」 をミッションに掲げ、 「アイデアやパッションやスキルがあればだれでも、 ビジネスを強くスマートに育てられるプラットフォーム」 の実現を目指してサービスの開発及び提供をしております。 大胆に、スピード感をもってアイデアを具現化することができる スモールビジネスは、様々なイノベーションを生むと同時に、 大企業を刺激して世の中全体に新たなムーブメントを起こすことができる存在だと考えております。 会社概要
 会社概要
 会社概要
 3

Slide 4

Slide 4 text

スモールビジネス向けに統合型クラウドERPを提供 請求書 | 経費精算 | 決算書 | 予実管理 | 内部統制
 統合型クラウド(1)会計ソフト
 統合型クラウド人事労務ソフト 2013年3月~ 日本のクラウド市場 シェアNo.1 (2) 2014年10月~ 日本のクラウド市場 シェアNo.1 (3) 勤怠管理 | 入退社管理 | 給与計算 | 年末調整
 マイナンバー管理
 その他サービス
 会社設立 開業 税務申告 マイナンバー管理 クレジットカード フリーカード
 4 プロジェクト 管理 注: 1. クラウドサービス:ソフトウェアやハードウェアを所有することなく、ユーザーがインターネットを経由してITシステムにアクセスを行えるサービス 2. 株式会社BCN「クラウド会計ソフトを導入している従業員数300名未満の企業又は個人事業主へのWeb調査(2017年9月実施、2017年10月公表))」(N=418) 3. クラウド給与計算ソフトの市場シェア:株式会社MM総研「日本におけるクラウド給与計算ソフトの利用状況調査に関するWeb調査(2016年3月実施)」(N=4,168)

Slide 5

Slide 5 text

● バックエンドは Rails
 ○ 巨大なモノリス+いくつかのマイクロサービス
 ○ 人事労務 freee など、他の社内プロダクトとの連携あり
 ○ 銀行などの明細を取得する部分も含んでいる
 ■ これはサービス切り出しが進んでいる
 ○ Service, Presenter, Form など、よくありそうなのが app 以下にある
 ○ lib 以下がカオス
 ● フロントエンドは React
 5 会計 freee の基本的な構成


Slide 6

Slide 6 text

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 チーム
 いくつかの チーム


Slide 8

Slide 8 text

8 会計 freee の開発に関する数字
 テーブル数
 700くらい
 Ruby ファイル数
 10000くらい
 JavaScript ファイル数
 5000くらい
 routes
 4000くらい
 1ヶ月のコミット数
 2000くらい
 1ヶ月のプルリクエスト数
 1000くらい


Slide 9

Slide 9 text

● 影響範囲が読めなすぎる
 ● リファクタリングが怖い
 ● 同じく Web API の変更が難しい・変更リスクが高い
 ● Web フロントエンド以外の開発が後回しになる
 ● etc...
 9 大きさとのコンボで辛くなる問題点


Slide 10

Slide 10 text

どう戦っていくか
 10

Slide 11

Slide 11 text

11 基本方針
 開発者が見るべきスコープを狭める
 
 
 実装時に気をつけないといけない範囲が広くなりすぎているため、適度に狭めてあげることで開発効率を維持す る。チームごとの担当領域を区切ることでスコープにオーナーシップを明確化する。
 
 ActiveRecord には制限をかける。どこからでも何でもできてしまうため、ある程度の制限を設けないと安心してス コープを狭めることができない。


Slide 12

Slide 12 text

● 2年ほど前に会計 freee の一部機能をマイクロサービスに切り出した
 ○ これは freee Tech Night にて話した
 ○ 書き込み系は完了したが読み込み系が少し残り、DB 分離が完了していない
 ■ 別プロダクトからも使いたかった要求は満たせている
 ■ 移行に見積もりより多くの時間をかけてしまったため、他タスクとの兼ね合いで 優先度を上げられていない
 ● 機能を分離する目的だけでマイクロサービス化はしないほうが良い
 ○ そもそも機能の分離をしないとマイクロサービス化できない
 12 つまりマイクロサービス?


Slide 13

Slide 13 text

● 分離したい機能をアプリケーション内でモジュールとして分離する
 ○ たとえば Rails なら Rails Engine として分離
 ○ たとえばモジュールのインポートが明示的な環境ならモジュールで分離
 ● マイクロサービスでとくに頭が痛くなるトランザクションをどうするかという問題を後回 しにできる
 ● 「Modular Monolith」で検索すると Shopify の例がよく出てくる
 13 モジュラモノリス


Slide 14

Slide 14 text

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 にて紹介 する


Slide 32

Slide 32 text

● ざっくりした PoC の実装を終えた
 ● 1つの機能を対象にして実際に Backend API を導入中
 ○ PoC では見えなかった細かい問題と戦いながら仕組み化中
 32 現在の状況


Slide 33

Slide 33 text

● 「開発者が見るべきスコープを狭める」という基本方針
 ○ 開発者とコードが増えても安全を確保しつつ開発速度を維持するため
 ● モジュラモノリスを目指す
 ● そのために Backend API を定義
 ● Rails Way から外れる部分は用途に応じて小さなレールを作る
 ○ 用途が限定されたレールは案外小さくシンプルに作れる
 33 まとめ


Slide 34

Slide 34 text

34 一緒に開発してくれる人を募集中!
 https://jobs.freee.co.jp/


Slide 35

Slide 35 text

スモールビジネスを、
 世界の主役に。