Slide 1

Slide 1 text

freee finance lab の歩み 〜モダンでフルサイクルな⾦融プロダクト開発〜 ogugu (Riku Ogura) 2023年4⽉16⽇

Slide 2

Slide 2 text

ここに円に切り抜いた画像を入れてく ださい ogugu (Riku Ogura) ● ヤフーに新卒⼊社。ヤフーショッピングのリアー キテクチャに従事。 ● → freeeへジョイン。freee⼈事労務の開発を担 当。モジュラモノリス化などに貢献。 ● → SREへ社内留学。 ● → ⾦融開発へ異動。freeeカードUnlimitedや新規 プロダクトの開発に従事。 ● → 現在は同チームのEMを担当。 ⾦融開発 エンジニアリングマネージャー

Slide 3

Slide 3 text

  アジェンダ ● freee finance labについて ● カード事業の取り組み ○ 可⽤性を重視したマイクロサービスの初期導⼊ ○ ⼤きなスクラムから⼩さなスクラムへ ○ DevOpsの実践による開発速度の向上 ○ Enabling SREによって⾃律的な開発組織へ ● 決済事業の取り組み ○ マイクロサービスは成功だったか? ○ モジュラモノリスで⼩さく始めるドメイン分割 ○ 突き詰めながらも、挑戦や遊び⼼を ● さいごに

Slide 4

Slide 4 text

  freee finance lab について

Slide 5

Slide 5 text

  freee finance labについて 事業をもっとラクに、もっと⾃由に、 スモールビジネスを主役にする⾦融インフラ freeeが⽬指す統合型経営プラットフォーム(ERP)と繋がる⾦融‧決済サービスによって、1つ1つの取引や事業 活動が⾃動化‧可視化され、ラクになることを⽬指します。 また、データ活⽤による与信など各種サービスの提供を受けることで、より⾃分らしく⾃由に経営ができる世界を ⽬指します。 そして、⽔やガスのように、意識せずとも当たり前に利⽤でき、⽣活(経営)を⽀える重要な存在、すなわち⾦融 インフラとなることを⽬指します。 freee finance lab は、これらをビジョンに掲げるfreee株式会社の100%出資⼦会社です。

Slide 6

Slide 6 text

  freee finance labについて ⾦融開発部 カード開発A カード開発B 決済開発 freee 株式会社 開発組織 カード事業(biz) ⾦融事業 (biz) ⾦融BPR (ops) freee finance lab 開発組織は freee 株式会社本体に所属しているため、⽂化や 技術資産は共有している。本体との異動‧留学も可能。 事業部やオペレーションは freee finance lab に所属している。 いわゆる社内ベンチャーという形に近く、現在ではカード事業と決済事業を主軸に、 これまでも多くの新規事業の⽴ち上げをアグレッシブに⾏ってきた。

Slide 7

Slide 7 text

  カード事業の取り組み

Slide 8

Slide 8 text

  経営を強くする法⼈カード 「freeeカード Unlimited」を2021年にリリース 独⾃の ロジックで ⾼額与信 素早く freee会計へ 明細を同期 従業員の 利⽤統制

Slide 9

Slide 9 text

  EKS Cluster 可⽤性を重視したマイクロサービスの初期導⼊ オーソリ 請求 与信 カード管理 通知 BFF … Pod … Namespace EKS クラスタ上にGoで書かれたマイクロサービスを複数展開。フロントエンドはReactで、 BFFはfreeeのコード資産を活かすためRailsとなっている。これらをフルスタックに開発。

Slide 10

Slide 10 text

  なぜマイクロサービス?

Slide 11

Slide 11 text

  可⽤性を重視したマイクロサービスの初期導⼊ 従業員⽤カードを 100枚増やしたい ユーザーが店舗で決済 オーソリ (httpsリクエスト) オーソリ以外の⼤量のSQL 新たにカードを 申し込みたい (N⼈) 共有された サーバープロセス 共有された データストレージ モノリスの場合 オーソリに関するSQL オーソリに応答できないと、ユーザーの決済が失敗してしまう。 DBやサーバーなどインフラを共有することでユーザーの決済に影響する。 ⼤量のトラフィック カード追加処理に伴う メモリリーク

