こんにちは、OTTサービス技術部開発第一グループの麻田です。
今回は、案件で実施した型リポジトリの導入および運用効率化の取り組みについてご紹介します。
導入背景と課題
私たちのチームでは、OTTサービス向けのWebおよびHTML5 TV(テレビ向けWebアプリ)のフロントエンドと、BFF(Backend for Frontend)の開発を担当しています。
直近でプロダクトをTypeScriptへ移行しましたが、ツールを使って一括変換したこともあり、型定義が十分に整備されておらず型安全性が担保できない状態が続いていました。
また、Web/TVフロントエンド、BFFそれぞれでAPIレスポンスの型を独自に定義していたため、以下のような課題が顕在化していました。
- 型の重複定義による保守性・拡張性の低下
- API変更時の追従漏れのリスク
- サービス間での整合性の確保が困難
これらを解決するため、共通のAPIレスポンス型を集約する「データ型専用リポジトリ」を新たに作成しました。
これにより、
- Web/TV/BFF間での型の重複排除
- 型の変更が一元管理できる
- 各アプリケーションが同一の型定義に基づいて開発できる
といったメリットが得られました。
なお、本プロジェクトではtRPCのように自動で型を生成・適用しているわけではなく、BFFが返すレスポンスの型をWeb/TVアプリケーション側で手動でimport・適用する運用を採っています。
そのため、型リポジトリの整備によって、アプリケーション間で「同じ型を正しく使う」ことを仕組みとして担保する狙いがありました。
開発時の運用
型リポジトリはnpmパッケージとして管理されています。本番環境ではnpmレジストリ経由で取得しますが、開発中はローカルパスを指定して参照できるようにしています。
// "@sample/types": "^0.0.15" // ローカルの型リポジトリがあるパスに変更 "@sample/types": "file:../sample-types/lib"
当プロジェクトではビルド結果をlibに出力しその内容をnpmレジストリにパブリッシュしているので、ローカルでもlibを参照しています。
型定義が終わったらビルドをして、利用しているリポジトリで yarn install
することでローカルで作成中のデータ型を利用することができます。
これによって、
- 型リポジトリのレビューが通る前でも各アプリケーションの開発が進められる
- 機能ブランチ上でPRの差し替えに強く、開発の停滞が発生しにくい
- 「型定義のPRだけ先に出す」というフローが可能になり、段階的な開発・レビューがしやすい
といったメリットがあります。
GitHub Actions による CI/CD パイプライン構築
運用し始めた当初、データ型を定義してPR→承認→ローカルでビルド→npmにパブリッシュするというフローを手動で行っていました。しかし、毎回行う作業については自動化しておきたいです。ということでGitHub Actionsでこれらの一連のフローを自動化しました。
以下がそのWorkflowです。
name: Publish type definitions to custom registry on: push: branches: - main permissions: contents: write packages: write jobs: publish: runs-on: self-hosted steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22 registry-url: ${{ secrets.NPM_REGISTRY }} always-auth: true - name: Install dependencies run: yarn install # バージョンアップコミット出す - name: Bump version (patch) run: | yarn version --patch git push origin main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ビルド - name: Build package run: yarn run build # npmリポジトリにpush - name: Publish to custom registry run: | cd lib npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
自動化の流れ
- mainブランチへのマージをトリガーに実行
- バージョンのpatchアップ → 自動コミット&タグ付け
- パッケージビルド
- lib ディレクトリへ移動して npmにレジストリにパブリッシュ
yarn version --patch
は便利なコマンドで、コミットとタグ付けを一括で行ってくれます。
メジャー・マイナーを指定したい場合は --major
や --minor
を利用することで変更が可能です。
公式ドキュメント classic.yarnpkg.com
補足ですが、GitHub Enterpriseを利用しているため、runs-on: self-hosted
を指定しています。
現状の課題と今後の展望
現在の型リポジトリの運用では、複数のブランチを同時に mainブランチにマージしようとした際に競合が発生し、自動パブリッシュが失敗するケースがあります*1。このような競合を避けるために、GitHub Actions による Workflow の同時実行をconcurrencyなどで制御する予定です。
また、型定義の変更がレビュー対象となったことで、開発に必要なPR数が増え、レビュー工程がスケジュールを圧迫することもあります。レビューの質を保ちながら効率を上げるために、通知の自動化やCIチェックによるレビュー支援など、運用の最適化にも取り組む必要があると考えています。
今後の展望としては、現在型のみを対象としているリポジトリに加えて共通のユーティリティ関数やロジックも別リポジトリに切り出すことでよりDRYな構成を目指す予定です。あわせて、パッケージのバージョン管理についても、メジャー・マイナー・パッチといった変更規模に応じた戦略をチームで統一し、変更の意図が伝わりやすい運用にしていきたいと考えています。
まとめ
今回は、型リポジトリの構築とその運用効率化に向けた取り組みをご紹介しました。 地味な取り組みに見えますが、複数アプリ間で型を共有する環境では非常に重要な基盤整備です。
まだまだ改善の余地はありますが、チームの開発体験を高めるために、今後も継続的にブラッシュアップしていきたいです。
*1:先にマージされたブランチでは、main へのマージ後に他のブランチが最新の main を取り込んでいない場合、コミットの競合が発生し、自動でのバージョン更新やパブリッシュに失敗。後にマージされたブランチでは、すでに main に存在する新しいバージョン番号と同一のバージョン番号でコミットを行おうとして失敗(バージョン番号の重複によるエラー)。