OpenAPIを使ったTVer APIのスキーマ駆動開発

こんにちは。 id:takanamito です。
以前書いた記事「TVerバックエンドAPIのリアーキテクチャ」では、TVerAPIアーキテクチャを移行した背景と全体設計について紹介しました。
本記事では、アーキテクチャから1段ブレークダウンして、OpenAPIによるスキーマ駆動開発の実践について現場レベルの具体的な運用の話を書きます。

TVerにはcontents-api, user-api, manager-apiという3種のAPIが存在します。それぞれの詳細は前回の記事でご確認ください。
この記事ではcontents-apiを例に紹介を進めます。

  • OpenAPIを使った開発フロー
  • なぜOpenAPIなのか
  • OpenAPIスキーマ定義
    • ディレクトリ構造とスキーマファイル分割戦略
    • 細かいスキーマ設計のローカルルール
      • HTTPレスポンスのrootには必ずキーを持たせる
      • oneOf, anyOfを使わない
  • OpenAPIからのコード生成手法
    • redoclyを使ってymlファイル結合
    • Spectralを使ったLint
    • oapi-codegenを使ったGoのコード生成
    • 生成フローの自動化
  • モックサーバーの活用
  • 出てきた課題
    • モックサーバーのレスポンスの表現力不足
  • まとめと今後の展望
続きを読む

Google Cloud Next Tokyo '25 に登壇しました

はじめに

TVer 広告プロダクト本部の髙品です。8月5日と6日に東京ビッグサイト南展示場で開催された Google Cloud Next Tokyo '25 に登壇させていただきました。セッションタイトルは『月間動画再生数約 5 億回を誇る TVer の、広告配信基盤における Memorystore & Bigtable 併用戦略と実践的チューニング』です。

Google Cloud Next Tokyo '25 イベントウェブサイトに掲載されたセッション概要

この記事では、登壇の振り返りと、セッション内容の簡単な紹介を書こうと思います。後日、セッションのアーカイブと資料が Google Cloud Next Tokyo のイベントウェブサイト にて公開される予定なので、この記事をきっかけに、より多くの方にセッションのアーカイブと資料をご覧いただき、TVer の広告プロダクトにご興味を持っていただけたら幸いです。

追記 (2025年8月21日)

Google Cloud Next Tokyo のイベントウェブサイトにて、セッションのアーカイブと資料が公開されました。ご覧いただくには、イベント参加登録が必要です。

セッションアーカイブと資料

イベント参加登録しても上記の URL からご覧いただけない場合は、Google Cloud Next Tokyo のイベントウェブサイトのホームから、[セッション一覧]→[ソリューション]→[データベース] と進んで、セッションタイトルでお探しください。

登壇の振り返り

私には、Google Cloud Next Tokyo '25 のブレイクアウトセッションに登壇する目的が2つありました。

  1. TVer 広告というプロダクトの技術的なアピール、すなわち月間数十億にもなる大量の広告リクエストを低レイテンシで処理する大規模システムを開発・運用していて、広告配信というビジネスクリティカルなシステムを Google Cloud 上に構築したこと
  2. 広告配信基盤のように高いパフォーマンスを要求されるシステムのアーキテクト・開発者に向けて、(1) Key-Value 型にカテゴライズされる Google Cloud の NoSQL データベースである Memorystore for Redis Cluster (MRC) と Bigtable の併用戦略、(2) Bigtable の性能を十分に引き出す方法、の2つをお伝えすること。

結果としては、目的は2つとも達成できたと感じています。

1つ目の目的は、250 名を収容可能なセッションルームが満席になったことで達成されたと感じています。いままで TVer の広告プロダクトを支えている技術について、Google Cloud Next Tokyo のような大きなテックイベントで発表したことはありませんでしたが、今回は多くの方に TVer 広告の技術的な側面を知っていただくことができました。

250 名を収容可能な Room 6 が満席の様子

2つ目の目的も、個人的には達成されたと感じています。というのも、スピーカーはセッション終了後に Ask the Speaker ブースにて、セッション参加者のご質問に回答させていただくのですが、そのブースにて他の配信事業者や、数千万の登録者を抱える大規模なWebサービス事業者に所属されている開発者の方々から、お褒めの言葉やたくさんのご質問をいただけたからです。情報を発信した直後に、私と属性の近い開発者の方々から face to face でリアクションをいただけたのは非常に嬉しくて、登壇してよかったと感じられた出来事でした。

セッション内容

セッションの内容も簡単に紹介しておきましょう。私のセッションは、4 つのセクションで構成されていました。

  1. TVerTVer 広告
  2. 広告配信と NoSQL DB
  3. MRC & Bigtable 併用戦略
  4. Bigtable 実践的チューニング

1 と 2 は導入部です。to C のプロダクトである TVer サービスに対して、TVer 広告は広告代理店様・広告主様のためのプロダクトなので認知度は高くないと考え、1 つ目のセクションでは TVer 広告の紹介をさせていただきました。2 つ目のセクションでは、TVer の広告配信基盤において、リレーショナルデータベースではなく、Key-Value 型にカテゴライズされる NoSQL データベースを採用した理由を取り上げました。弊社の広告配信基盤は、膨大な広告リクエストを低レイテンシで処理する必要があり、また、事業成長と共に合理的なコストでスケールできなければならないため、パフォーマンスと拡張性に優れた分散型の Key-Value データベース が最適な選択であった、とお話しました。

