Mirrativ Tech Blog

株式会社ミラティブの開発者(バックエンド,iOS,Android,Unity,機械学習,インフラ, etc.)によるブログです

ミラティブのバックエンド基盤チームのご紹介 〜開発者体験の向上とコスト最適化の取り組み〜

こんにちは、バックエンドのテックリード兼バックエンド基盤チームマネージャーの夏(なつ)です。

採用面接などの場で「バックエンド基盤チームって具体的に何をしているの?」と聞かれることがよくありました。これまでもバックエンド基盤チームのメンバーが取り組んできた内容は、個別のテックブログとして紹介してきました。

一方で、これらの記事だけでは、

  • そもそも何のために存在しているチームなのか
  • 具体的にどういうことをしてきたのか

といった点については、まとまった形では説明できていませんでした。そこでこの記事では、バックエンド基盤チームの役割・意義・実際の業務内容を改めて整理して紹介します。

バックエンド基盤チームの意義

ミラティブのバックエンド基盤チームを一言で表すと、 「バックエンド領域の開発者体験(DX)とコスト最適化を軸に、エンジニア主導で課題を発見・解決していくチーム」 です。

ミラティブのバックエンドエンジニアの大半はプロダクトチームに所属しており、そこではエンドユーザーに直接価値を届ける機能開発が最優先となります。そのため、以下のような改善テーマは、プロダクトマネージャーの視点からはどうしても優先度が下がりがちです。

  • 中長期的には重要だが、短期的な事業KPIには貢献しにくい
  • 効果測定が難しく、優先順位をつけづらい
  • 技術的難易度が高く、完了の見通しが立ちにくい
  • エンジニア以外からは課題感が把握しづらい

しかし、システムの安定性・開発速度・保守性は、プロダクトが成長するほど重要性を増していきます。こうしたテーマに長期的な視点で取り組むため、プロダクト開発からリソースを切り離した専任チームとして、バックエンド基盤チームが組成されました。組織規模が小さかった頃はテックリードやマネージャーが個人で進めていた領域も、組織拡大に伴い、チームとして体系的にアプローチする必要が出てきたためです。

具体的な取り組みは後述しますが、大きく分けると以下の領域を担当しています。

システムの安定性や開発者体験の向上

  • PerlからGoへの移行支援
  • CI/CDの整備
  • 開発環境の整備
  • ソフトウェアアーキテクチャの整備
  • 静的解析・テスト基盤の整備
  • 依存ライブラリや言語本体の継続的なアップデート
  • 生成AIの活用基盤の整備
  • 技術的負債の解消

インフラコスト削減の主導

  • データベース容量の削減
  • 実負荷に基づいたリソースプランニング
  • パフォーマンスチューニング

なお、プロダクト開発の過程で生まれる細かい負債については、バックエンドエンジニア全体(15〜16名)のタスクとして管理・消化しています。バックエンド基盤チーム(2〜3名)は、プロダクト開発の合間では進められないような、半年〜1年以上かけて取り組む必要があるタスクを集中的に担当しています。

インフラ・SRE・Platform Engineeringチームとの違い

一般的に「開発者体験の向上」や「生産性向上」という文脈では、SREやPlatform Engineeringと呼ばれるチームがその役割を担うことが一般的です。ミラティブの現状の組織体制では、そのような名称のチームは存在せず、「インフラチーム」と、バックエンドチームから派生した我々「バックエンド基盤チーム」が連携してその役割を担っています。

各チームの主な担当領域は以下の通りです。縦割りにしたいわけではなく、むしろ積極的に越境することを推奨していますが、基本的な立ち位置を明確にした方が動きやすいという考えです。

チーム 主な担当領域
バックエンドチーム(プロダクト) アプリケーションコード内のビジネスロジック
バックエンド基盤チーム アプリケーションコード内のインフラレイヤー
ソフトウェアアーキテクチャ
アプリケーションコンテナやそのCI/CD
インフラチーム サイドカーコンテナやコンテナ管理全般
ミドルウェア・OS・クラウド・監視など

現時点では、プロダクトが多数並行して立ち上がるフェーズではないため、Platform Engineeringのような共通基盤専任チームは置いていません。また、SRE的な信頼性担保(オンコールやポストモーテム等)は役割を固定せず、各チームがそれぞれの領域で対応しています。