Slide 12

Slide 12 text

  可⽤性を重視したマイクロサービスの初期導⼊ 従業員⽤カードを 100枚増やしたい ユーザーが店舗で決済 オーソリ (httpsリクエスト) オーソリ以外の⼤量のSQL 新たにカードを 申し込みたい (N⼈) 共有された サーバープロセス 共有された データストレージ モノリスの場合 オーソリに関するSQL オーソリに応答できないと、ユーザーの決済が失敗してしまう。 DBやサーバーなどインフラを共有することでユーザーの決済に影響する。 ⼤量のトラフィック カード追加処理に伴う メモリリーク マイクロサービスの場合 従業員⽤カードを 100枚増やしたい ユーザーが店舗で決済 オーソリ (httpsリクエスト) 新たにカードを 申し込みたい (N⼈) サーバーやDBを物理的に分離し、共有インフラの影響を回避する

Slide 13

Slide 13 text

  可⽤性を重視したマイクロサービスの初期導⼊ カード情報 ● アクティベート済みか ● ⽉当たりの上限額 ● 取引あたりの上限額 カード情報 ● ステータス(アクティベート含む) ● ⽉当たりの上限額 ● 取引あたりの上限額 ● PIN ● カード番号の下4桁 ● 有効期限など… ● カードのアクティベート有無と上限額だけ知れればよい ● アクティベート以前のステータスは知らなくてよい → カード情報の解釈が異なるため別々にモデリングする オーソリコンテキスト カード管理(申込〜発⾏)コンテキスト 境界づけられたコンテキスト (Bounded Context) 特定のモデルを定義‧適⽤する境界を明⽰的に⽰したもの。代表的な境界の例は、サブシステムやチームなど。 DDD Reference: https://www.domainlanguage.com/ddd/reference/ を和訳 業務ドメインの「関⼼の分離」によって、開発者はすべての業務ドメインを知らなくてもよい。 ⾔い換えると、DDDでは「結合‧再利⽤」よりも「重複」を好むとも⾔われる。

Slide 14

Slide 14 text

  可⽤性を重視したマイクロサービスの初期導⼊ カード情報 ● アクティベート済みか ● ⽉当たりの上限額 ● 取引あたりの上限額 カード情報 ● ステータス(アクティベート含む) ● ⽉当たりの上限額 ● 取引あたりの上限額 ● PIN ● カード番号の下4桁 ● 有効期限など… オーソリサービス カード管理サービス 境界づけられたコンテキスト (Bounded Context) 特定のモデルを定義‧適⽤する境界を明⽰的に⽰したもの。代表的な境界の例は、サブシステムやチームなど。 DDD Reference: https://www.domainlanguage.com/ddd/reference/ を和訳 マイクロサービスは、DDDのエッセンスを物理的設計に反映したものといえる。 関⼼の分離によるモジュール性の獲得で、組織が増えても開発はスケールすると実感した。 「アクティベート」など ドメインイベントを連携 オーソリ処理時に参照するための Read Model として永続化

Slide 15

Slide 15 text

  事業拡⼤とともに開発組織は2倍に…

Slide 16

Slide 16 text

  組織のスケーラビリティはどうだった?

Slide 17

Slide 17 text

  プロダクトオーナー バックログ アイテム1 アイテム2 … … スクラムマスター ユニットA スクラムマスター ユニットB スクラムの営みを⼀部合同で実施 全員でプロダクトの最適化を考える オーソリ 請求 カード管理 与信 全員でモノを考えて作る意味で、組織全体の結束感は⾼まった。しかし、 それ以上にコミュニケーションコストと認知負荷が⾼く、パフォーマンスに限界が⾒えた。 増員当初は LeSS (Large-Scale Scrum) をベースとした⼤規模なスクラムを運⽤ ⼤きなスクラムから⼩さなスクラムへ 担当ドメインは決めず 状況に応じてタスクを 分担し合う

Slide 18