3 と 4 が本題です。3 つ目のセクションでは、弊社の広告配信基盤における MRC と Bigtable の併用戦略をお話しました。このセクションでは、広告配信・計測に必要なデータと Key-Value データベースの特徴を分析してデータストアを選ぶプロセスを紹介した後、性能試験で発生した課題をどのように解決したかをお伝えすることを通して、弊社における MRC と Bigtable の併用戦略を説明しました。弊社ではデータの一貫性、ストレージの上限、データベースの可用性のバランスを考慮して、MRC と Bigtable の強みを活かせるようにプロダクトを使い分けています。4 つ目のセクションでは、Bigtable の性能を十分に引き出すための実践的チューニング手法をお話しました。このセクションでは、アプリケーションから Bigtable にアクセスさせる負荷試験を実施した際に学んだ、Bigtable におけるデータ最適化の仕組みと、クライアント側のコネクションプールサイズと読み取りレイテンシの関係性の解説を通して、Bigtable に大量の読み取りをミリ秒で処理させるチューニング方法を説明しました。

以上がセッション内容の簡単な紹介です。気になった方はぜひセッションのアーカイブをご覧いただけると幸いです。

おわりに

Google Cloud Next Tokyo '25 では、広告配信基盤の設計〜開発のフェーズで学んだ(苦労した)出来事・経験から、MRC と Bigtable にスポットを当て、汎用的な知見を抽出してお話させていただきました。私のセッションが Google Cloud で大規模システムを設計・開発するアーキテクト・開発者の方のお役に立てば嬉しいです。

今後も TVer 広告の配信を支える技術について、テックブログや Google Cloud のイベントで発信したいと思っておりますので、ご注目いただけると嬉しいです。今回のセッションで話すことができたのは、TVer 広告を支える技術の一部です。Bigtable について様々な視点から話したように見えますが、実際は広告配信サーバーからの読み取りを高速化する手法について deep dive するセッションになっていたかなと思います。Bigtable だけ取り上げても、Bigtable に大量のデータをロードするアーキテクチャBigtable のデータ集計手法、データ量の最適化など、別の角度から話したいことがありますし、GKE やログ収集/集計基盤など、データベース以外についても機会があれば発信したいと思っています。発信をきっかけに、また Google Cloud を大規模に利用しているユーザー同士で交流できたら良いなと思っています。

最後に、登壇準備に協力してくれた弊社の広報チーム、一緒に広告配信基盤を開発したチームメンバー、そして Google Cloud のご関係者の皆様に感謝を伝えて締めくくりたいと思います。Google Cloud Next Tokyo '25 のような晴れの舞台で素晴らしい発表ができたのは、皆様のおかげです。本当にありがとうございました。

PR単位の開発環境構築自動化によるWEBフロントエンド開発の生産性向上

みなさん、こんにちは!TVer SREチーム DevOps Unitの鈴木です!

TVerでは採用に非常に力を入れており、おかげさまで社員数が右肩上がりに増え続けています。 note.com

TVerでは、WEB、iOS/Androidアプリ、Fire TV Stickなどといった多様な端末でサービスを提供しており、それぞれに専門の開発チームが存在しています。 組織拡大に伴い、それぞれのチームで複数の新規機能開発や改善プロジェクトが同時に推進されるようになりました。

しかしながら、この急速な組織拡大に伴い開発環境の不足がボトルネックとなり、開発生産性向上を阻むという課題が浮き彫りになりました。

開発組織全体の生産性向上は、私たちSREチームの重要なミッションの一つです。

本記事では、この多岐にわたる開発チームの中でも、WEBフロントエンドチームが抱えていた「開発環境の課題」に焦点を当て、PR単位での自動開発環境構築というアプローチが、どのような効果をもたらしたのか紹介します。

なお、本記事は以下の記事から着想を得たものであり、@dtaniwaki さんにこの場を借りてお礼申し上げます。

techblog.jmdc.co.jp

1. 開発環境の課題

WEBフロントエンドチームでは、組織の拡大と並行して進むプロジェクトの増加に伴い、いくつかのボトルネックが顕在化していました。

開発環境利用における待機時間の発生

これまで、利用できる開発環境の数が限られていたため、複数の開発メンバー間で開発環境の利用が集中し、使いたい時に使えないという状況が常態化していました。これにより、自身のコードのテストや機能の確認を行う際に、不要な待機時間が生じていました。

レビュープロセスの遅延

PRのレビューにおいては、実際に動く開発環境での確認が必須です。 しかし、開発者だけでなくPdM(プロダクトマネージャー)やQAチームのメンバーも動作確認を行うため、開発環境を占有する時間が長くなりがちでした。 結果として、開発環境の待機時間が発生し、レビュープロセス全体が滞る主要な原因となっていました。

構築・運用コストの高さ

従来の開発環境はバックエンドアプリケーション、データベース、外部サービスなど全ての機能を含むフルパッケージ構成でした。 この構成では構築・維持にコストがかかるため、需要に応じて柔軟に開発環境を増やすことができませんでした。

データの不整合

フルパッケージ構成の開発環境はそれぞれの開発環境でデータベースが独立しているため、参照できるデータが開発環境ごとに異なるという課題がありました。 これにより、フロントエンド開発者が特定のUI/UXやユースケースを検証したい際に、必要なテストデータが存在しないケースが頻発し、検証作業に支障をきたしていました。

