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

密結合なバックエンドから TypeScript のコードを生成する

密結合なバックエンドから TypeScript のコードを生成する

Avatar for kemuridama

kemuridama

May 22, 2026

More Decks by kemuridama

Other Decks in Programming

Transcript

  1. 2 メイン - 2018 年新卒で freee 入社 - freee会計の開発 -

    主にフロントエンド基盤 その他 - Dev Branding / Dev Relationship - freee Tech Night - freee 技術の日 - 全社イベント運営 - TSKaigi コアスタッフ SNS - X: @_kemuridama - GitHub: @kemuridama フリー株式会社 / エンジニア & DevRel kemuridama Ryo Ochiai
  2.   電⼦稟議 経費精算 債権債務 管理 ⼈事労務 電⼦契約 固定資産 請求管理 会計

    ⼯数管理 販売管理 会計‧⼈事労務‧販売管理を核とした 統合型経営プラットフォーム
  3. 5 スモールビジネスの ⼈事管理市場において  売上⾦額シェアNo.1(3) スモールビジネス向けに統合型クラウド(1)ERPを提供 注: 1. クラウドサービス:ソフトウェアやハードウェアを所有することなく、ユーザーがインターネットを経由してITシステムにアクセスを行えるサービス 2. リードプラス「キーワードからひも解く業界分析シリーズ:クラウド会計ソフト編」(2022年8月)

    3. 「freee人事労務」はITRが今年調査発行した「ITR MARKET VIEW:人事・給与・就業管理市場2022」の人事管理市場において、従業員100人未満および従業員100~300人未満の企業で売上金額シェアNo.1(2020年度)を獲得しています。 統合型クラウド会計ソフト 統合型クラウド⼈事労務ソフト その他サービス 2013年3⽉〜 請求書 経費精算 決算書 予実管理 ワークフロー 内部統制 勤怠管理 ⼊退社管理 給与計算 年末調整 マイナンバー 管理 2014年10⽉〜 2022年11⽉〜 ⽇本のクラウド 会計ソフト市場  シェアNo.1(2) 統合型クラウド販売管理ソフト 【国内初】 クラウド会計ソフトと ⼀体型で使える 販売管理サービス ⽀出管理 ⼈事労務 ⼯数管理‧労務費管理 社宅制度の導⼊ 申告書作成 ⾒積‧発注‧請求 法⼈⼿続き クレジットカード 開業⼿続き 電⼦契約
  4. 6 スモールビジネスの ⼈事管理市場において  売上⾦額シェアNo.1(3) スモールビジネス向けに統合型クラウド(1)ERPを提供 注: 1. クラウドサービス:ソフトウェアやハードウェアを所有することなく、ユーザーがインターネットを経由してITシステムにアクセスを行えるサービス 2. リードプラス「キーワードからひも解く業界分析シリーズ:クラウド会計ソフト編」(2022年8月)

    3. 「freee人事労務」はITRが今年調査発行した「ITR MARKET VIEW:人事・給与・就業管理市場2022」の人事管理市場において、従業員100人未満および従業員100~300人未満の企業で売上金額シェアNo.1(2020年度)を獲得しています。 統合型クラウド会計ソフト 統合型クラウド⼈事労務ソフト その他サービス 2013年3⽉〜 請求書 経費精算 決算書 予実管理 ワークフロー 内部統制 勤怠管理 ⼊退社管理 給与計算 年末調整 マイナンバー 管理 2014年10⽉〜 2022年11⽉〜 ⽇本のクラウド 会計ソフト市場  シェアNo.1(2) 統合型クラウド販売管理ソフト 【国内初】 クラウド会計ソフトと ⼀体型で使える 販売管理サービス ⽀出管理 ⼈事労務 ⼯数管理‧労務費管理 社宅制度の導⼊ 申告書作成 ⾒積‧発注‧請求 法⼈⼿続き クレジットカード 開業⼿続き 電⼦契約
  5. 7 - 2013 年 3 月リリース - 2012 年度の確定申告の直後にリリース -

    すでにリリースから 13 年が経過 - 巨大なモノリス - freee 社内でも最も大きなコードベース - バックエンド: Ruby + Ruby on Rails - フロントエンド: TypeScript + React - 一部 erb + Backbone.js freee会計
  6. 9 • バックエンドとフロントエンドで言語が異なる ◦ 基本的にはバックエンドの変更にフロントエンドが引っ張られる 状態 ◦ Ruby (Sorbet) と

    TypeScript の型をそれぞれ管理する必要がある • 一般的な解決方法: OpenAPI Schema からのコード生成 ◦ 取り組んでいるが、コードベースが大きすぎてなかなか進まない のが現状 ◦ API 経由だけではなく erb に直接値を埋め込んでいる箇所が存在する freee会計における課題
  7. 10 • バックエンドとフロントエンドで言語が異なる ◦ 基本的にはバックエンドの変更にフロントエンドが引っ張られる 状態 ◦ Ruby (Sorbet) と

    TypeScript の型をそれぞれ管理する必要がある • 一般的な解決方法: OpenAPI Schema からのコード生成 ◦ 取り組んでいるが、コードベースが大きすぎてなかなか進まない のが現状 ◦ API 経由だけではなく erb に直接値を埋め込んでいる箇所が存在する freee会計における課題 Ruby (バックエンド) の実装を SSoT (Single Source of Truth) として TypeScript (フロントエンド) のコードを生成するのはどうだろう
  8. 13 • バックエンド解析 ◦ Prism ▪ Ruby の新しい標準パーサー ▪ Web

    Assembly が提供されていて Node.js から利用可能 ▪ https://www.npmjs.com/package/@ruby/prism • フロントエンドのコード生成 ◦ TypeScript Compiler API ▪ 依存を増やしたくなかったので ts-morph や Alloy の採用は見送った 実現方法
  9. 14 • Prism を使って Ruby のコードから AST (抽象構文木) を抽出 •

    Ruby AST から TypeScript Compiler API で TypeScript のコード生成 ◦ 型・定数・それらに関連する utility method を生成 • この仕組みを使って約 1,000 ファイルのコードが作成されている 実現方法 module FlagHelper def flags { flag_1: hogehoge_method, flag_2: hogehoge_method, flag_3: hogehoge_method } end end type Flags = { flag_1: boolean, flag_2: boolean, flag_3: boolean } const defaultFlags: Flags = { flag_1: false, flag_2: false, flag_3: false }
  10. 15 • 複雑な型の生成 ◦ Ruby は型がない ◦ インターフェースを整理して型を自明にすることでマッピングを楽にしている ▪ 基本的にすべてのフィールドが

    1 つの primitive 型になるように ◦ 変換ロジックが肥大化して今後のメンテナンスが困難になることを避けた やらなかったこと
  11. 18 • バックエンドの実装を SSoT としてフロントエンドのコードを生成した • バックエンドとフロントエンドの両方の型をメンテナンスする必要がなくなった ◦ ある程度の変更漏れを TypeScript

    の型エラーで検出可能 ◦ 変更漏れが起因となっていたバグを減らすことができた • Prism/TypeScript Compiler API を使って Ruby AST を TypeScript AST に変換した ◦ 飛び道具感はあるが言語の壁を超えて現時点での依存の最適化ができた まとめ