Upgrade to Pro — share decks privately, control downloads, hide ads and more …

会計 freee バックエンドの今後 / freee backend api

Mihyaeru
February 09, 2021

会計 freee バックエンドの今後 / freee backend api

【Engineering Team Presentation】各社の事業を支えるアーキテクチャ
https://sansan.connpass.com/event/200589/
での発表資料です。

Mihyaeru

February 09, 2021
Tweet

More Decks by Mihyaeru

Other Decks in Programming

Transcript

  1. freee 株式会社

    会計 freee バックエンドの今後

    〜 Backend API の導入 〜


    View full-size slide

  2. 2016年、freee 株式会社へ入社。

    以降ずっと会計 freee の開発を行なっている。

    社内でも基本ハンネで生きている。


    仕事では1つのアプリケーションをオーナーシップを
    持ちつつ長く開発運用していくのが好き。長く運用
    する前提でコードを書きたい。


    逆にプライベートでは興味が行ったり来たり。

    最近は nand2tetris をちまちま進めている。

    @mihyaeru21
    ミヒャエル

    freee株式会社

    2

    View full-size slide

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

    会社概要

    会社概要

    3

    View full-size slide

  4. スモールビジネス向けに統合型クラウド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)

    View full-size slide

  5. ● バックエンドは Rails

    ○ 巨大なモノリス+いくつかのマイクロサービス

    ○ 人事労務 freee など、他の社内プロダクトとの連携あり

    ○ 銀行などの明細を取得する部分も含んでいる

    ■ これはサービス切り出しが進んでいる

    ○ Service, Presenter, Form など、よくありそうなのが app 以下にある

    ○ lib 以下がカオス

    ● フロントエンドは React

    5
    会計 freee の基本的な構成


    View full-size slide

  6. 6
    会計 freee の基本的な構成

    主に今回注目している部分について

    会計 freee

    Rails App

    Web

    フロント

    Private API

    Controller

    Service

    モバイル

    アプリ

    3rd Party

    Client

    Public API

    Controller

    Admin

    Controller

    Model

    銀行等

    人事労務 freee

    Rails App

    マイクロサービス


    View full-size slide

  7. 7
    会計 freee の基本的な構成

    ある1つの機能について、各チームの担当領域

    会計 freee

    Rails App

    Web

    フロント

    Private API

    Controller

    Service

    モバイル

    アプリ

    3rd Party

    Client

    Public API

    Controller

    Admin

    Controller

    Model

    銀行等

    人事労務 freee

    Rails App

    マイクロサービス

    会計チーム

    モバイルチーム

    API チーム

    いくつかの
    チーム


    View full-size slide

  8. 8
    会計 freee の開発に関する数字

    テーブル数
 700くらい

    Ruby ファイル数
 10000くらい

    JavaScript ファイル数
 5000くらい

    routes
 4000くらい

    1ヶ月のコミット数
 2000くらい

    1ヶ月のプルリクエスト数
 1000くらい


    View full-size slide

  9. ● 影響範囲が読めなすぎる

    ● リファクタリングが怖い

    ● 同じく Web API の変更が難しい・変更リスクが高い

    ● Web フロントエンド以外の開発が後回しになる

    ● etc...

    9
    大きさとのコンボで辛くなる問題点


    View full-size slide

  10. どう戦っていくか

    10

    View full-size slide

  11. 11
    基本方針

    開発者が見るべきスコープを狭める



    実装時に気をつけないといけない範囲が広くなりすぎているため、適度に狭めてあげることで開発効率を維持す
    る。チームごとの担当領域を区切ることでスコープにオーナーシップを明確化する。


    ActiveRecord には制限をかける。どこからでも何でもできてしまうため、ある程度の制限を設けないと安心してス
    コープを狭めることができない。


    View full-size slide

  12. ● 2年ほど前に会計 freee の一部機能をマイクロサービスに切り出した

    ○ これは freee Tech Night にて話した

    ○ 書き込み系は完了したが読み込み系が少し残り、DB 分離が完了していない

    ■ 別プロダクトからも使いたかった要求は満たせている

    ■ 移行に見積もりより多くの時間をかけてしまったため、他タスクとの兼ね合いで
    優先度を上げられていない

    ● 機能を分離する目的だけでマイクロサービス化はしないほうが良い

    ○ そもそも機能の分離をしないとマイクロサービス化できない

    12
    つまりマイクロサービス?


    View full-size slide

  13. ● 分離したい機能をアプリケーション内でモジュールとして分離する

    ○ たとえば Rails なら Rails Engine として分離

    ○ たとえばモジュールのインポートが明示的な環境ならモジュールで分離

    ● マイクロサービスでとくに頭が痛くなるトランザクションをどうするかという問題を後回
    しにできる

    ● 「Modular Monolith」で検索すると Shopify の例がよく出てくる

    13
    モジュラモノリス


    View full-size slide

  14. 14
    モジュラモノリス

    Rails Engine を使った場合の単純な例

    Rails App

    機能 A

    Rails Engine

    Model

    Controller

    機能 B

    Rails Engine

    Model

    Controller


    View full-size slide

  15. ● Backend API というものを新しく定義して導入する

    ● Controller などは Backend API を利用する立場と定義する

    ● Backend API の内側をモジュラモノリスにおけるモジュールと定義する

    ● この単位でモジュラモノリス化を進めていく

    15
    会計 freee ではどうするか

    会計 freee

    Rails App

    Module

    Model

    Service

    Controller
 API


    View full-size slide

  16. ● Backend 内部の API の意味(Web API とは別物)

    ● Service のインタフェースを明示的にしたもの

    ● 現時点では Protobuf を採用

    ○ マイクロサービス化したときにそのまま gRPC に流用可能

    ○ API に ActiveRecord を登場させないという意思

    16
    Backend API


    View full-size slide

  17. ● ある機能に属するテーブルに対応する ActiveRecord Model は、その機能の
    Backend API を実装する Service 内でだけ使用可能

    ● 機能をまたいで ActiveRecord Model の関連を作らない

    ● ある機能Aの Backend Service 内部から別の機能Bに属するテーブルを読み書きす
    る場合は、Bの Backend Service を経由する

    ● (超汎用的なテーブルなど例外はある)

    17
    Backend API と共に導入する制約


    View full-size slide

  18. 18
    Backend API と共に導入する制約

    ある機能に属するテーブルに対応する ActiveRecord Model は、

    その機能の Backend API を実装する Service 内でだけ使用可能

    会計 freee

    Rails App

    機能 A

    Model A

    Service A

    機能 B

    Service B

    これもダメ

    Controller

    これはダメ


    View full-size slide

  19. 19
    Backend API と共に導入する制約

    機能をまたいで ActiveRecord Model の関連を作らない

    会計 freee

    Rails App

    機能 B

    Service B

    機能 A

    Model A1

    Service A

    Model A2
 Model A3

    Model B1

    Model B2

    これはダメ


    View full-size slide

  20. 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


    View full-size slide

  21. ● 機能と ActiveRecord Model の対応関係を設定ファイルとして用意


    ● DB 操作時に、現在のコンテキストから操作して良い Model なのかを判別

    ● development/test 環境でエラーにすることで強制力を持たせる


    ● 許容される関連かどうかは Model の関連を辿ったものと設定ファイルを比較すること
    で検知し、CI で常にチェックする

    21
    どうやって制約をつけるか


    View full-size slide

  22. ● Private API を Web フロントエンドとモバイルアプリ両方から利用していたのをやめる

    ● モバイルアプリ向けに Mobile API を新設する

    ● 各チームが Controller のオーナーになり、他チームに影響を与えずに Web API を変
    更していけるようにするため

    22
    Backend API と一緒に行う変更


    View full-size slide

  23. 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


    View full-size slide

  24. 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


    View full-size slide

  25. 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


    View full-size slide

  26. 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 についても同様。実際の構成要素のうち説明に関係のないものは省いている。


    View full-size slide

  27. ● Service 実装より前にインタフェースを作ることになるため、Service 実装中でもモバ
    イルアプリや Public API を並行で作れるようになる

    ○ これを行いたいのが発端だった

    ● 機能実装の影響範囲がはっきりする

    ● Web API の変更が各チーム内で完結する

    27
    Backend API 導入でどう良くなるか


    View full-size slide

  28. ● ActiveRecord が制限され、Rails Way から大幅に外れる

    ● Backend Service の外側では ActiveRecord を前提としたライブラリが使えなくなる

    ○ 例えばシリアライズのための ActiveModel::Serializer

    ○ 普通なら Model で関連を定義して preload を書いて終わりなデータ取得が面倒に
    なる

    ● つまり、レールを自分たちで考え、作る必要がある

    28
    Backend API 導入のデメリット


    View full-size slide

  29. ● JSON シリアライズ時に ActiveRecord と Serializer は何を司っているのか


    ● Serializer

    ○ Model のシリアライズ後の構造を定義

    ○ Model をその構造に変換

    ● ActiveRecord

    ○ Model のデータを取得

    ○ 他の Model との関連を定義

    29
    脱 Rails Way の例

    Serializer を使わないならどうするか


    View full-size slide

  30. ● JSON シリアライズ時に ActiveRecord と Serializer は何を司っているのか


    ● Serializer

    ○ Model のシリアライズ後の構造を定義

    ○ Model をその構造に変換

    ● ActiveRecord

    ○ Model のデータを取得

    ○ 他の Model との関連を定義

    30
    脱 Rails Way の例

    Serializer を使わないならどうするか

    ViewModel

    ViewModelBuilder

    Fetcher


    View full-size slide

  31. ● ViewModel

    ○ 構造を定義するのみ

    ● ViewModelBuilder

    ○ Model を ViewModel に変換する

    ○ 変換時に必要になる関連先 Model とそれを取得する Fetcher を定義する

    ■ Builder は定義するだけで、具体的な取得方法は知る必要がない

    ■ ActiveRecord は使わないけど preload のような動きを実現

    ● Fetcher

    ○ Backend Service を用いて関連先 Model を取得する

    31
    脱 Rails Way の例

    コードレベルで解説する時間枠がないので、詳しくはいずれ freee Developers Blog にて紹介
    する


    View full-size slide

  32. ● ざっくりした PoC の実装を終えた

    ● 1つの機能を対象にして実際に Backend API を導入中

    ○ PoC では見えなかった細かい問題と戦いながら仕組み化中

    32
    現在の状況


    View full-size slide

  33. ● 「開発者が見るべきスコープを狭める」という基本方針

    ○ 開発者とコードが増えても安全を確保しつつ開発速度を維持するため

    ● モジュラモノリスを目指す

    ● そのために Backend API を定義

    ● Rails Way から外れる部分は用途に応じて小さなレールを作る

    ○ 用途が限定されたレールは案外小さくシンプルに作れる

    33
    まとめ


    View full-size slide

  34. 34
    一緒に開発してくれる人を募集中!

    https://jobs.freee.co.jp/


    View full-size slide

  35. スモールビジネスを、

    世界の主役に。


    View full-size slide