2. 課題解決のためのアーキテクチャ

前述の課題解消にあたり、PR単位でWEBフロントエンド開発環境を自動で構築できる仕組みを用意しました。 アーキテクチャとしてはCloudFrontとS3を利用した非常にシンプルな構成になっております。

今回のアーキテクチャの特徴は以下になります。

  • CloudFront FunctionにてサブドメインのPR番号を取得し、PR番号に応じたパスに書き換える
  • ワイルドカードドメインで任意のPR番号で対象PRの画面を確認できるように
  • PRにdeploy-prラベルの付与をトリガーにS3のPR番号フォルダ配下に自動デプロイ
  • バックエンドはテストデータが充実した既存の開発環境を参照

新しく上記リソースをCDKで用意するだけだったため、少ない工数ですぐに構築することができました。

3. PR単位の開発環境構築がもたらした効果

今回の対応で以下の効果をもたらしました。

課題の解消

開発環境利用における待機時間の解消

新しい仕組みでは、PRに特定のラベルを付与するたびに、専用の開発環境がゼロから自動で構築されます。 これにより、誰もが「確認したい」と思ったその瞬間に、自身の変更が反映された独立した開発環境を利用できるようになりました。

レビュープロセスの効率化

PR単位でユニークなURLが発行されるため、開発者、PdM、QAメンバーは、確認したい時に、確認したいPRの開発環境へ直接アクセスし、独立して動作確認を行えるようになりました。 GitHub Actionsによる開発環境の自動作成は、構築時間を大幅に短縮し、すぐに検証を開始できるため、レビュープロセス全体が飛躍的に効率化されました。

構築・運用コストの最適化

従来のフルパッケージ構成の開発環境ではなく、WEBフロントエンド用開発環境のみを必要な時に即時かつ自動で構築できるようになったため、インフラの構築・維持にかかるコストを大幅に削減できました。

テストデータ不整合の解消

PR単位の開発環境はテストデータが充実しているバックエンド開発環境に接続するようにしました。 これにより、実施したいテストを確実に行えるようになり、検証の品質が向上しました。

データで見る開発生産性の向上

今回、PR単位の開発環境構築を自動化したことで、WEBフロントエンドチームの開発生産性がどのように向上したのかを、開発組織の生産性分析ツールであるFindy Team+のデータで見てみましょう。 この仕組みを本格的に導入した2025/06以降、PR作成数や開発者数に変化がない中で、開発フローにおける複数の重要な指標で顕著な改善が見られました。

変更のリードタイム

変更のリードタイムは約80%(前月比)ほど減少しました。 これは、コードの変更(コミット)してからmainブランチにマージされるまでの、開発サイクル全体のスピードが大幅に向上したと読み取れます。

PRオープンからレビューまでの平均時間

PRオープンからレビューまでの時間は約40%(前月比)ほど減少しました。 PRが作成されてから、レビュアー(開発者、PdM、QA)がレビューを開始するまでの時間が短縮され、開発環境の待機時間が解消されレビューに着手しやすくなったことを表しています。

もちろん、これらの数値改善は「PR単位の開発環境構築自動化」のみが要因ではありません。 開発チーム全体の継続的な努力や改善活動も大きく寄与していることを認識しております。

しかし、WEBフロントエンドチームから「従来の開発フローにはもう戻れない」という嬉しい声をいただいており、今回の対応が開発生産性向上に貢献できたと思っております。

4. まとめ

今回はWEBフロントエンド環境構築の自動化によってWEBフロントエンドチームの開発生産性が向上した話を紹介させていただきました。

SREチームでは組織全体の開発生産性向上をするためにまだまだたくさん解消しなくてはいけない課題が存在するため、興味がある方は以下からのご応募お待ちしております。

herp.careers

TVerにおける生成AI活用の現在地 - Claude MAX導入から活用事例まで

TVerの開発組織で本部長をしている脇阪(@tohaechan)です。

先日、GENDA Tech Talk#1 で登壇する機会をいただきました。 今回はその内容を振り返りながら、TVerでの生成AI活用の取り組みについてお伝えします。

登壇資料

当日の登壇資料はこちら

speakerdeck.com

きっかけは開発合宿

TVer社内では3月ごろから、Devin、Claude Teamプラン、Cursorなどを導入していました。

バックエンドの開発にDevinを試し、アプリ開発周りでClaudeを使い、ドキュメント整備周りでCursorを使い…、というような試験的な取り組みです。 ただし組織の全員が使っているというわけではなく、一部の人がどこまで使えそうかを確認している状態。または一部の人は便利に使いこなしているが、業務に余裕がない人はなかなか着手できないというような状態でした。 業務に余裕が無い人ほど使ってほしかったのですが、なかなかうまく展開できないという組織的な課題がありました。

そんな中、バックエンドチームで生成AI縛りの半日合宿を実施しました。 techblog.tver.co.jp

当時のモデルはそこまで賢くなく、生成されたコードに文句が多くありましたが、それでも短時間で動くものができ手応えを感じます。 これをバックエンド開発だけでなく全社的に展開したく、そして自身も生成AI沼にハマるための時間を強制的に作るために、開発合宿を行うことを決めました。

techblog.tver.co.jp