透明性の確保とチーム運営

エンジニア主導のチームである以上、ROI(投資対効果)が見えにくい「自己満足な重厚長大プロジェクト」に陥るリスクとは常に隣り合わせです。会社のトップラインに対して短期での貢献が難しく、組織状況によっては「何をしているか分からない」と思われがちなポジションでもあります。だからこそ、チームの存在意義(レゾンデートル1)は自分たちで証明し続ける必要があると個人的には考えています2

具体的には以下のような取り組みで透明性を確保しています。

  • 定期的なアンケートの実施と公開
    • バックエンドエンジニア向けのアンケートを実施し、課題・提案・要望には原則すべて回答した上で集計内容を公開しています。
    • 人員に限りがあるため全ての要望には応えられませんが、優先順位の温度感や期待値を調整する場としても意識しています。
  • 月報でのマイルストーン共有
    • メインプロジェクトの進捗と「いつ頃チームにとって成果が出るか」を共有しています。
    • 期限を自分たちで決められるからこそ、過剰な投資をせず、適切なスコープを保つ自浄作用を意識しています。

アンケートでは以下のような項目を聞いています。

  • 普段の開発体験を阻害する要因(気になっている順に3つ選択)
    • それぞれに対する補足や改善アイデア(自由記述)
  • ここ半年の基盤チームの施策のうち印象に残っている改善(複数選択)
  • 基盤チームが現在何を取り組んでいるかは分かりやすいか(5段階評価)
  • 基盤チームは開発者体験にどの程度影響を与えていると思うか(5段階評価)
  • その他、基盤チームへの期待や改善要望

アンケート案内

アンケートの集計結果は以下のような形で全体公開しています。

アンケート集計結果

一方で、Four Keysなどのチームパフォーマンスに関する定量評価については、現時点では優先順位の都合上、意図的に実施していません。指標自体は有用ですが、改善につなげるためには背景にある課題整理と解決策の検討プロセスが不可欠なため、アンケートや日々のフィードバックを通じて課題を把握し、具体的な改善を積み重ねることを重視しています。また、「ある指標が目標になった瞬間に、その指標は良い指標ではなくなる」というグッドハートの法則が示すとおり、特に生成AIの登場以降は、作業量やアウトプット量に基づく指標がハックされやすい状況にあると考えています。将来的に必要性が高まれば、開発組織の健康状態を把握する参考情報として導入を検討します。

実際の業務

業務は大きくメインプロジェクト、サブタスク、定常業務に分かれます。

メインプロジェクト

メンバー1人につき1つアサインし、3か月〜1年以上かかるタスクに取り組みます。

サブタスク

メインプロジェクトの合間に取り組むタスクです。小規模な改善要望、不具合修正、負債解消のほか、将来の改善の種になりそうな技術検証なども含まれます。

定常業務

他チームからの問い合わせ対応や、以下の業務を日替わりの当番制で対応しています。

  • RenovateによるGo ModulesやGo本体の更新
  • 管理している外部サービスの更新・障害情報の確認
  • 管理対象の warn/errorログ監視
  • Flaky testの調査・対応

メインプロジェクトの実績

ここからは、これまで取り組んできた主要なプロジェクトを紹介します。

Perl製レガシーシステムからGoへの漸次的移行支援

Mirrativは2025年8月28日で10周年を迎えました。DeNA内の別の配信サービスを土台に高速にリリースして仮説検証を行うためにPerlを採用して開始しましたが、会社分割後はGoによる新規開発体制を整え、新規APIや非同期処理はGoで実装されるようになりました。しかし、サービスのコア機能には依然として巨大なPerlの同期処理として残っている箇所があります。このような巨大で複雑な処理を一度にGoへ移行しようとすると、開発を長期間止める必要があること、広範なリグレッションテストが必要になること、リリース後に予期せぬ不具合が大量に発生することがリスクとして懸念されました。そこで、私たちは 「PerlからGo関数を“関数呼び出し感覚”で実行できる基盤」 を整備しました。具体的には、開発者がプロセス間通信やシリアライズを意識することなく、以下のようにPerlのメソッド呼び出しと同じ感覚で記述できるインターフェースを提供しています。