Slide 18 text

  スクラム マスター チームA スクラム マスター チームB 必要な時だけコミュニケーション スクラムイベントなどは個別実施 オーソリ 請求 カード管理 与信 コミュニケーションコストや認知負荷が⼤きく低減された。 幸い、LeSSによってチーム横断の⼀体感の下地ができていたため、サイロ化の恐れも少なかった。 次第に Scrum of Scrum に変更し、それぞれのチームを独⽴に成熟させる流れへ ⼤きなスクラムから⼩さなスクラムへ プロダクトオーナー バックログ プロダクトオーナー バックログ リード エンジニア リード エンジニア 担当ドメインを決め、 そのドメインに対して オーナーシップを持つ

Slide 19

Slide 19 text

  そして、機能開発が並⾏するようになり…

Slide 20

Slide 20 text

  以下の課題がベロシティに悪影響を及ぼした。 ● ブランチ運⽤の煩雑化 ● QAを実施する環境の不⾜ DevOpsの実践による開発速度の向上

Slide 21

Slide 21 text

  以下の課題がベロシティに悪影響を及ぼした。 そのため、⼀時的にEnabling Team 的な遊撃隊を構成し、以下の取り組みを実施。 ● ブランチ運⽤の煩雑化 ○ → Feature Toggleの導⼊ ○ →トランクベース開発の導⼊ ● QAを実施する環境の不⾜ ○ → IaCのリファクタリングを伴う環境増築 DevOpsの実践による開発速度の向上

Slide 22

Slide 22 text

  DevOpsの実践による開発速度の向上: IaCのリファクタリングを伴う環境増築 resource "aws_rds_cluster" "database" { + for_each = local.environments - cluster_identifier = "database" + cluster_identifier = format("database-%s", each.value) engine = "aurora-mysql" ... } コード管理 コード管理 AWSリソースは Terraform によってコード管理。 社内 Terraform Module によって標準化。 kubernetesリソースは Helm によってコード管理。 社内 Helm Package によって標準化。 今まで単⼀の環境だったため、複数環境を考 慮していなかった。 そこで、IaCを全⾯的にリファクタリング。 プロダクト開発者⾃⾝の⼿で、⾃律的かつ迅 速に⾏った。

Slide 23

Slide 23 text

  DevOpsの実践による開発速度の向上: Feature Toggle の導⼊ develop release 機能AのQA (QA環境へデプロイ) master QA完了 タグリリース v1.1.0 feature/A feature/B 致命的な問題が起きたため 機能Bを先に出したい… 機能Aのrevert 機能BのQA merge & revert時の コンフリクトリスク 機能Aを先にリリース予定の場合、機能Bは本番に反映したくないため、featureブランチに退避していた。 ただし、開発が規模化するとコードコンフリクトのリスクが増える。また、リリース順序を組み替える際、 revertが必要になるなどブランチ操作が複雑化。デプロイのリードタイムに影響していた。 これまでのリリースフロー (Git-flowベース) → ステージング環境デプロイ → リグレッションテスト → 本番環境デプロイ 作業ブランチ

Slide 24