開発合宿に関しては上記の記事にありますが、 合宿では参加者がそれぞれ生成AIを使ってプロダクトを開発しました。 希望者にはClaude Codeを利用してもらいました。自身もここで初めて本格的に利用したのですが、明らかな手応えを実感することになります。 合宿後、エンジニアとエンジニアマネージャーから「Claude Codeを全社で使いたい」という声が多数上がりました。

ちなみに、登壇では「湯河原に行けばすべてが解決します!」と会場で話をしたのですが、生成AIの取り組みだけでなく、チームビルディング的な意味でもとても良かったのでおすすめです。

Claude Code MAXプランの全社展開

この声を受けて(正確には受ける前から動いてはいたのですが、経理周りをどうするかの調整に時間がかかった…)、合宿の成果をGeminiで提案資料にまとめ、役員会でプレゼンテーションを実施。 結果として以下の承認を得ることができました。

  • 全エンジニアのClaude Max 20x Proプランの予算承認
    • Claudeだけでなく、今後も継続的に投資をしていく
  • 新プロジェクトの始動
    • 合宿の成果物をベースにした新プロジェクトの始動

というわけでTVerでは7月から全エンジニアがClaude Codeを利用しています!!!

実際に起きた変化

Claude Code導入後、組織に様々な変化が生まれています。 先日の登壇資料にもありますが、いくつか抜粋して紹介・補足します。

エンジニアリングマネージャーの変化

マネジメントに専念していたマネージャーが、再び実装に携わるようになりました。 バックエンドのEMは、MTGの合間にIssueを作成してMTG中にClaudeに実装させるというような流れ。 QAのEMはiOSのE2Eテストの基盤を開発してました。 私も誰もメンテしてない古のリポジトリを調査させて修正させたり、インシデント対応をさせたり、なれないiOSの実装を確認したり…、Claudeを楽しく利用しています。

PdMも開発に参画

技術職以外のメンバーも開発に参画できるようになりました。

Claude Code Actionの環境を整備し、Issue作成→AI実装→PR作成の流れを確立しています(ただ最近はClaude Code Actionがうまく動かず停滞中…) もともとタスク管理をGitHub IssueとProjectで行っていたので、自然な流れで実装を依頼できる点が良かったです。 一方でレビューや検証の量が増えることは課題感としてありますし、パフォーマンス面での懸念もあります。 資料の中で取り上げた一例の話にはなりますが、最初Claudeが出してきたPull Requestにはパフォーマンス上の課題がありました。 加えてテストがもともと書かれてないコードだったので、エンジニアが代わりに動作確認をするなど、完全にPdMが開発をしたとは言い切れないものでした。 ですが、きちんとテストが整備されていたり、負荷試験も同時に行われたり、QAを手厚く行うようにするなど、周辺環境が整いさえすればエンジニアなしで完結する可能性は高いので今後もトライしていきます。

その他の生成AI活用事例

資料にも記載していますが

  • QA分析の自動化
  • ペルソナ作成の自動化

など、実装とは直接関係ありませんが、開発プロセス全体で見ると大きく影響する部分での生成AI活用も進んでいます。 他にもドキュメント整備や運用の自動化なども進んでいます。

見えてきた課題と対応

生成AI活用が進む中で、新たな課題も見えてきています。

レビュー・検証のボトルネック

個人の生産性が向上した結果、レビューや検証工程がボトルネックになるという新たな課題が生まれています。 一つの課題を解決すると次の課題が顕在化する——これは組織が成長している証でもありますが、マネージャーとしては先回りして対応策を準備していく必要があります。

組織全体への展開

開発組織では生成AI活用が着実に進んでいますが、会社全体で見るとまだ活用の余地が大きく残されています。 そこで、まずエンジニアが先行して成功事例を積み重ね、その知見を組織全体に展開していく戦略を取っています。

「習うより慣れろ」の精神は、エンジニア以外のメンバーにも当てはまります。 組織全体での活用を加速させるには、まず実際に触れてもらう機会を作ることが重要だと考えています。 今後は、エンジニア向けの開発合宿に加えて、他部門も交えたミニ合宿なども企画していく予定です。

おわりに

生成AIの価値は、コーディングだけにとどまりません。開発プロセスの様々な場面で活用することで、組織全体の開発速度を向上させることができます。 生成AIの知見を持つエンジニアは、設計・実装だけでなく、組織全体の生成AI活用をリードする役割も担っていけると良いと思っています。 TVerは「全員が作り手になる組織」を目指して、これからも挑戦を続けていきます!

TVerでは生成AIを活用して新しい開発文化を一緒に作っていく仲間を募集しています。

TVer採用情報

TVerのエンジニアで湯河原へ開発合宿に行きました!

おはようございます。こんにちは。こんばんは。 TVeriOSエンジニアの遠藤(entaku)です。

6/19,20でTVerのサービスプロダクト本部内のエンジニアで湯河原へ開発合宿へ行ってきました。

今回は湯河原駅からバスで10分ほどのところにある、【公式】ニューウェルシティ湯河原 を利用させていただきました。

当日までの流れ

今回の開発合宿のテーマは「AI」。 会社で利用している、Gemini や Claude Codeなどを利用して、業務効率化やTVerへの新企画を導入してみよう!というものでした。

チーム分けは事前にアンケートを取り、「一人で開発したい」、「複数人で開発したい」、「どちらでもよい」をヒアリングし、希望に沿った形にしました。 結果としては3〜4人チームが4つと、1人チームが2つの合計16人6チームとなりました。 複数人のチームは、所属をバラバラにしてフロントもバックエンドもインフラも担当ができる構成にすることで、組織の横断的な交流と、普段の業務とは離れた発想ができるようにしました。