# PerlコードからGoの関数(ToCamel)を呼び出すイメージ
my $res = $c->call_go('ToCamel', +{ text => 'hello world' });

仕組みの詳細はPerlからGoへのシステム移行のアシスト 〜Perl XSとUnix Domain Socketを活用〜をご覧ください。

当初はGoアプリケーションを共有ライブラリ(*.so)としてPerlからロードする仕組みを試みましたが、fork後のPerlプロセスからGo関数を呼び出す際、goroutineが正常に動作せずハングアップする事象が稀に発生しました。Goランタイムの制約上プログラム側では回避が困難だったため、共有ライブラリ方式を廃止し、同一コンテナ内でGoとPerlを別プロセスとして起動し、通信に関しては引き続きUnix Domain Socketで行うよう修正しました。

安定化に向け、まずはバックエンド基盤チーム自身でドッグフーディングを実施しました。管理画面や影響範囲が限定的な処理での導入から始め、その後、採番機能のような多種多様な機能の内部から高頻度で呼ばれる処理を対象に、1%→10%→50%→100%と段階的にトラフィックを移行し、安定性を検証・改善し続けました。安定運用を確認した後、バックエンド全体へ展開・普及活動を行い、現在ではPerlでの新規ロジック実装を原則禁止とするルールを制定するに至りました。Perlコードに変更があった場合はバックエンド基盤チームへSlack通知が飛ぶ仕組みを導入していますが、これは監視・管理のためではなく、「プロダクト開発においてGo移行の障壁となっている箇所」を把握し、基盤側でサポートするためです。

デプロイ所要時間を半減

デプロイ速度の高速化も実現しました。以前はデプロイごとにVMインスタンスの入れ替えを行っていましたが、インフラチームと共同でコンテナのみの入れ替えで済む構成に変更しました。結果、本番環境への反映が1時間→30分に、開発環境への反映が30分→15分に短縮されました。詳細はEnvoyでVM内のトラフィックをコントロールしてデプロイを高速化したをご覧ください。

この改善により、アンケートで上位に挙がっていた「デプロイ速度」に対する不満の声が明確に減少しました3。また、反映完了時のSlack通知も導入し、好評を得たため、本番環境を含め、デプロイ進捗に関する通知を今後も改善していく予定です。

その他、マスターデータ管理システムの運用やArtifact Registryへの移行なども担当しました。

Mac上でのアプリケーション動作確認方法の改善

デプロイ高速化と並行して、ローカル環境(Mac)での動作確認フローも改善しました。デプロイ高速化は今後も続けていく予定ですが、どんなに最適化したとしても数秒〜数十秒でデプロイを完了させるのは現実的ではありません。検証中の不具合調査などで開発環境のデータが必要になる際、デプロイを待たずに手元で調査できるよう、ローカル環境から開発環境のデータへ安全にアクセスできる仕組みを構築しました。これにより、手元でシードデータを生成する手間なく、実際のデータを用いた動作確認が可能になりました。詳細はIAPを利用した開発体験向上の記事をご覧ください。現在はPerlシステム側も対応し、実機やシミュレータ上の開発版アプリからもアクセス可能です。

Goコード自動生成(go generate)の最適化

Mirrativのバックエンドでは、StringerEnumergomockなどの外部ツールに加え、データベースのDDL/DMLからのコード生成やTable Driven Test用のユーティリティコード生成などの独自のコード生成ツールも多用しています。コード規模の拡大に伴い生成時間が増加していたため、以下の3点で最適化を行いました。

1. 全削除による高負荷の解消

  • 課題: 毎回最初に自動生成コードを全削除してから再生成しており、エディタによっては負荷がかかりやすい状態でした。
  • 解決策: 各生成システムごとに生成されたファイルを記録しておき、生成されなくなったファイルのみ削除するよう修正しました。