Slide 24 text

  DevOpsの実践による開発速度の向上: Feature Toggle の導⼊ func (s *Server) CreateCard(ctx context.Context) error { if featflg.Enabled(featflg.FeatureA) { // ONのときのロジック } else { // OFFのときのロジック } } デプロイとリリースを分離できるようになり、まだ本番で有効化したくない機能でも コード統合が可能になった。 --- feature_A: enabled: true expiration_date: 2023-04-26 team_name: Team B feature_B: enabled: false expiration_date: 2023-03-20 team_name: Team A yamlからフラグの状態を読み取る Feature Toggleとは、コードを変更することなくシステムの振る舞いを切り替える仕組みのこと。 その中でも、まずは 各機能のon/offを管理するための Release Toggle を導⼊。 既にfreeeの多くのプロダクトで導⼊されているが、Goの実績がなかったためライブラリを内製。 AWS AppConfigなども検討したが、まずはyamlでフラグの状態を管理するシンプルな形式でスタート。

Slide 25

Slide 25 text

  DevOpsの実践による開発速度の向上: トランクベース開発の導⼊ main 個⼈の作業ブランチ release 機能A 機能B 1. 個⼈の作業ブランチを切って、mainにマージ。Release Toggle を off にしてコードが発⽕しないように制御しておく。 機能Aの回帰テスト 機能B タグリリース v1.1.0 リリース順序の変更時にブランチ操作は不要になり、フラグの状態を変更するだけでよくなった。 頻繁にコード統合されることで、main が常に最新の状態を保てるようになった。 QAに必要なfeatureもコード統合された状態で main に存在するため、QA⽤のブランチは不要になった。 QA環境Xへデプロイ { A: on, B: off } とする 機能A ステージングデプロイ { A: on, B: off } 本番デプロイ { A: on, B: off } 機能Bの回帰テスト ステージングデプロイ { A: on, B: on } QA環境Yへデプロイ { A: on, B: on } とする 2. リリース前のコードスナップショットを release ブランチに退避し、短いスパンでマージする。

Slide 26

Slide 26 text

  Enabling SRE によって⾃律的な開発組織へ Platform SRE Enabling SRE DBRE SRE組織 プロダクト開発チーム プロダクトA プロダクト開発者 プロダクトB プロダクト開発者 プロダクトC プロダクト開発者 Product SRE プロダクト開発者の中でSREの実践を率先できるメンバー(プロダクトSRE)を育成する。 freee finance lab では、各チームにプロダクトSREを1名ずつ任命。 クラスタのアップグレードなどの作業を委譲、特権ロールを付与し作業可能な範囲の拡⼤など。 プロダクトを載せる基盤 や仕組みを提供 DB運⽤のための仕組みや 知⾒を提供 プロダクト開発者にSREの知⾒ を提供‧サポートする プロダクト開発者の中で SREの実践に責任を持つ

Slide 27

Slide 27 text

  Enabling SRE によって⾃律的な開発組織へ Platform SRE Enabling SRE DBRE SRE組織 プロダクト開発チーム プロダクトA プロダクト開発者 プロダクトB プロダクト開発者 プロダクトC プロダクト開発者 Product SRE ● プロダクト開発の⽬線を知れる ● SREの知⾒を提供できる 社内留学 ● SREの知⾒を学べる ● プロダクト開発の⽬線を提供できる 社内留学 SREとプロダクト開発者同⼠で相互留学をすることで、知⾒や⽂化を共有するムーブメント。 特に SRE→プロダクトの留学は Embedding SRE とも呼ばれる。 freee finance lab では早速受け⼊れを開始。

Slide 28

Slide 28 text

  決済事業の取り組み

Slide 29

Slide 29 text

  ラクで正確、安⼼、安価な 法⼈向け銀⾏振込サービスを提供予定 freee内で スムーズに ⽀払いが完結 安価な 振込⼿数料 独⾃技術で 誤り‧改ざん を抑制 2023年内にfreee会計からの銀行振込機能を提供予定 国内の 銀行への振込をカバー | プレスリリース

Slide 30

Slide 30 text

  カードの経験を活かすべく振り返り会へ…

Slide 31

Slide 31 text

  マイクロサービスは成功だったか? 成功だったポイント ● 可用性・耐障害性 ○ オーソリを物理的に分離かつ疎結合にしたため、他サービス依存の決済障害はほぼ起こらなかった。 ● モジュール性・開発のスケーラビリティ ○ 業務ドメインによる関心の分離によって、開発が並行・規模化しても独立して開発可能。 ○ 新メンバーが増えたが、1つの業務ドメインおよびマイクロサービスから独立して学べた。 ● 幸い分散トランザクションが不要だった ○ 一般的には、マイクロサービスで最も大きな課題になる。 ○ 粒度は「集約(=整合性の単位)より大きく、コンテキスト境界より小さく」が良いとされる。 ■ 集約より小さく作ってしまうと、複数のMS間で1つの整合性を維持することが必要に…。 ■ コンテキスト境界より大きく作ってしまうと、1つのMS内でモデルの定義がブレる。 ○ ドメイン分析をしっかりしていたため、MSの粒度設計を間違えなかった。 ○ また、ドメイン間でトランザクションのライフサイクルも異なっていたのも大きい。 ○ (リアルタイムなオーソリ、毎月決まった日付に処理する請求、ユーザー申込時の与信など) ● 一般的に、他にはデプロイ容易性・弾力性・進化性といったメリットもある。 しかし、どんなアーキテクチャにもトレードオフがある

Slide 32

Slide 32 text

  マイクロサービスは成功だったか? 失敗だったポイント ● 複雑性(マイクロサービス間の連携) ○ SQS + SNS のFanout PatternでProducerがConsumerを意識しない形にしたが、逆に無意識に多くの依存 が生まれていた。依存関係の把握が難しい。 ○ SNSへのメッセージ配送とSQLを同一txnで扱うため、Outbox Patternを導入 ○ メッセージの重複処理を排除するため、Inbox Patternを導入 ● 動作確認が難しい(テスト容易性) ○ 基本的に1つのマイクロサービス内で完結するが、ユースケースによっては複数起動が必要 ● インフラの管理コスト・料金コスト ○ 環境 ✕ マイクロサービス分だけインフラが必要 ○ IaCコードの書き方で工夫しているが、それでもメンテコストがかかる ● 可観測性 ○ 社内の分散トレーシングは進みつつあるが、サービス間のやりとりを追いかけるのは少し難しい 可⽤性が必要だったオーソリ以外は物理的分離である必要はなく、 論理的分離でモジュール性‧スケーラビリティを獲得することはできなかったか?

Slide 33

Slide 33 text

  デプロイ単位 モジュラモノリスで⼩さく始めるドメイン分割 照合 モジュール 申込‧審査 モジュール ワークフロー モジュール 振込 モジュール ✕ 名前空間やパッケージで表現するため 再設計が比較的容易 ◯ あるべき依存関係を定義し、相互参 照・循環参照を禁止する メソッド呼び出し 法人間の振込業務では、即日の振込はあれどカードのオーソリほどのリアルタイム性は求められない。 これを踏まえて、モジュラモノリスを採用してみることにした。 モジュラモノリスでは、論理的分離でマイクロサービス同等のモジュール性の獲得を目指す。 こうしたアプリケーションレイヤーの設計は軌道修正が比較的容易で、ドメイン分析に不安があっても後戻り しやすい。逆にいうと、設計の強制力が弱いため、依存関係の違反をlintで禁止する。

Slide 34

Slide 34 text

  モジュラモノリスで⼩さく始めるドメイン分割 他モジュールを参照できるレイヤーの制限 データに対する排他的所有権 domain domain module A ◯ ✕ ✕ ✕ 一番外側のレイヤー同士のみ依存できるようにする。例えば domain層同士が依存するとドメイン分割が無意味になる。 module B 申込 ワークフロー 申請 取引 ⽀払先 法⼈情報 代表者 審査 DBは単一なので、モジュール間でデータモデルを介して 密結合になる可能性がある。排他的な所有権を定める。 Shopifyの事例 (*) を参考に、「まずは取り入れてみて考えよう」という気持ちで進めている。 (*) Shopify Engineering「Deconstructing the Monolith: Designing Software that Maximizes Developer Productivity」

Slide 35

Slide 35 text

  突き詰めながらも、挑戦や遊び⼼を 「プロダクトの特性・組織の事情を抑えながら、価値ある技術的チャレンジをする」 ● フロントエンドにおける vite の採用 ○ 最近では Next.js や Astro のように多様なレンダリング方式・最適化・開発体験を提供するFWが登場 ○ 一方、ログイン前提の機能がほとんどで「静的な海」は少ないため、CSRが落とし所になる ○ そこで、開発者体験に焦点を置き、 vite を採用するに至った。 ● playwright codegen の採用検討 ○ 開発者自身が e2e をメンテナンスしやすいように selenium による e2e 基盤からの移行を検討 ● sqlc の技術検証  ○ SQLから構造体やデータアクセスロジックなどのボイラープレートコードの自動生成が可能 ● など… 新規プロダクトだからこそ積極的に取り組んでいく

Slide 36

Slide 36 text

  さいごに そんなフルスタック‧フルサイクルな開発組織で、 スモールビジネスを主役にする「⾦融インフラ」を実現したい 仲間を募集しています。 カード事業エンジニア 決済事業エンジニア

Slide 37

Slide 37 text

No content