また合宿のしおりをGitHub Pagesで作成し、合宿当日の持ち物や予定表、注意事項などの情報をまとめて誰でも確認しやすいようにしておきました。 合宿のしおりでは、湯河原駅までの行き方や、ホテル情報、タイムテーブル、チーム、部屋割りといった情報を記載しました。このあたりも、Cursor上で「こんな情報載せてほしい」といったプロンプトを投げて、AIが作ってくれたので運営の負荷になることなく準備することができました!

合宿当日

当日はチーム毎に湯河原駅周辺へ集合し、ホテルへ向かいました

ホテルの会議室へ入ると早速チームに分かれて作業開始!

ホワイトボードなどを使って、今回のテーマをそれぞれのチームで開発を進めました。限られた時間なので何を作るかをチームで相談しながら、アウトプットを少しずつ作って行きました

合宿の夜はみんなで食事をとりました!普段は同じプロジェクトではない人たちとも交流ができているようでした。

2日目はホテルの会議室へ集まって、発表会...! TVerアプリへ新たな一機能を入れるチームや、日々TVer内で発生している事象をニュース形式にして話すサービスなどを発表いただきました👏

最後にチームの表彰がありました👏 表彰チームへのコメントと合わせて、AIによってプロダクト開発が変わっていくこと、それでも開発自体は無くならないことがお話にありました。 僕らも2日間を通じて、AIによって今後のプロダクト開発が大きく変わっていくだろうことを肌で感じました。

最後にホテルの前で集合写真を撮りました〜心なしかみんなやり切った顔ですね✨

参加者の声

合宿終了後に参加者へアンケートをとりました。

普段は作れない時間でがっつりAIで開発をする経験ができて良かったという意見や、いつもは業務で関わらないメンバーとも開発という形で交流することができた合宿となったようです✨

しっかりとAI (Claude Codeなど)と向き合う時間が取れてよかった。結局時間をどう確保するかが大事だと思っているので、そういう意味でめちゃくちゃいい機会だった。


普段話さないメンバーと一緒に開発することが関係性を深める機会になった。


普段、チームでは既存のコードを意識しながらAIにはサポートツールとして動いてもらうような使い方をすることが多かったですが今回0->1の開発をする中で改めてパワーを感じました。例えば、ざっくりとしたアイディアから簡単なPoCをやるみたいな事はAIを使って一気にコードを書いてみるというのは使えそうだなと感じます

今回の合宿で生まれたアイデアや学びを、これからのTVerのサービス開発に活かしていけるよう、日々の業務に邁進していきます。そして来年もまた、新たなテーマで開発合宿を開催できることを楽しみにしています💪

TVer WebのUI構築

TVerのWebフロントエンドエンジニアのJeun Yun (Paul) Tsangです。2024年から始まったWebフロントエンド開発の内製化によって改善した、 tver.jp のUI構築の考え方を紹介します。

tver.jpの技術スタック

以下は改善後のフロントエンド技術スタックです。

内製化で見えてきた課題の全体像

私は2024年10月にTVerへ入社してから、新しい機能を実装しながら既存コードの可読性や使いやすさの問題に気づきました。これまで外部パートナーに依存していた開発体制では、コードの統一性やアーキテクチャの一貫性に課題もありました。フロントエンドチームの内製化を進める中で、長期的なビジョンを描きながら品質向上と開発効率を改善するために、チームで課題を洗い出した結果、主に以下の3つの領域で問題があることが明らかになりました。

1. アーキテクチャの混乱による開発効率の低下 - コンポーネントの責任分界が不明確で、可読性・メンテナンス性に課題 - 再利用性を考慮した設計になっておらず、カスタマイズ性・拡張性に問題

2. デザインシステムの未整備による非効率な開発 - 統一されたデザイン仕様がなく、個別実装による重複コードの発生 - CSS管理が非効率で、開発者の使いやすさ・生産性に課題 - 類似コンポーネントでもUIの見た目や挙動が微妙に異なり、ユーザー体験の一貫性が損なわれる問題

3. 開発・テスト環境の不備による品質担保の困難 - コンポーネント検証環境の不足 - UIの変更影響範囲の把握が困難

これらの課題を解決するため、以下の改善戦略で取り組みました: - アーキテクチャの再構築によるコードの整理と責任分離 - デザインシステムの導入と標準化による開発の標準化と効率化 - 開発・テスト環境の整備による品質向上

課題解決のアプローチと実装した施策

1. アーキテクチャの再構築

新しいコンポーネントの実装やデザインシステムを導入する前に、根本的なアーキテクチャを改善する必要がありました。既存の構造的な問題を解決せずに新機能を追加しても、可読性とメンテナンス性の課題が残り続けてしまうためです。そこで、まず以下のアーキテクチャ改善に取り組みました。

Feature-Sliced Designによる可読性とメンテナンス性の改善

特に気になったのは、コードの可読性とメンテナンス性に関する構造的な問題でした。すべてのコンポーネントが単一の/componentsディレクトリに配置されており、汎用的なUIコンポーネントと特定の機能やページに紐づくビジネスロジックを含むコンポーネントが同一のフォルダーに混在していました。例えば、Buttonのような再利用可能なUIコンポーネントと、EpisodePageContainerのような特定のドメインに関連するコンポーネントが同じフォルダに並んでいる状況でした。