2. AST解析コストの削減

  • 課題: 各生成システムごとに毎回 packages.Load でAST解析を行っており、これが実行時間に対して支配的でした。
  • 解決策: 前回解析した結果をファイルにキャッシュし、以下の2つの観点で解析結果を再利用できるよう修正しました。
    • 前回実行時の再利用: 前回実行時からファイルに変更がないパッケージは解析をスキップしてキャッシュを利用する
    • 生成システム間の共有: 一度解析した結果は、他の生成システムでも共有して利用する

3. 不必要な再生成のスキップ

  • 課題: 変更内容と関係ないコードも含め、毎回すべてを再生成していました。
  • 解決策: 各生成システムにキャッシュを導入し、「前回とキャッシュの値が変わらない」かつ「生成ファイルがすべて揃っている」場合は再実行しないよう修正しました。
    • キャッシュのキーは基本的には参照ファイル名と最終更新日時ですが、gomockの場合はinterfaceの構造を利用するなど、ケースバイケースで対応しています。

また、各生成システムには依存関係(有向非巡回グラフ)があり、それらを考慮しながら並列実行するためにコード自動生成の仕組みを抜本的に改修しました。これにより元々常に1分くらいかかっていた実行が、キャッシュが最大限効いた場合は2秒程度で終わるようになり、気軽に実行できるようになりました。

CIコストの最適化

CI環境は、Jenkins → CircleCIと変遷し、現在はCloud Buildで運用しています。CircleCIからCloud Buildへの移行はインフラチームが主導し、Perlのテスト移行などをバックエンド基盤チームが引き継ぎました(背景はこちらの資料CI/CD Conference 2023の講演を参照)。その後も、マスターデータを別リポジトリに切り出してgit clone時間を短縮する(Cloud Buildがsparse checkout未対応のため)、自動生成コードをGit管理に含めることでCIでの生成時間を削減するなど、地道な改善を積み重ね、直近では月数十万円規模のコスト削減を達成しました。

データベースコストの最適化

負荷が低いMySQLのリードレプリカを削減し、参照系クエリもソース(Primary)に向けることでコストを削減しました。バックエンド側の変更はYAML設定のみで完結し、今後負荷が上昇した場合は再度リードレプリカに向けられる設計にしています。開発環境ではあえてリードレプリカに向け、1秒の遅延を付与することで、レプリケーション遅延を考慮した実装を強制的に意識づける工夫もしています。

また、データベース容量の削減にも取り組んでいます。古くから存在してきたテーブルの場合、実装当初の想定以上のペースでレコード数が増えているケースがあり、定期的にディスク容量の拡張を検討・実施する必要が生じています。しかし、ディスク容量を際限なく拡張し続けることは、インフラコストの増大につながるだけでなく、MHA(MySQL High Availability)作業や拡張に伴う作業コストといった運用上の負荷も無視できません。特にQPSが高い系統については、MHA実施時にメンテナンスが必要となり、サービス影響を伴う全社的な対応が発生します。また、障害時やスケールアウト時にリードレプリカをバックアップからリストアする必要が生じた場合、フルリストアおよびレプリケーションの追従に時間を要するため、データ容量が大きいほどサービスインまでに要する時間も増加します。

そこで、バックエンド基盤チーム側で1年以内にディスク使用率が70%を超える可能性があるデータベース系統を洗い出し、テーブルごとの容量増加の傾向を調査しました。バックエンドマネージャー陣と協議の上、対応方針と優先順位を決定し、現在は各チームで分担して対応を進めています。

おわりに

組織規模が小さかった頃はCTOやマネージャーが個人で進めていた「重要だが重たいタスク」。組織が拡大した今、私たちバックエンド基盤チームは、組織再編や短期的な事業優先度に流されることなく、腰を据えて技術的負債や開発効率と向き合っています。

Mirrativはサービス開始から10周年を迎えました。長年運用されてきたシステムには様々な技術的負債が蓄積されますが、それを計画的に解消しながらサービスを成長させていくのが私たちの役割です。

Mirrativの次の10年を支えるため、技術的な挑戦を続けたい方、開発者体験の向上に情熱を持つ方、ぜひ採用ページもご覧ください。

www.mirrativ.co.jp

mirrativ.notion.site

speakerdeck.com


  1. 一度使ってみたかった
  2. 上長から圧を感じたことは一度もないですが、ないからこそ…
  3. その分、別の課題の割合が増えましたが😅