この問題を解決するために、Feature-Sliced Designアーキテクチャを採用しました。Feature-Sliced Designは、shared(共通関数、汎用コンポーネント)、features(機能)、pages(ページ)などの層に分けることで、コンポーネントの責任と依存関係を明確にするアーキテクチャパターンです。これにより、どこに何があるかが直感的に理解でき、コードの可読性を改善できました。

さらに、Container/Presentationalコンポーネントのパターンが採用されていないため、データ取得やビジネスロジックとUI表示の責任が混在したコンポーネントが多数存在していました。これにより、コンポーネントのファイルサイズが肥大化し、理解と修正が困難になっていました。

この問題に対して、Container/Presentationalコンポーネントのパターンを導入してデータ取得とUI表示の責任を分離し、コードの可読性とメンテナンス性を改善しました。Feature-Sliced Designと合わせて、ビジネスロジックも独立した関数に分割することで、単体テストの作成が容易になり、再利用性も向上しました。

以下の例では、ContainerでデータとビジネスロジックをUIコンポーネントから分離することで、可読性とテストしやすさを改善できました。

// EpisodeContainer.tsx
const EpisodeContainer = () => {

  const episodeData = useEpisodeData()

  // ロジックの分離で再利用性の向上と単体テストの実装がやりやすくなる
  const episodeStatus = getEpisodeStatus(episodeData)

  return <Episode episode={episodeData} status={episodeStatus} />
}

// Episode.tsx
const Episode = (props) => {
  return (
    <section>
      <h1>{props.episode.title}</h1>
    </section>
  )
}

コンポーネント設計による拡張性の向上

既存の汎用コンポーネントは、CSSとPropsを簡単にカスタマイズできない状態で、コンポーネントの再利用性に問題がありました。新しいデザイン要件が発生した際に、既存のコンポーネントを拡張するのではなく、似たような新しいコンポーネントを作成してしまうことが多く、コードの重複や管理の複雑化を招いていました。

上記の可読性とメンテナンス性の改善により、ビジネスロジックを分割した後、コンポーネントの機能を達成するために必要なPropsとCSSを簡単に設定できるようになり、コンポーネントの再利用性を改善できました。今後、新しいデザイン要件により既存コンポーネントの新しいバリエーションが必要な場合は、元のコンポーネントを修正したり完全に新しいコンポーネントを作成するのではなく、既存コンポーネントと分割した関数の機能を活用しながら拡張したコンポーネントを簡単に実装できます。これにより、コンポーネントの再利用性と開発の生産性を向上できました。

2. デザインシステムの導入と標準化

アーキテクチャの改善により安定した基盤が整った後、次にデザインシステムを基盤とした新しいコンポーネントの実装に着手しました。以下、デザインシステム導入の取り組みについて紹介します。

Radix Primitivesによる高品質なコンポーネント基盤の構築

TVerは自社のデザインで開発しているため、これまで外部のUIフレームワークを採用していませんでした。汎用コンポーネントの再実装とデザインシステムの導入をきっかけに、自社UIフレームワークを作ることが決まりました。しかし、ゼロから全ての機能を実装するのではなく、業界標準の仕様は外部パッケージに任せ、TVerの独自デザインの実装に集中できる開発環境を選択しました。そこで、汎用コンポーネントの再実装を始める前に、ヘッドレスUIライブラリであるRadix Primitivesを採用することにしました。

Radix PrimitivesはヘッドレスUIライブラリで、CSSが含まれていないため、簡単に独自のCSSを設定でき、高いカスタマイズ性を持つツールです。

採用理由

デザインシステムを元に汎用コンポーネントの再構築

チームの内製化以前は、汎用コンポーネントがありながらデザインシステムの意識が不足しており、各画面のデザインを統一することが困難な状態でした。デザインシステムに基づいたコンポーネントが存在せず、毎回個別にCSSを定義する必要があったため、コンポーネントの使いやすさに問題がありました。また、デザイン仕様の統一も困難で、全体的に開発生産性に課題がある状態でした。

特に問題だったのは、同じ機能を持つボタンでも、ページによって微妙にスタイルが異なったり、フォントサイズや余白の値がバラバラだったりと、UIの一貫性が保たれていないことでした。これにより、ユーザーが同じサービス内で異なる体験をしてしまい、ブランドの統一感やユーザビリティが損なわれていました。

そこで、デザインシステムの導入とコンポーネント基盤の整備により、開発の標準化と効率化を進めました。

デザイントークンとSassによる開発効率の向上

開発者の使いやすさと生産性の観点では、CSSの管理と開発体験に課題がありました。CSSの変数はカラー定義のためにしか使用されておらず、Sassも活用されていない状態で、重複したCSSが多く存在していました。これにより、開発生産性や仕様統一の難しさが問題となっていました。

この課題を解決するために、デザイントークンベースのCSS変数システムと、Sassのmixin機能を活用したスタイル管理を導入しました。レスポンシブデザインやタイポグラフィ、スペーシングなどを統一された方法で管理できるようになり、開発効率と品質の向上を実現しました。

例えば、以下のように毎回media queryを記述する代わりに、Mixinとして定義することで仕様の統一とメンテナンス性を改善できます。

@mixin sp {
  @media screen and (max-width: 845px) {
    @content;
  }
}

.component {
  @include sp {
    // スマホサイズのCSS
  }
}

デザイントークンによるスタイル統一の実現

当時、デザインチームでもFigmaにデザインシステムの導入を開始していたため、それをきっかけにデザインシステムの概念を意識しながら新しい汎用コンポーネントを作り直し始めました。デザイントークンの整備も並行して行ったことで、CSSの実装がより効率的になりました。

従来の実装方法

カラーに関する変数は存在していましたが、各画面のコンポーネントに個別のCSSを設定していたため、メンテナンス性とコンポーネントの再利用性が低下していました。また、ホバーやフォーカスなどのインタラクティブなスタイルの実装も困難な状況でした。

例えば以下のように、背景色は同じでありながら個別に設定されており、同じ仕様であるはずなのにPaddingが異なるといった問題がありました。

.button-a {
  padding: 12px;
  background: var(--bg-blue-btn);
  font-size: 14px;
}
/* 同じ仕様はずのにpaddingが違う */
.button-b {
  padding: 10px;
  background: var(--bg-blue-btn);
  font-size: 14px;
}
改善後の実装方法

カラーの変数だけではなく、PaddingやTypographyのデザイントークンを作成し、コンポーネント全体を共通化して必要なバリエーションを定義することで、コンポーネントの再利用性と使いやすさを改善しました。Figmaに同じバリエーションが定義されているため、デザインと同じ変数名を設定すれば、簡単にデザイン通りのUIを再現できるようになりました。

以下の例では、各Buttonのバリエーションを汎用コンポーネントに定義し、使用時にはバリエーションのPropsを設定するだけで、必要なデザイン要件を迅速かつ簡単に実現できるようになりました。これにより、アプリ全体のUI統一も改善できました。

/* Button.module.scss */
.primary {
  background: var(--Surface_Accent);
  color: var(--Content_Inverse);

  &:disabled {
    background: var(--Surface_Disabled);
    color: var(--Content_Disabled);
  }
}

.sm {
  @include Button_S; // TypographyのMixin

  padding: var(--Spacing_0) var(--Spacing_150); // Paddingの変数化
  height: 24px;
}
// Buttonコンポーネントを置くだけで楽にUIを実装できる
<Button color="primary" size="sm" />

3. 開発・テスト環境の整備

アーキテクチャの再構築とデザインシステムの導入により、新しいコンポーネントが作成できるようになりました。しかし、これらのコンポーネントの品質を継続的に担保するためには、適切な検証とテスト環境が不可欠でした。そこで、開発・テスト環境の整備に取り組みました。

StorybookとChromaticによる品質向上

内製化以前は、Storybookを採用せずにコンポーネントを実装していました。そのため、コンポーネント単体での状態検証やテストが困難で、開発の生産性と品質に課題がありました。

この課題を解決するため、コンポーネントの可視化やテスト環境を改善するためにStorybookとChromaticを導入しました。Storybookを使用することで、データや実際の画面がなくてもコンポーネントの状態を検証でき、プロトタイピングが容易になります。Chromaticは無料プランでもStorybookのホスティングとVisual Regression Testing (VRT) が利用できるため、導入しやすいツールです。UIのビジュアルテストにより、CSSとHTML構成の変更がユーザーに見えるUIへ与える影響範囲を検証でき、品質の担保が効率的に行えます。さらなる品質向上のため、今後はインタラクションテストやビジュアルテストの強化を計画しています。

Storybookのコンポーネント検証

ChromaticのVRTとUIレビュー機能により、CSSとHTML構成の修正によって発生するUI変更を効率的に検証できます。

ChromaticのVRT機能

今後の取り組みと最後に

今回は、TVer Webフロントエンドの内製化によって改善したtver.jpのUI構築について紹介しました。内製化の1年目で、すでに多くの課題を解決し、開発体験を向上させることができました。しかし、まだ解決すべき課題は多く残っており、今後もユーザー体験の向上はもちろん、アプリのパフォーマンスや開発生産性のさらなる改善に取り組んでいきたいと考えています。

例えば以下のような点です。

今回紹介した取り組みは始まったばかりですが、チームとしてTVerのフロントエンド開発の生産性と品質向上に取り組んでいます。もしこのような技術的チャレンジに興味を持っていただけましたら、ぜひ採用サイトから応募してみてください!

TVerバックエンド開発におけるAIツールの導入の今〜2025年Q1編〜

みなさん、こんにちは。TVer サービスプロダクト本部バックエンドEMの和田(@tench_oo)です。

いきなりですが、世の中AIが著しく成長していっていますよね。
取り残されないようにしないといけないと思い情報収集するのも大変なほど、日々新しい刺激が待っているのが今のAIの状況な気がしています。
そんな環境で、バックエンド部でもAI開発ツールの導入を進めていて実際に活用しており、その取組を一部ご紹介していきたいと思います。
(TVerもちゃんとAIを活用しはじめているんだよ。というアピールです。)

バックエンド部が活用するAIツール

現在バックエンド部では、いくつかのAI開発ツールの導入検証を進めています。
導入する際には各社AIツールのポリシーを確認し、データの学習に使われているかなどの点をチェックしたうえで導入を進めています。

主に利用しているツール:GitHub Copilot

チームでライセンスを契約し、全エンジニアが利用できる公式ツールとして導入しています。IDE統合開発環境)上やGitHub上で動作し、日々のコーディングにおける強力なサポート役となっています。

主な用途としては、

  • IDE上でのリアルタイムなコード補完
  • 定型的な関数やクラスのひな形生成
  • コメント(自然言語)からのコード生成

などが挙げられます。
TVerはGo言語を利用してバックエンドを実装していますので、ちょっと大きめの構造体なんかを定義するときは、AIによるコード補完によって作業を効率化させることが多いです。
反復的な処理を削減することができるため、エンジニアは本質的なビジネスロジックの設計や実装に集中することができるため、活用しています。
最近では、より広範なタスクを自動化するGitHub Copilot Workspaceのようなツールも登場しています。チームでも検証しましたが、同様の役割において、現在は後述するDevinの活用に特に注目が集まっている状況です。進化が早い。

次によく使うツール: Devin

Devinは、IssueからPR作成までの開発プロセスを一貫して行ってくれる言わずと知れた自律型のAIエージェントです。
TVerのSlackにはDevin専用のchが存在していて、お互いのプロンプトを共有することでナレッジをためながら使えるような運用をしています。

なんといっても、自律型ということでGitHub Issueにやりたいことや実現したいことを日本語でつらつらと書いて、URLを渡すだけである程度完成したコードをPRとして作ってくれる点が優れています。
生成されたコードを元に、人間による詳細なレビューと修正を加えた上で、 プロダクションに投入されたAPIもいくつか生まれています。このように、開発の初速を上げる役割として、Devinはチームで重要な存在になりつつあります。

コードレビュー: Gemini Code Assist

先月からコードレビュー補助ツールとして、Gemini Code Assistを導入しています。
なかなか鋭いコードレビューをしてくることもあり、見落としてしまうような細かいところにも気がつくきっかけになり重宝しています。
バックエンドのEnablingチームが、Gemini Code Assist用のレビューの styleguide.md の作成と管理をしてくれているため、導入から1ヶ月も経たないうちにTVerバックエンドアーキテクチャの特性やコードスタイルを理解してくれて、レビューの質も向上してきています。

※バックエンドのアーキテクチャはぜひこちらをご覧ください。

techblog.tver.co.jp

壁打ち・相談役としてのLLM活用

会社として導入しているGoogle Workspaceに付属しているGeminiの活用も進めています。
社員であれば誰でもGemini 2.5 Proが利用できるため、広大なコンテキストウィンドウを活かし、仕様に関する壁打ちや実装相談の相手として利用するシーンが増えています。

また、一部プロジェクトではNotebookLMの活用も始まりました。要件定義書やDesign Docなどをソースとして入力し、プロジェクトの仕様や決定事項をいつでも質問できる「ヘルプセンター」のような役割を担っています。これにより、エンジニアだけでなくPdMなどのメンバーも、ドキュメントを探し回ることなく迅速に情報へアクセスできるように整備をすすめています。

今後の導入予定ツール

さらに、チーム全体の開発能力を底上げする次の一手として、コーディングに特化したAIであるClaude Codeの導入準備も進めており、活用の幅は今後も広がっていく予定です。

半日AI合宿もやってみました

チーム内でAIツールの活用が進む中、個人の知見をチーム全体に広げ新たな可能性を探ることを目的に、4月にバックエンドチームの有志で「半日AI合宿」を開催しました。
(写真をとる習慣がなく、合宿の様子がわかる写真はゼロです)

お題

「業務が良くなるツールを作る」
自身やチームの業務で「これがあったら効率上がる!」と思えるものを、AIと一緒に企画・開発するという内容でした。

ルール

人間がコードを書くことを禁止し、AIツールのみがコードを書くことだけを良しとしました。
プロンプト力が求められることから、これからのバックエンド開発のチームの開発力の底上げを目的としています。
時間は4時間。限られた時間の中で、企画から実装までをこなさなければならないので、AIをうまく駆使して成果に繋げなければなりません。

結果

完璧に仕上がったメンバーはゼロでしたが、企画から実装の途中までいくつか面白いアイデアが生まれたので、一部をご紹介します

  1. rails routes コマンドみたいなGoのコマンド
  2. 革新的なAPI負荷テストの新時代へ。負荷試験ツールのテストシナリオ自動生成ツール
  3. DBのテーブル消したらどこに影響あるか教えてくれるツール

どれもAIを壁打ちをし、先ほどご紹介したツール群を活用して実装をしていました。
しかし、当時は導入したてのツールも多く、「期待通りのコードが一発で出てこない」「どう指示すれば意図を正確に汲み取ってくれるのか」など、まさにツールと対話しながら仲良くなることに多くの時間を使いました。この試行錯誤そのものが、大きな学びだったようです。
この半日合宿を契機に、SlackでのAIに関する質問や「こんな面白い使い方を見つけた」といった情報共有が以前にも増して活発になり、チーム全体のAIに対する解像度が一段上がったように感じています。

おわり

この記事を書いている最中にもGemini CLIが発表されたりと、本当に目まぐるしく動いていくAIエージェントの世界ですが、 それに遅れることなくチームとしてもキャッチアップと活用を進めていきたいと思っています。
あくまでこの記事は「バックエンド部の2025年Q1の現状」ですので、きっと他のバックエンドメンバーやお隣フロントエンド部のだれかが定期的にAIツールの現状をまとめてくれることでしょう。
それを期待していただきながら、終わりとさせていただきます。

TVerのサービス開発をAI使いながらスピード感を高めながら、開発したいという方はぜひご応募お待ちしています。

herp.careers