1. はじめに こんにちは。株式会社タイミーのデータサイエンスグループ(以下、DSG)でグループマネージャーを務めている菊地です。 前回の記事 では、タイミーのDSGが認知負荷をコントロールするために仮想チームという形態をとり、チームトポロジーの考え方をベースに組織を運営していることをお話ししました。 その中で、MLOpsエンジニア主体のプラットフォームチームの役割を「専門性を最大化するための共通基盤を提供すること」と定義しました。現在、その基盤の上でホットなトピックとなっているのが、LLMをはじめとする基盤モデルの活用です。 昨今の基盤モデルの急速な進化に伴い、タイミーの各プロダクトチーム(チームトポロジーにおけるStream Aligned Team、以下SA Team)からも「基盤モデルを使ってユーザー体験を向上させたい」というアイデアが次々と生まれています。プロダクト内のコンテンツ生成から業務の効率化まで、基盤モデルを活用することで解決できる課題の幅は非常に多岐にわたります。 ただ、基盤モデルをプロダクトの機能として組み込むプロセスは、従来のソフトウェア開発とは異なる考慮事項も多く、不確実性も伴います。 「そもそもこの課題に基盤モデルは最適なのか?」 「精度の評価はどう客観的に行えばいいのか?」 「セキュリティやコストの管理はどうすべきか?」 これらの問いに対して、すべての案件にMLOpsエンジニアやデータサイエンティストが付きっきりで関与していると、どうしても開発のスピード感を維持するのが難しくなることもあります。DSGがボトルネックになるのではなく、SA Teamが自分たちの力で自律的に、かつ安全に基盤モデルを活用した機能をリリースできるような状態を整えていく必要があります。 そのような背景から、DSGとして「基盤モデルを用いた機能開発のガイドライン」を策定しました。 本記事では、SA Teamのセルフサービスな開発を支援し、組織全体で価値提供を加速させるためのガイドラインのエッセンスをご紹介します。 2. 開発体制パターンとDSGの関わり方 基盤モデルを活用した機能開発を進めるにあたり、まず私たちが整理したのが、開発の特性に応じた開発体制パターンです。 すべての開発を同じフローに乗せるのではなく、技術的な複雑さや求められる専門性に応じて役割分担を明確にすることで、SA Teamが迷わずに開発を開始できるようにしています。 選択の指針:スピードか専門性か これら2つのパターンのどちらを選択するかは、主に「基盤モデルの出力がそのまま価値になるか」、それとも「複雑なロジックや既存システムとの高度な統合が必要か」という観点で判断します。 パターン1. セルフサービスパターン(ガイドラインのメイン対象) SA Teamが主体となり、クラウドプロバイダーが提供するAPIを利用して開発を進めるパターンです。基盤モデル周辺の実装が比較的シンプルに完結し、プロンプトの調整や基本的なRAG(検索拡張生成)の構成で十分な価値が出せるケースを想定しています。 主なユースケース:定型文の生成、ドキュメントの要約、シンプルな分類タスクなど。 責任の所在:機能の企画、プロンプトエンジニアリング、実装、評価までをSA Teamが完結して持ちます。 DSGの役割:DSGは、API利用環境の払い出しや、セキュリティ・コストのガードレール提供、技術的な壁打ち相手としての伴走(Enabling)に徹します。 このパターンの最大のメリットは、DSGとの調整コストを最小化し、SA Teamのスピード感で価値検証のサイクルを回せることにあります。 パターン2. Complicated Subsystemパターン システムやロジック自体が高度に複雑で、運用・改善にデータサイエンティストやMLOpsエンジニアの専門知見が不可欠なケースです。例えば、基盤モデルの出力を独自の数理モデルや推薦アルゴリズムと組み合わせる場合や、ドメイン特有の複雑な評価指標が必要な場合が該当します。 主なユースケース:複雑なマッチングロジックへの組み込み、高度な推論パイプラインの構築など。 責任の所在:DSGがアルゴリズムやバックエンドの主要ロジックに責任を持ち、SA Teamと協力してプロダクトへ統合します。 DSGの役割:モデル選定からパイプライン構築、精度評価の設計までを深くリードします。 専門性が求められる部分をDSGが引き受けることで、SA Teamが基盤モデルの深い専門知識をすべて学習する負荷を下げつつ、プロダクトのコア価値を最大化します。 3. 不確実性を乗りこなす5つの開発フェーズ 基盤モデルを活用した機能開発は、従来のソフトウェア開発に比べて不確実性が高く、やってみないとわからないことが多い領域です。そのため、ウォーターフォール型で一気に作り込むのではなく、アジャイルなアプローチで段階的に仮説検証を進めることが成功の鍵となります。 ガイドラインでは、開発プロセスを以下の5つのフェーズに定義しています。ここでは、各フェーズの概要と、私たちが重視している検証のポイントを紹介します。 実際のガイドラインでは、各ステップで「どのような性質の成果物が求められるのか」を具体的に定義しています。さらに、過去の成功事例で作成したシステム構成図や、投資対効果(ROI)の判断資料、プロンプトの評価ログなどを参照できるようにしており、各ステップで目指すべきゴールを明確にイメージできるように工夫しています。 Phase 1: 計画・設計フェーズ プロジェクトの目的を定義し、ビジネス価値と技術的実現性の両面から、プロジェクトの妥当性を検証します。 検証のポイント:解決したい課題に対して基盤モデルが最適な手段であるか、成功を測るための指標(KGI/KPI)が明確か、既存システムとの安全な連携が可能か。 期待される成果物の例:成功基準を定義したドキュメント、全体的なシステム構成案、想定されるリスクと対策方針の整理。 Phase 2: PoC開発フェーズ 「この機能は本当にユーザー価値があるか?」という仮説を検証するため、最小限のコストで迅速にコア機能を構築するフェーズです。 検証のポイント:基盤モデルの応答性能が実用レベルに達しているか、提示されたユーザー体験(UX)が課題解決に繋がっているか。 期待される成果物の例:主要なプロンプトの初案、コア機能が実際に動作するプロトタイプ、コストや性能を可視化する簡易的なモニタリング環境。 Phase 3: PoC評価・本番移行計画フェーズ PoCで得られた定量的・定性的なデータに基づき、本番開発へ進むべきかを客観的に判断するフェーズです。 検証のポイント:精度、コスト、速度を総合的に評価した際に、十分な投資対効果(ROI)が見込めるか。 期待される成果物の例:本番開発への移行を判断するための意思決定ドキュメント。 意思決定のプロセス:タイミーでは、本番移行にあたって技術およびプロダクト責任者による承認を必須としており、スピードとガバナンスの両立を図っています。 Phase 4: 本番開発フェーズ 検証された価値を、全ユーザーに安定して提供できる、スケーラブルで信頼性の高い機能を構築するフェーズです。 検証のポイント:最大トラフィックに耐えうる負荷対策がなされているか、プロンプトの変更が品質劣化を招かないための評価基盤が整っているか。 期待される成果物の例:環境分離(dev/stg/prod)が徹底された本番機能、品質劣化を防ぐための自動評価(リグレッションテスト)環境、運用のための各種レポート。 Phase 5: 本番運用・継続的改善フェーズ 安定稼働を維持しつつ、収集したデータに基づいて継続的に機能を改善し、ビジネス価値を最大化するフェーズです。 検証のポイント:実際の利用データに基づき、KPIが想定通り改善されているか。 期待される成果物の例:段階的なリリース計画、インシデント発生時の対応フロー、ユーザーフィードバックの収集・分析プロセス。 継続的改善:新しいモデルの登場やモニタリング状況の変化に合わせ、迅速にプロンプトやモデルをアップデートできる体制を維持します。 4. プロダクト品質を支える技術ナレッジの体系化 開発プロセスが整っても、個々の技術的な判断基準が属人化していては、プロダクト全体の品質を一定に保つことはできません。ガイドラインでは、SA Teamが自律的に最適な意思決定を行えるよう、基盤モデル活用の勘所を技術ナレッジとして集約しています。 ここでは、私たちがガイドラインで定めている技術ナレッジの概要をいくつかご紹介します。 本当に「基盤モデル」が最適か? 基盤モデルは極めて汎用性が高いツールですが、すべての課題に対する正解ではありません。私たちは、開発を始める前に「本当にその課題を基盤モデルで解くべきか?」を立ち止まって考えることを推奨しています。 基盤モデルが得意なこと: 創造性が求められる文章生成、膨大な情報の要約、そして「文脈やニュアンス」を汲み取った高度な分類・抽出、画像や音声を統合して理解するマルチモーダルな処理。 基盤モデルが苦手なこと・適していないこと: 100%の正確性が求められる、シンプルな条件分岐で済むルールベースの処理、すでに特定のタスクに特化した専用AI APIが存在するケース。 「最新技術だから使う」のではなく、コスト・精度・安定性のバランスを鑑みて、従来通りのプログラムや専用APIの方が優れていないかを冷静に見極める眼を養うための基準を明文化しています。 素早い価値検証とデータ資産の積み上げ 一方で、基盤モデルの大きな強みは「機械学習の事前準備をショートカットできること」にあります。 従来の機械学習プロジェクトでは、特定のタスクを解くために大量の学習データを準備し、モデルをトレーニングするという数週間〜数ヶ月単位のプロセスが必要でした。基盤モデルを使えば、この重たい工程を飛び越え、プロンプトの調整だけで数日〜数週間でユーザーへの提供価値を検証できる可能性があります。 たとえ初期のAPIコストが高くついたとしても、まずは最速で「そもそもこの機能がユーザーに求められているか」という本質的な仮説に答えを出す。そして検証の過程で蓄積された「ユーザーの入力」と「フィードバック」は、将来的に専用モデルや自社独自のモデルへ移行する際の貴重な学習データとなります。 「まずは基盤モデルで素早く価値検証を行い、成功すればそのデータを基に、より最適なソリューションへ進化させていく」という、時間軸を味方につけた戦略も取りうることを明文化しています。 処理の安定性と信頼性 基盤モデルの出力をプログラムで安定して扱うためには、自由な文章ではなく、後続の処理で扱いやすい形式でデータを受け取ることが不可欠です。これは一般的に構造化出力と呼ばれていますが、私たちは構造化出力を実装における標準として定義しています。 プロンプトによる指示に加え、モデルのネイティブ機能やバリデーション用のライブラリを適切に組み合わせることで、システムの安定性を高めます。また、APIの利用制限や一時的な負荷増大によるエラーに備え、自動的な再試行や代替モデルへの切り替えといった、プロダクション環境に耐えうる信頼性設計のパターンを共通化しています。 5. おわりに 今回ご紹介したガイドラインは、一度策定して終わりではありません。現場からのフィードバックや日々進化する技術動向を取り入れながら、常にアップデートし続けるドキュメントとして運用しています。 私たちがこのガイドラインを通じて実現したかったのは、不確実性の高い、基盤モデルを活用した開発において、各プロダクトチームが余計な迷いなく自律的に動けるよう、必要な指針を示し、環境を整えることでした。 DSGがすべての案件を抱え込むのではなく、専門知見を標準化して組織全体に開放していく。このプロセスこそが、タイミーが技術の力でミッションを達成するための大きな原動力になると信じています。 We’re Hiring! タイミーでは、データサイエンティストやMLOpsエンジニアはもちろん、今回ご紹介したようなガイドラインや基盤を使い倒してプロダクトに価値を届けるエンジニア、プロダクトマネージャーなど、全方位で一緒に働くメンバーを募集しています! 最新の技術をどう社会実装するかという仕組みづくりに興味のある方は、ぜひカジュアル面談でお話ししましょう。皆さんの挑戦をお待ちしています! タイミー採用情報 - Product Team
1. はじめに こんにちは。株式会社タイミーのデータサイエンスグループ(以下、DSG)でグループマネージャーを務めている菊地です。 タイミーでは「『はたらく』を通じて人生の可能性を広げるインフラをつくる」というミッションを掲げ、日々膨大なマッチングデータや行動データを活用して、プロダクトの価値向上や意思決定の高度化に取り組んでいます。 ありがたいことに、最近は採用活動を通じて多くの方とカジュアル面談でお話しする機会が増えています。その中で、非常によくいただくのが「DSGはどのような組織体制で、どのようにコミュニケーションを取りながら組織運営しているんですか?」というご質問です。 これまでは面談の場で個別にお伝えしてきましたが、私たちの組織も拡大し、フェーズに合わせて柔軟に形を変えてきました。そこで今回、改めてタイミーDSGの現在の「組織のカタチ」を言語化し、候補者の皆さんに私たちのチームの現在地を詳しくお伝えしたいと思い、この記事を書くことにしました。 私たちの組織運営のキーワードは、「認知負荷の低減」と「自律性の最大化」です。 かつては全員で一つのスクラムを組んでいましたが、現在は「仮想チーム」という形態をとり、各チームが自律的に開発サイクルを回しています。本記事では、チームトポロジーの考え方を取り入れた組織構造から、具体的な開発フロー、そしてグループ内の文化までご紹介します。 2. 組織の変遷:なぜ「仮想チーム」へと移行したのか 全員ですべてを把握していた「単一スクラム」時代 以前、まだグループの人数が少なかった頃は、DSG全体で一つのスクラムチームとして活動していました。当時は全員がすべての取り組みの状況を把握し、毎日のデイリースクラムで情報を共有し、全員でリファインメント(バックログの精査)を行っていました。このスタイルは、情報の透明性が高く、誰が何をやっているかが一目でわかるという大きなメリットがありました。 急成長に伴う「認知負荷」の限界 しかし、タイミーというプロダクトの成長に合わせ、DSGが解決すべき課題は急速に増え、かつ多様化していきました。 担当するドメインの拡大 MLOps基盤の高度化と、それに伴う専門知識の深化 ステークホルダーの増加 こうした状況下で、一つの大きなスクラムを維持しようとすると、メンバー一人ひとりが追わなければならない情報量が爆発的に増えていきました。例えば、あるデータサイエンティストにとっては、自分が担当していない領域の細かい仕様検討を延々と聞き続けなければならず、逆にMLOpsエンジニアにとっては、すべてのモデルの数理的な背景まで深く理解し続けなければならない…といった具合です。 これが、本記事のキーワードである「認知負荷」が限界に達した瞬間でした。 「仮想チーム」とチームトポロジーの導入 この課題を解決するために私たちが取り入れたのが、実組織の中をいくつかの「仮想チーム」に分割する運用です。 「実組織」としては一つのDSGですが、日々の活動(スクラム)は各仮想チーム(Squad)単位で行います。この体制を設計する際、書籍「 チームトポロジー 価値あるソフトウェアをすばやく届ける適応型組織設計 」の考え方を参考にしました。 チームトポロジーとは、チームの「認知負荷」を考慮して組織とシステム構造を整合させ、高速な価値提供を目指す組織論です。私たちはこれに基づき、チームの性質を以下のように定義しました。 MLOpsエンジニア主体のチーム:プラットフォームチーム DSを中心とした多様な利用者が、ML/LLMを用いた価値提供に集中できるように、機械学習基盤やLLM基盤、CI/CD、MLミドルウェアなどの「専門性を最大化するための共通基盤」を提供する役割。 データサイエンティスト主体のチーム:コンプリケイティッド・サブシステム・チーム 推薦・マッチングやモデレーションといった特定のドメインに責任を持ち、高度なサブシステムの開発やビジネス上の複雑な課題解決を担う役割。 このように役割とチームを明確に切り分けることで、メンバーは「今自分が注力すべき領域」に認知的リソースを集中することができるようになりました。 DSG内の仮想チーム関係図 %%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'arial', 'primaryColor': '#ffffff', 'edgeLabelBackground':'#ffffff', 'tertiaryColor': '#f8fafc' }}}%% graph BT %% --- スタイル定義 --- classDef platform fill:#2563eb,stroke:#1e40af,stroke-width:2px,color:#ffffff,rx:10,ry:10,font-size:15px,font-weight:bold; classDef css fill:#f97316,stroke:#c2410c,stroke-width:2px,color:#ffffff,rx:10,ry:10,font-size:15px,font-weight:bold; classDef dsgContainer fill:#f1f5f9,stroke:#3b82f6,stroke-width:3px,stroke-dasharray: 6 4,color:#1e40af,font-weight:bold,font-size:16px; %% --- DSG内部の組織構造 --- subgraph DSG ["DSG (Virtual Organization Structure)"] direction BT %% 上層:価値創出の主体 CSS["コンプリケイティッド<br/>サブシステムチーム<br/>(Squads)"]:::css %% 下層:強固な基盤 MLP["ML基盤チーム<br/>(Platform Team)"]:::platform %% 供給フロー(強力な支援) MLP ====>|専門性を最大化するための共通基盤を提供| CSS end %% スタイルの適用 class DSG dsgContainer linkStyle 0 stroke:#3b82f6,stroke-width:4px; 関連記事として、データサイエンティストのストリームアラインドチームからコンプリケイティッド・サブシステムチームへの配置変更の変遷は、以下の記事をご参照いただければと思います。 tech.timee.co.jp 3. 現場の意思決定を加速させる「Squad Lead」 仮想チーム(Squad)は、特定のプロジェクトを遂行するためだけのタスクフォースではなく、担当ドメインの成果に対して中長期的に責任を持つ半永久的な組織として機能しています。 このSquadにおいて、現場の自律性を支えているのがDSG独自の役割である「Squad Lead(SL)」です。SLは、データサイエンティストやMLOpsエンジニアが本来の業務と兼務する形で担う「内部的なロール」です。 GMとSLの役割分担 私(グループマネージャー:GM)とSLは、「組織の土台作り」と「ドメインの戦略実行」という軸で役割を分担しています。 GM:採用・配置・評価・キャリア成長など、「ヒト・モノ・カネ」といった組織基盤の最適化。 SL:担当ドメインにおける「コト(プロダクト・課題)」の解決。ロードマップ策定、短期〜中期の成果創出、ステークホルダーとの合意形成に責任を持つ。 現場のコンテキストを一番理解しているメンバーがSLとして意思決定を主導し、私はそれを組織的な側面から全力でサポートする。この補完関係を築くことで、マネージャーがボトルネックにならないスピーディな開発体制を実現しています。また、あえて「仮想」という柔軟な形にしていることで、メンバーがリーダーシップを経験する機会を広げ、事業状況に合わせた機動的なチーム編成を可能にしています。 4. 専門性を最大化するプラットフォームと開発フロー では、具体的にどのようにプロダクト開発が進められているのでしょうか。ここからは、MLOpsエンジニアとデータサイエンティストの連携に焦点を当ててご紹介します。 MLOpsエンジニアが整える、専門性に集中するための共通基盤 MLOpsエンジニアは、いわゆるプラットフォームチームとして、利用者が本来の役割に集中できるよう、共通の開発環境やデプロイフローを整えています。 利用者の中心はDSですが、領域によってはデータアナリストやプロダクトエンジニアも想定ユーザーに含まれます。Google Cloudをメイン基盤とし、モノリポ構成でのディレクトリ設計やTerraformによる構成管理、CI/CDスクリプトの整備、さらにLLM基盤の構築やMLミドルウェアの導入・運用までを幅広く担当します。これにより、インフラやデプロイの複雑さを意識せずとも、安全かつ高速に価値を送り出せる仕組みが整っています。 大まかな機械学習基盤の構成は下記ページの「 Architecture 」セクションをご覧いただければと思います。 product-recruit.timee.co.jp データサイエンティストによる一気通貫の価値創出 データサイエンティストはこの基盤を使い倒し、ビジネス課題の発見から解決までを一気通貫で担います。 上流工程:課題設定、問題発見、ステークホルダーとの期待値調整。 開発・実装:分析、PoC(LLM活用含む)、本番環境へのエンジニアリング。 検証・改善:デプロイ後のABテスト、効果検証、それに基づく改善サイクルの実行。 整備されたプラットフォーム上で、Dev / Stg / Prod の各環境を使い分けながら高速にサイクルを回しています。このように、基盤を支えるスペシャリストと、事業価値を創出するスペシャリストが背中を預け合える関係性が、タイミーDSGの強みです。 5. チーム運営とシナジーを生む仕組み 仮想チームとして分かれて活動しつつも、グループ全体としての知見の共有や、職種を越えた連携を支えるための「場」や「仕組み」を大切にしています。 MLOpsとDSを繋ぐフィードバックループ MLOpsエンジニア主体のプラットフォームチームは、2週間のスプリントで動いています。スプリントの終わりには、基盤の利用者(主にDS)に向けた「ML基盤アップデート共有会」を実施しています。 ここでは新機能の周知だけでなく、利用者からの改善リクエストや困りごとを直接受け付けるスプリントレビューのような役割も果たしています。「作って終わり」ではなく、常に利用者の声を聞きながら基盤をブラッシュアップしていく。この対話の仕組みこそが、DSG内での高い開発体験を支えています。 AIも駆使して刺激を与え合う「学び」の習慣 私たちは技術的な研鑽も欠かしませんが、その「継続しやすさ」にもこだわっています。DSG内では定期的に勉強会を開催していますが、現在は隔週1時間で「毎回3,4名が10〜15分ずつ発表する」というスタイルをとっています。 意識しているポイントとしては、発表のハードルを極限まで下げていることです。発表時間を短くすることで、トピックの論点を端的にまとめやすくし、発表のハードルも下げています。発表資料の作成にはNotion AIやNotebookLMといったツールを積極的に活用し、準備の省力化を推奨しています。これにより「資料作りに追われてアウトプットが億劫になる」のを防ぎ、ハイスピードで知見を循環させることに挑戦しています。 また、グループ内に閉じず、他部署のエンジニアを交えた合同輪読会を行っているチームもあり、組織を越えて互いに高め合う文化が根付いています。 制度を活用した「チームビルディング」 仕事以外での繋がりも、心理的安全性を高める重要な要素です。タイミーにはチームビルディング費用の補助が出る全社的な福利厚生制度があり、これを活用して毎月、部署内外のメンバーと交流(飲み会や親睦会)を行っています。 部署内の結束を深める月もあれば、他部署のメンバーと交流する月もあり、こうした定期的な交流の場が「困った時にいつでも相談できる」関係性の土台になっています。 6. おわりに 今回は、タイミーのデータサイエンスグループ(DSG)がどのような組織構造で、どのような思想を持って日々開発・運用を行っているのかをご紹介しました。 私たちが「仮想チーム」や「Squad Lead(SL)」という運用に行き着いたのは、単に組織を管理するためではなく、「メンバー一人ひとりが認知負荷に振り回されず、本来の専門性を最大限に発揮して、プロダクトに価値を届けられる環境」を作りたかったからです。 組織の形は、プロダクトのフェーズや課題に合わせて柔軟に変わっていくべきものです。今回ご紹介した体制も現在の「最適解」ではありますが、今後さらに組織が拡大していく中で、私たちはまた新しい壁にぶつかり、形を変え続けていくはずです。そうした変化を楽しみながら、仕組みそのものをアップデートしていけることも、今のタイミーDSGの面白さだと感じています。 この記事を通じて、私たちの組織運営やチームの雰囲気が少しでも伝わっていれば幸いです。 We’re Hiring! タイミーではデータサイエンティスト・MLOps Engineerをはじめ、一緒に働くメンバーを募集しています! カジュアル面談 も行なっておりますので、興味のある方はぜひお気軽にお申し込みください! https://product-recruit.timee.co.jp/
はい、亀井です。 yykamei という名前でインターネットではやらせてもらっています。所属はタイミーです。 Regional Scrum Gathering Tokyo 2026(RSGT2026)に、ボランティアスタッフとして参加しました。 今年は会場が変わったこともあり、運営側としても新たな挑戦が多い年でした。今回は「運営としての学び」と、セッションや対話から得られた「実践知としての学び」という二つの視点から、今年のRSGTを振り返ります。 ボランティアスタッフとして見た「現場」と「適応」 今年の大きなトピックは、やはり会場が変わったことでした。これによって、長年蓄積されてきた「あの会場ならこう動けばいい」という特定の場所に依存したノウハウが使えなくなりました。 しかし、具体的な手順書がリセットされた状態でも、スタッフそれぞれが「このイベントにおいて自分は何をやるべきか」という本質を理解していたため、阿吽の呼吸でなんとかなったように思います。自己組織的なコミュニティーですね。終わった後にスタッフでこのRSGT2026について全員が一言を述べるのですが、皆さん、それぞれの視点からいろいろな学びやフィードバックを持ち込んでくださったり、「そもそも今回はどのような心持ちで望んでいたか」という話をしてくれたりして、カンファレンスのスタッフとしてどのような価値を出すべきかということについてハッとさせられました。 今回の私のスタンスは「無理にがんばらない」ということでしたが、終わってみるとそこそこの歩数を稼いでしまったので、目標達成はできなかったようです。しかし、それだけ人との会話を楽しめたのかなと思います。 「空調」と「導線」 会場の空調管理が難しかったです。結果として「寒い」という意見がマジョリティを占めてしまったように感じます。RSGTは例年1月の最も寒い時期に開催されるため、基本的には「高めの温度設定」をデフォルトにしておくのが正解だという明確な学びを得ました。これは来年への重要な引継ぎ事項かもしれないですね。とはいっても、空調管理は他のスタッフがやってくれていたので、まずは空調機器の操作方法を覚えるところからが来年のスタートになりそうです。 また、会場レイアウトについても気づきがありました。Hall AとHall Bは基本的には同じ作りのはずなのですが、机の配置の影響で、Hall Aは両サイドに廊下的スペース(通路)がなく、人の移動がしづらい状態になっていました。一方でHall Bは余裕があり、スムーズな回遊ができていました。来年はHall AもHall Bのような配置をするといいのだろうなと思っております。 壁を取り払う 今回の会場であるベルサール羽田空港は、部屋と部屋をつなげるなど、レイアウトに柔軟性があります。また、部屋の数も多いので、今回はスポンサーブースとして部屋を二つ借り、その間の壁をなくしてつなげていました。 これは大成功だったようでして、スポンサーの方からも「参加者が回遊できてよい」というポジティブなフィードバックがあったようです。 「情報保障」と能動的なキャッチアップ RSGTは昨年同様、今年も情報保障にかなり力を入れていました。しかし、ボランティアスタッフとして参加していながら、その具体的な仕組みや運用ノウハウについて、私自身が意外と知らないことに気づかされました。 運営マニュアルとして手取り足取り教えられるわけではないので、スタッフ自身が積極的に知ろうと動かないと、その裏側にある努力や仕組みを知ることができません。 これってオンボーディングのない会社に入社したときと同じですよね。来年は、この情報保障の領域についても、もっと能動的にキャッチアップしていこうと心に決めました。 セッションを見た感想 運営の合間に参加したセッションと、部屋付きとして参加したセッションについて書いてみます。 改めてスクラムについての学び ryuzeeさんのキーノートでの デイリースクラム Deep Dive のセッションに部屋付きとして入りました。デイリースクラムは単なる報告会ではなく、透明性を確保し、検査と適応を行うためのイベントです、と。「スプリントゴール達成が唯一の目的」であり、そのための検査である、といったことをおっしゃっていたように思います。特に印象的だったのが、「タイムボックスの延長を許すのは『割れ窓理論』と同じである」という指摘です。一度時間を守らなくなると、他の規律もなし崩し的に守らなくなるとのことでした。「PBI単位で、上から順番に確認する」という具体的なアドバイスや、スプリントゴールチェックインという手法は、すぐに現場で試せる知見でした。 また、Yohさんの よくわからないことが多い場合の計画づくりのコツ にも部屋付きで入りました。「わからないことはわからない」と認め、細かく計画しすぎず、「わからないことを見える化」するために頻繁に計画を見直す、といったことをおっしゃっていたような気がします。面白いのは、「わからないことリスト」的なものを作成しておく、という点ですかね。これは、Kent Beckが『Tidy First?』で言っていた「お楽しみリスト」みたいなものかもしれない、と勝手ながら思いました。リストに含めておく、という行為がいったん忘れることができるのでいいですよね。 とみたさん・田口さんの Sprint Reviewで、ビジネスと開発の「当たり前」を同期する 、こちらも部屋付きで聞かせていただきました。レビューが盛り上がらない根本原因は「学習の場になっていない」ことにあるという指摘には深く頷きました。ステークホルダーには「アジャイル」という用語を使わずに対話するという話があったのですが、すごくいい話だなと思いました。 複雑さと向き合う組織づくり 組織論の観点では、長沢さんの EBM実践のカタ —— 実践とゴールと計測を結びつけるアジャイルのありたい姿へ が印象に残っています。「開発作業ではなく実験をするべき」という言葉。そして、リーダーは戦略的ゴールを示し、実践者が戦術的ゴールを定めるという構造は、健全な自律組織の条件だと感じます。 森さんの 「私の要求最優先!あなた後回し」そんな対立を超えてビジネス、開発、顧客が本当に欲しかったものを全両立するプロダクト組織の作り方 での「循環構造型トレードオフ(AをやるとBがだめになり、BをやるとAがだめになる)」という話も、プロダクト開発のリアル!という感じでしたね。ビジネス、開発、顧客の間で揺れ動く中で、「長期的な有害」をマネジメントするという発想はなかったなーと思いました。今まで気にならなかったものが気になり始めたら、それは工夫が始まっている証拠だという言葉には勇気づけられました。 およべさんの AI時代のアジャイルチームを目指して - "スクラム"というコンフォートゾーンからの脱却- では、組織を「チームのような密度」で捉え、ロールを動的にしていくという、これからの組織のあり方が示唆されていました。振り返ってみると、これはDay3の漆原さんの クロージングキーノート につながっていたな、という気がします。 人、モチベーション、そして物語 Day2のいくおさんの 自己管理型チームの一員となるためのセルフマネジメント:モチベーション編 、こちらはたまたま私のフリーな時間が重なったので話を聞くことができました。「自己管理型チームと個人のセルフマネジメント 〜モチベーション編〜」というタイトルです。ERG理論(成長・関係・存在)とかABC理論(出来事・信念・結果)といった理論を紹介しつつ、ご自身の経験をもとにした発表で、「え、いくおさん、そんなことを思っていたんだ」という感じです。その中でも「自分はいつもメンバーに恵まれている」と言っていたのですが、シンプルにこれを言えるマネージャーってすごいな、と思いますよね。 ちんもさんの 田舎で20年スクラム(後編):一個人が企業で長期戦アジャイルに挑む意味 、こちらは部屋付きで入っていました。急遽、部屋付きを一人でやることになってバタバタしそうだったのですが、それでも内容は結構印象に残っています。私の印象では一言で言えばチェンジエージェントの話です。しかし、チェンジエージェントといってもそれを20年やっているわけですよ。言葉の重みが違いますよね。現場を変えようとする人々の背中を押すような素晴らしい内容でした。 最後に セッションだけでなく、廊下での雑談もRSGTの醍醐味です。たぶんインターネットで公開できないような話も聞けたと思います。 ボランティアスタッフの打ち上げ的な飲み会で、永瀬さんがおすすめしてくれたものをメモしたのを見返すと、「セサミストリート」「スンスン」と書いてありました。 会場変更という大きな変化の中で、ボランティアスタッフとして「適応」を実践できたこと。そして、セッションを通じてスクラムの「基本」と「本質」に立ち返れたこと。 今年のRSGTは、運営という立場だからこそ得られた「組織としての動き方」の学びと、コンテンツからの学びがリンクする、非常に濃密な時間でした。 ここで得た熱量と知見を、明日からの現場、そして来年のRSGTにつなげていきたいと思います。
はじめに こんにちは、タイミーでPlatform Engineerをしている近藤です。 タイミーでは、インフラ管理においてTerraformを積極的に活用しています。 当初はAWSリソースの管理が中心でしたが、事業や組織の拡大に伴い、管理対象は多岐にわたるようになりました。 現在では、以下のような様々な用途でTerraformリポジトリが運用されています。 AWSインフラ: メインとなるサービス基盤の構築・運用 GCPインフラ: BigQueryなどのデータ分析基盤や、特定のGoogle Cloudリソース管理 SaaSアカウント管理: GitHubやDatadogなどのユーザー・権限管理 その他: Elastic Cloudなどの専用リソース管理 このように、クラウドプロバイダーも用途も異なる複数のリポジトリが存在する状況において、私たちは「Terraformワークフローの共通化」に取り組みました。 共通化前の課題 リポジトリが増えるにつれて、開発・運用チームは次のような課題に直面していました。 ワークフローの実装と機能のバラつき リポジトリごとにCI/CDの設定がコピペと独自改変を繰り返して作られていたため、「あるリポジトリではLintが走るが、別のリポジトリでは走らない」「あるリポジトリではSlack通知が飛ぶが、別のリポジトリでは通知自体がない」といった不整合が起きていました。 メンテナンスコストの増大 新しいセキュリティチェックツールの導入や、Terraformのバージョンアップに伴うCI修正を行おうとすると、全てのリポジトリに対して個別に修正PRを送る必要がありました。 新規リポジトリ作成への心理的ハードル 「リポジトリを分けたほうが責務が明確になる」と分かっていても、「またあのCI設定をコピーしてメンテナンスするのか」という負担が頭をよぎり、既存のリポジトリに無理やりリソースを追加してしまうケースがありました。 結果として、ワークフローの維持管理が大変そうで、新しい用途での活用を躊躇してしまうという状態になっていました。 解決策:共通Terraformワークフロー基盤の開発 これらの課題を解決するために、社内のTerraformリポジトリで利用するためのCI/CDワークフローを共通化し、単一のプロダクトとして管理する共通Terraformワークフロー基盤を開発しました。 安全かつ自動化された配布の仕組み 共通化にあたっては、変更が全リポジトリに波及するリスクを考慮し、安全に開発・配布できる仕組みを構築しました。 サンドボックス用リポジトリでの開発 まず、Terraform用の実験リポジトリで機能追加や修正を行います。ここで実際にTerraformを動かし、動作を検証します。 共通ワークフロー基盤リポジトリへの自動PR サンドボックスでの検証が完了して main ブランチにマージされると、自動的に共通Terraformワークフロー基盤リポジトリに対してPull Requestが作成されます。 各リポジトリへの自動配布 共通Terraformワークフロー基盤側でPRをマージすると、その変更が対象となる全ての実利用リポジトリ(AWS用、GCP用、SaaS用など)に対して自動的に配布されます。 このサイクルにより、開発者は安心して共通基盤を改善でき、利用者も常に検証済みの最新ワークフローを享受できるようになりました。 同期ワークフローの実装 上記の配布フローは、GitHub Actions と GitHub App を使った同期ワークフローによって実現されています。具体的な実装を見ていきましょう。 同期ワークフローの全体像 name : Sync Workflow on : push : branches : [ main ] workflow_dispatch : jobs : # 配布先リポジトリ一覧を設定ファイルから読み込み load_repositories : outputs : repositories : ${{ steps.load.outputs.repositories }} steps : - uses : actions/checkout@v4 - id : load run : | REPOS=$(yq -o=json '.repositories' sync-repositories.yaml | jq -c) echo "repositories=$REPOS" >> "$GITHUB_OUTPUT" # 各リポジトリに対してマトリクス実行で同期 sync_workflow : needs : load_repositories strategy : matrix : include : ${{ fromJson(needs.load_repositories.outputs.repositories) }} steps : # GitHub Appで配布先リポジトリ用のトークンを発行 - uses : actions/create-github-app-token@v2 id : app-token with : app-id : ${{ vars.BOT_APP_ID }} private-key : ${{ secrets.BOT_APP_PRIVATE_KEY }} owner : ${{ matrix.owner }} repositories : ${{ matrix.name }} # ソースと配布先の両方をチェックアウト - uses : actions/checkout@v4 with : repository : ${{ matrix.owner }}/${{ matrix.name }} token : ${{ steps.app-token.outputs.token }} path : target-repo # sync-files.yaml に基づいてファイルをコピー - name : Copy workflow files run : .github/scripts/sync-copy-files.sh # 差分があればPRを作成 - name : Create PR if changed run : .github/scripts/sync-create-pr.sh env : GH_TOKEN : ${{ steps.app-token.outputs.token }} 配布先リポジトリの設定(sync-repositories.yaml) 配布先となるリポジトリは、設定ファイルで管理します。共通基盤リポジトリでは、実利用リポジトリすべてを配布先として定義しています。 # 共通基盤リポジトリの sync-repositories.yaml repositories : - owner : your-org name : repo-a # 利用リポジトリA - owner : your-org name : repo-b # 利用リポジトリB - owner : your-org name : repo-c # 利用リポジトリC # ... 他の利用リポジトリ 一方、サンドボックスリポジトリでは、共通基盤リポジトリのみを配布先として定義します。 # サンドボックスの sync-repositories.yaml repositories : - owner : your-org name : workflow-base # 共通基盤リポジトリのみ 同期対象ファイルの設定(sync-files.yaml) 同期するファイルと除外するファイルは、設定ファイルで明確に管理します。 # .github/config/tf/sync-files.yaml # 同期対象のファイル・ディレクトリ files : - .github/config/tf/ # 共通設定ファイル - .github/workflows/ # ワークフローファイル - .github/actions/tf_* # カスタムアクション # 除外対象(リポジトリ固有の設定) exclude : - .github/workflows/tf_sync_workflow.yml # 同期WF自体 - .github/config/tf/sync-files.yaml # 同期設定 - .github/config/tf/sync-repositories.yaml - .github/config/tf/.env.local # ローカル環境変数 - .github/config/tf/dirs.json # 対象ディレクトリ一覧 - .github/config/tf/filters.local.yaml # ローカルフィルタ - .github/config/tf/.tflint.hcl # tflint設定 - .github/config/tf/trivy.yaml # trivy設定 このように、共通化すべきファイルと、リポジトリ固有であるべきファイルを明確に分離することで、柔軟性を保ちながら一貫性を維持しています。 設定ファイルによる振る舞いの制御 共通ワークフローの振る舞いは、階層化された設定ファイルによって柔軟に制御できます。 設定ファイルの階層構造 .github/config/tf/ ├── .env # グローバル設定(共通) ├── .env.local # リポジトリ固有の設定 ├── dirs.json # 対象ディレクトリ一覧 ├── filters.yaml # グローバル変更検出フィルタ ├── filters.local.yaml # ローカル変更検出フィルタ ├── .tflint.hcl # tflint設定 └── trivy.yaml # trivy設定 envs/ ├── production/ │ └── .env # ディレクトリ固有の設定 └── staging/ └── .env グローバル設定(.env) 全リポジトリで共通の設定です。同期によって配布されます。主な設定項目は以下の通りです。 Terraform実行設定 : 並列数( TF_MAX_PARALLEL_JOBS )、CLI引数( TF_CLI_ARGS_plan )など Git設定 : コミット時のユーザー名・メールアドレス Slack通知設定 : ステータスごとの色・メッセージ・絵文字・アイコンを SLACK_STATUS_{STATUS}_{PROPERTY} 形式で定義 Slack通知の設定はデータとして定義し、ワークフロー側ではシェルの間接変数展開を使ってジョブのステータス(success / failure / cancelled / maintenance)に応じた値を動的に参照する設計にしています。 リポジトリ固有・ディレクトリ固有の設定 グローバル設定を上書きする設定は、以下の2箇所で定義できます。 .env.local : リポジトリ全体に適用される設定(同期の除外対象) envs/{env}/.env : 特定のディレクトリにのみ適用される設定 主な設定項目: TF_MAX_PARALLEL_JOBS : APIレート制限を考慮した並列数の上書き AWS_ROLE_TO_ASSUME / GCP_WORKLOAD_IDENTITY_PROVIDER : 認証設定 SLACK_CHANNEL_ID / SLACK_MENTION_NAME : 通知先チャンネルとメンション 対象ディレクトリ設定(dirs.json) terraform plan/apply の対象ディレクトリを定義します。 [ " envs/production ", " envs/staging ", " envs/development " ] 変更検出フィルタ(filters.yaml) 共通モジュールや設定ファイルの変更時に全ディレクトリを再実行するためのグローバルフィルタです。 # .github/config/tf/filters.yaml(共通) terraform_trigger : - modules/ - .github/config/tf/ - .github/actions/tf_*/** - .github/workflows/tf_* - .github/workflows/*tf** - .terraform-version # .github/config/tf/filters.local.yaml(リポジトリ固有) terraform_trigger : - shared/ # リポジトリ固有の共有モジュール 認証処理の共通化(tf_init アクション) 認証処理はComposite Actionとして共通化し、AWS OIDC / GCP Workload Identity Federation の両方に対応しています。 # .github/actions/tf_init/action.yml name : Terraform Init inputs : directory : required : true credentials : required : false runs : using : composite steps : # リポジトリ固有のパッチがあれば適用 - name : Check if tf_patch exists id : check-patch shell : bash run : | if [ -d ".github/actions/tf_patch" ] ; then echo "exists=true" >> "$GITHUB_OUTPUT" fi - name : Apply patches if : steps.check-patch.outputs.exists == 'true' uses : ./.github/actions/tf_patch with : directory : ${{ inputs.directory }} # Terraformバージョンのセットアップ - name : Setup Terraform uses : hashicorp/setup-terraform@v3 with : terraform_wrapper : false terraform_version : ${{ steps.var.outputs.terraform-version }} # 環境変数の読み込み(グローバル → ローカル → ディレクトリ固有) - name : Load environment variables shell : bash run : | for env_file in \ ".github/config/tf/.env" \ ".github/config/tf/.env.local" \ "${{ inputs.directory }}/.env" ; do if [ -f "$env_file" ] ; then envsubst < "$env_file" >> "$GITHUB_ENV" fi done # AWS OIDC認証(設定がある場合) - name : Configure AWS credentials if : env.AWS_ROLE_TO_ASSUME != '' uses : aws-actions/configure-aws-credentials@v4 with : aws-region : ${{ env.AWS_REGION }} role-to-assume : ${{ env.AWS_ROLE_TO_ASSUME }} # GCP Workload Identity認証(設定がある場合) - name : Authenticate to Google Cloud if : env.GCP_WORKLOAD_IDENTITY_PROVIDER != '' uses : google-github-actions/auth@v2 with : workload_identity_provider : ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }} service_account : ${{ env.GCP_SERVICE_ACCOUNT }} # Terraform init - name : Terraform init shell : bash run : | terraform -chdir=${{ inputs.directory }} init 導入成果 運用面での改善 共通基盤を1箇所修正するだけで、全リポジトリに改善が行き渡るようになりました。セキュリティスキャンの追加やツールのバージョンアップも、一括で適用可能です。 また、どのリポジトリを触っても、「PRを出せばPlanが走り、結果がコメントされる」「マージすればApplyされる」という同じ挙動が保証されるようになりました。これにより、エンジニアが新しいリポジトリを触る際の学習コストが下がりました。 技術的に実現できたこと 共通Terraformワークフロー基盤では、インフラ運用に必要な仕組みを次のような形でまとめて提供しています。 Terraform実行パイプラインの共通化: PRごとに terraform plan 、mainマージ時に terraform apply を自動実行し、複数環境をマトリクス実行しながら並列数を制御。 実行の安全性とレートリミット対策: ワークフローのコンカレンシーやキャンセルポリシーを設定し、不要な再実行を避けつつ、GitHub API やクラウドプロバイダAPIのレートリミットにかからないように実行を制御。 品質・セキュリティチェックの標準化: terraform fmt / validate / tflint / trivy に加え、各種Lintを一括で走らせ、結果をPRレビューとしてフィードバック。 ドリフト検出と自動PR: 定期的なPlanで実環境とのドリフトを検出し、差分があれば自動でPRを作成・管理。 PRレビュー体験の強化: Plan/Apply結果や診断結果に加え、AIベースのPRエージェントによる要約・レビューコメント生成でレビュー負荷を軽減。 認証と権限管理の一貫性: AWS OIDC / GCP Workload Identity Federation とアクセスキー認証の両方に対応し、 plan / apply ごとに適切な認証情報を選択できるよう統一。 設計時に意識したこと Terraformワークフローを「単なるCI設定」ではなく、継続的に拡張・改善していける共通基盤にするために、次のような設計方針と実装上の工夫を取り入れています。 1つのソースから複数リポジトリへ安全に配布できること 共通ワークフローの更新がそのまま全リポジトリに波及するため、必ずサンドボックスで検証してから共通基盤に取り込む二段階フローにしています。その上で、GitHub App を使ったトークン発行と同期専用ワークフローにより、「人手でコピペせずに、レビュー済みの変更だけを各リポジトリへ配布する」という流れを自動化しました。 配布方法としては、reusable workflow を使って直接呼び出す案も検討しました。しかし、ユースケースが社内限定であること、配布時の差分をPRとして確認できたほうがレビューしやすいこと、呼び出し元ワークフロー側の設定も含めて将来的に変更する可能性があることから、GitHub App で各リポジトリにPRを作成する方式を選びました。 設定ファイルで振る舞いを切り替えられること Terraform の実行対象やトリガーとなるファイルパターンなどは、ワークフロー内にベタ書きせず、グローバル設定とリポジトリごとの設定ファイルをマージして解決する構造にしています。これにより、「共通のベースラインは維持しつつ、プロジェクトごとに監視対象や実行頻度だけ変える」といった調整をコード変更なしで行えるようにしました。 認証・権限まわりをワークフロー側で肩代わりすること AWS OIDC / GCP Workload Identity Federation によるキーレス認証と、従来のアクセスキー認証の両方をラップし、 plan / apply などのアクションごとに適切な権限を選び分けられるようにしています。個々のリポジトリでは「どのロール/サービスアカウントを使うか」だけを意識すればよく、認証フローそのものの実装は共通基盤に閉じ込めています。 共通ワークフローと各リポジトリの実装を柔軟につなげられること ワークフローの中で、Terraformファイルに対して小さなパッチを当てる専用アクション tf_patch を用意しています。 例えば、各リポジトリの providers.tf には、過去の経緯からローカル開発用のAWS認証設定(プロファイル指定やロール引き受け設定)が含まれています。CI環境ではOIDC認証を使用するためこれらの設定は不要であり、むしろ干渉してしまいます。 tf_patch アクションは terraform init の前にこれらの行を自動的に削除し、どのリポジトリでも同じOIDC認証の前提で共通ワークフローを実行できるようにしています。 このように、共通ワークフローと各リポジトリ固有の実装の間をつなぐアダプタとして機能させることで、既存コードへの変更は最小限に抑えたまま共通化を進められるようにしています。 現状の課題 共通化によって多くのメリットを得られましたが、運用を続ける中でいくつかの改善点も見えてきました。 同期除外対象の管理 現在、同期対象から除外するファイルは sync-files.yaml にファイル名を個別で定義しています。しかし、除外対象が増えるにつれてこのリストの管理が煩雑になってきました。ディレクトリ構造を整理し、「共通化するもの」と「リポジトリ固有のもの」を明確にディレクトリで分離することで、除外設定をシンプルにできる余地があります。 ファイルの差分管理 同期ワークフローは「ソースリポジトリにあるファイルを配布先にコピーする」という動作をしますが、ソースリポジトリでファイルを削除・移動した場合に、配布先の古いファイルを自動で削除するような仕組みにはなっていません。そのため、ファイル構成を変更した際には、配布先リポジトリに不要なファイルが残ってしまうことがあります。この問題も、上述のディレクトリ構造の見直しによって対応できると考えています。現状では、AIコーディングエージェントの Devin を活用して、不要になったファイルのお掃除PRを作成してもらうなど、人力での対応を行っています。 おわりに 共通Terraformワークフロー基盤によって、インフラや各種 SaaS アカウント管理のワークフローは一貫性を持って運用できるようになり、個々のリポジトリごとに CI を実装・メンテナンスする負担は大きく減りました。そのうえで、開発者は「リポジトリごとの Terraform の中身」に集中しやすくなり、ワークフロー自体は共通基盤として継続的に改善していける状態になっています。 また、この記事で紹介したのと同じような考え方で、アプリケーションのモノレポに対するデプロイワークフローも共通化しています。こちらについても、機会があれば別のエントリとして詳しく紹介できればと思います。
こんにちは、タイミーでバックエンドのテックリードをしている新谷( @euglena1215 )です。 Rails アプリケーションの開発をしていると、fat になってしまった Sidekiq worker や、ドメインロジックらしき実装が書かれている Serializer に遭遇したことがあるのではないでしょうか。 この記事では、MVC アーキテクチャを一段階抽象化して捉えることで、Rails のさまざまなレイヤーに対して一貫したプラクティスを適用する考え方を紹介します。ある程度 Rails を触ったことのあるエンジニアが感覚的に理解している概念を、改めて言語化したものです。 MVC の役割を改めて整理する まず、MVC の各レイヤーの役割を整理しておきましょう。 Model : ビジネスロジック、データ、ルールそのものを表現し、データの保存・取得を行う View : データをユーザーに返却するための適切な形で変換する Controller : 外部からの入力を受け取り、Model を操作しデータの取得・更新を行い、View で変換したデータを外部へ出力する ここで重要なのは、MVC を「Model, View, Controller という三つのディレクトリ」として捉えるのではなく、「三つの責務」として抽象的に捉えることです。 「実質〇〇」という視点 一番分かりやすい例は、JSON の組み立てを行う Serializer です。Serializer は app/serializers ディレクトリに配置されますが、その責務は「データを適切な形に変換してユーザーに返却する」ことであり、これは 実質的に View です。 この「実質〇〇」という視点でタイミーの Rails アプリケーションの各レイヤーを分類してみましょう。 実質 Model ディレクトリ 説明 app/models Model そのもの app/policies 特に認可にフォーカスしたもの app/validators 特にバリデーションにフォーカスしたもの Policy や Validator は、ビジネスルールを表現するという点で、 Model の責務を担っています。 実質 Controller ディレクトリ 説明 app/controllers Web API リクエストにおけるエントリポイント app/workers 非同期処理におけるエントリポイント app/mailers メール送信におけるエントリポイント lib/tasks rake タスクにおけるエントリポイント app/services エントリポイントから括り出された処理 app/forms エントリポイントから括り出された処理 ポイントは、Service *1 や Form *2 がエントリポイントではないものの、Controller に実装されるべき処理を括り出したものであるという点です。そのため、実質的には Controller と捉えるのが妥当です。 実質 View ディレクトリ 説明 app/views HTML やメール文面の組み立て app/serializers JSON の組み立て Serializer を View と捉えることで、View に関するプラクティスを Serializer にも適用できるようになります。 この視点のメリット 「〇〇は実質的に Model / View / Controller である」という感覚を持つことで、MVC の一般的なプラクティスを MVC 以外のレイヤーにも適用できます。 例えば、以下のようなセルフチェックが可能になります。 一般的な MVC のプラクティス チェックリスト 実質 Controller は十分に薄く、ドメインロジックや表示用ロジックが混ざっていないか? ドメインロジックは実質 Model に寄せているか? 表示のためのデータ加工は実質 View に寄せているか? 実質 Model は実質 Controller に依存していないか? 実質 Model は実質 View に依存していないか? 具体例 例えば、「Service クラスが肥大化している」という問題があったとします。 Service は実質 Controller なので、「Controller が肥大化している」と言い換えられます。Controller が肥大化する原因は、ドメインロジックや表示用ロジックが混入していることが多いです。 したがって、解決策は以下のようになります。 ドメインロジック → Model(または Policy, Validator)に移動 表示用ロジック → View(または Serializer)に移動 このように、MVC のプラクティスを適用することで、自然と適切な設計に導かれます。 まとめ MVC は「三つのディレクトリ」ではなく「三つの責務」として捉える Rails の各レイヤーを「実質 Model / View / Controller」で分類することで、一般的な MVC プラクティスを適用できる Service は実質 Controller、Serializer は実質 View、Policy は実質 Model この視点を持つことで、一貫性のあるクラス設計が可能になる 日々のコードレビューや設計判断の際に、「これは実質どのレイヤーか?」と問いかけてみてください。 *1 : タイミーでは、Service クラスをController や Sidekiq worker から呼ぶものと位置付け、Model からは呼び出されないようなルールにしています。詳細は https://tech.timee.co.jp/entry/2024/01/29/170000 をご覧ください。 *2 : タイミーでは、Form クラスにおける明確なルールはないものの、特定のエンドポイントにおける処理を括り出したものという位置付けの使い方をしていることが多いため、こういった整理をしています。
はじめに この記事は Timee Product Advent Calendar 2025 の25日目の記事です。 MLOpsエンジニアの tomoppi です。データエンジニアリング部 データサイエンスグループ(以下DSG)に所属し、ML/LLM基盤の構築・改善に取り組んでいます。 2024年10月にタイミーへジョインし、気がつけば1年あまりが経ちました。2025年はLLM/LLMOpsに奔走した1年で、PoCを実施した施策の本番導入や、LLMの可観測性・プロンプトマネジメントに取り組み、走りながら考え、考えながら走る日々でした。 そんな中で、ふと思うようになりました。「2026年、タイミーのLLM基盤はどうあるべきか?」 本記事は、その問いに対する私なりの答え——というより、 夢と妄想 です。この1年で見えてきた課題と、それを乗り越えるための構想を、できるだけ具体的に描いてみます。 2025年の振り返り 個人的な振り返り まずは、私がこの1年取り組んできたことについて、簡単に触れさせていただきたいと思います。 年初時点では、社内でいくつかのLLM関連PoCが動いているフェーズで、まだMLOpsとしてのLLMへの関わりは薄い状態でした。一方で、DSG内ではLLMへの注目が高まり、キャッチアップを目的としたLLM勉強会が始まりました(この勉強会は現在も継続しています)。 その流れで、2月に「LLMOpsとは何か」をテーマに勉強会を開催し、評価手法やプロンプト管理、モニタリングなど、従来のMLOpsとは異なる論点をDSGで共有しました。 3月に入ると、PoC段階だったLLM機能を本番導入する動きが増え、「どう設計すれば安全かつ現実的に運用できるか」を一から詰めていくことになりました。この過程で得られた知見・経験は、 LLMアプリケーション向けProduction Readiness Checklist 執筆の動機になりました。 LLMOpsツール導入の検討も並行して行い、10月頃、LLMOps基盤としてDatadog LLM Observabilityの本格運用を開始しました。 「なんとなく動いている」から「ちゃんと運用できている」状態へ、徐々に進めている感覚がありました。 また、Datadog社からのお声がけで、 Datadog LLM Observabilityを題材とした登壇 の機会もいただき、実りの多い1年となりました。 LLMOpsとTeam Topologies MLOpsチームは、Team Topologiesで言うCollaboration Modeで、データサイエンティストチーム(as Complicated Subsystem Team)やプロダクトエンジニア(as Stream-aligned team)と密に連携してきました。 AI施策ごとにMLOpsエンジニアがプロジェクトに参画し、初期の壁打ちからアーキテクチャ設計、実装まで伴走してきました。この進め方は、ナレッジが少なく不確実性が高い状況で、知見を素早く蓄積し、開発のアジリティを確保するうえで非常に有効でした。 一方で、この体制は長期的には持続しないことも見えてきました。 「AIを使いたい」という熱量が全社的に高まるほど、インフラやガバナンス整備待ちの「行列」が生まれ、結果としてビジネスのスピードを落としてしまいます。 同時に、LLM利用が拡大するにつれ、プロンプトインジェクションをはじめとするセキュリティ対策やコスト最適化、利用モデルの透明化といったガバナンスが、より重要になってくると考えています。 その規模になると、個別対応をずっと続けることは現実的ではありません。 2025年末の課題 整理すると、現状の課題は次の3つです。 Agility(俊敏性の欠如) 検証環境構築のリードタイムが長く、高速な検証を阻害する状況になっています。 LLM開発では「評価データの準備」「プロンプト変更→評価→改善の反復」「モデルの切り替え」「コスト見積(トークン/レイテンシ/単価)」など、環境以外にも反復のボトルネックが多く、施策の立ち上げや改善の速度を落としてしまいます。 Scalability(拡張性の限界) LLM施策の需要増に対しMLOpsチームの供給体制が追いつかず、組織全体でのLLM施策がスケールしません。 ボトルネックが「技術(インフラ)」ではなく「人(MLOpsチーム)」になっていることは、構造的な制約であり、このままではスケール上の限界に直面します。 Governance(統制の分散/部分最適) 施策ごとに個別最適な判断・実装が積み上がり、環境や運用がサイロ化します。その結果、コスト配賦や利用実態の把握、セキュリティ対策、監査対応などがチームごとにバラバラになり、全社としての管理が難しくなっています。 2026年に目指したいタイミーのLLMOps Collaboration ModeからX-as-a-Serviceへ 前述したような課題を乗り越え、LLM活用を全社的にスケールさせるために、2026年はMLOpsチームが個別のプロジェクトに入り込むのではなく、「セルフサービスで使えるプラットフォーム」を提供することを目指しています。Team Topologiesで言う X-as-a-Service への移行です。 プロダクトチームが自律的にLLM機能を開発・運用できる基盤——これを Unified LLM Platform と呼ぶことにします。 「The Art of AI Maturity」とPlatform Engineering Maturity Modelへの接続 とはいえ、「本当にUnified LLM Platformとしての共通基盤は必要なのか?」という問いには答えておきたいところです。戦略的なフレームワークを参照しながら、その必要性を整理してみます。 そのフレームワークとして、 The Art of AI Maturity と Platform Engineering Maturity Model を参照していきます。 The Art of AI Maturityから見た Unified LLM Platformの必要性 The Art of AI Maturityは、Accentureが提唱するAI成熟度を評価するフレームワークで、17のKey Capabilitiesを定義しています。タイミーでは、このフレームワークを全社的に参照しています。 Unified LLM Platformの構築は、以下の8つのKey Capabilitiesに対する実行施策となります。 Key Capability Unified LLM Platformとの関係 #3. Proactive vs Reactive 先行投資によるプラットフォーム整備により、市場ニーズ発生後の追随ではなく、先回りでAIオポチュニティを創出 #4. Readily Available AI/ML Tools セルフサービス化されたLLM開発環境により、開発者が環境準備で待たされない状態を実現 #5. Readily Available Developer Networks 統一インターフェースやオープンなアーキテクチャにより、OSSコミュニティとの連携を促進 #6. Build vs Buy 競争優位を生むコア領域(LLM features)は内製、基盤部分でのUtilityはSaaS/PaaS/OSSを活用するポートフォリオ戦略を実現 #7. Platform & Technology 推論基盤(マルチプロバイダー対応、統一API)、ガードレール(DLP/ポリシー/ツール実行制御)、可観測性(トレーシング/メトリクス)、評価、コスト管理をプラットフォームとして標準化し、安全で再現性のある運用を実現 #13. Innovation Culture Embedded 探索の自由度を高めるプラットフォームにより、日常業務に実験・学習サイクルを組み込む文化を促進 #16. Responsible AI 技術的統制(PIIマスキング、監査ログなど)により、倫理・法規制に適合したRAIプロセスを実現 #17. Responsible AI — Change RAI体制の継続的強化を、プラットフォームレベルで自動化・標準化 Platform Engineering Maturity Modelから見た Unified LLM Platformの必要性 次に、Platform Engineering Maturity Modelを参照してみます。 Platform Engineering Maturity Modelとは、プラットフォームエンジニアリングを5つの観点(Adoption、Interfaces、Investment、Measurement、Operations)で評価するフレームワークです。 これまでプロジェクト単位でのスピードを優先してきたため、プラットフォームとしての成熟度は「レベル1(暫定的)」であり、部分的に「レベル2(戦略的)」という評価になります。 0→1の立ち上げ期においては、この「都度対応」が最も機動力を発揮しました。しかし、1→10、10→100へとスケールさせるこれからのフェーズにおいては、かつての最適解(レベル1)が最大のアンチパターンになりつつあります。「レベル1だからダメ」なのではなく、「レベル1のやり方で戦えるフェーズは終わった」と認識しています。 2025年の振り返りで述べた課題や体制を踏まえると、現在のタイミーのLLMOpsは、各観点で以下のような状態にあると考えられます: 観点 現状 Investment(投資) プロジェクトごとの個別対応が基本で、MLOpsチームの部分的なタスクとして遂行している状況です。 Adoption(採用) LLMが必要なチームが散在する社内ナレッジをもとに施策を検討し、MLOpsチームも都度個別対応を行っていたため、標準的なプラクティスやポリシーが不十分な状態です。 Interfaces(インターフェース) これまではMLOpsエンジニアが伴走し、プロジェクトごとに最適な構成を提供してきました。部分的に共通化できている箇所もありますが、セルフサービスで利用できる統一インターフェースは整っていない状況です。 Measurement(測定) LLM基盤として指標は定義できておらず、収集もできていない状況です。 Operations(運用) これまではプロジェクトごとのリクエストに応じた柔軟な対応で素早く価値を届けてきましたが、モデルの利用状況や、更新対応は個別管理になっており、LLMライフサイクルを中央集権的に管理できていない状態です。 2026年に目指すのは、各観点でレベル3(スケーラブル)への移行です。これはチャレンジングな目標ですが、Unified LLM Platformの構築により実現を目指します: 観点 実現内容 Investment MLOpsチームがPlatform Teamとして明確な役割を持ち、LLM Platformのロードマップに基づく計画的な投資を実行していきます。 Adoption 「Golden Paths over Cages」 の方針により、「強制」ではなく「便利だから使われる」プラットフォームを実現。ドキュメント整備とオンボーディング(利用開始までの手順・ガイド)を含めたSelf-service化を推進し、プロダクトチームが自律的にLLM機能を開発・運用できる状態を目指します。 Interfaces 統一されたエンドポイントとOpenAI互換の単一API仕様を提供。認証・認可はインフラ層で透過的に実行され、開発者は意識不要。Observability by Defaultにより、追加実装なしで全リクエストのトレース・レイテンシ・コストを可視化し、セルフサービスで利用できるようにします。 Measurement LLM基盤のSuccess Metrics(標準指標)を定義し、必要な計装(テレメトリ/ログ/利用データ)を組み込みます。定期レビューにより、利用状況と改善効果を可視化し、意思決定と改善サイクルを回せる状態にします。 Operations どのサービスがどのモデルを利用しているのかを中央集権で管理し、モデルの非推奨対応や新規モデルのロールアウト統制を取れる状態にします。加えて、Migration手順、責任分界(責任共有モデル)、ロールバック戦略を標準プロセスとして整備します。 実現に向けたエンジニアリング ここからは、どのようにUnified LLM Platformを実現するのか、エンジニアリング観点で整理していきます。 「探索の自由度」・「運用時の信頼性」・「技術的統制」 プラットフォームを設計するにあたり、特に重視したい要求を3つに整理しました。 1. 探索の自由度(Freedom of Exploration) 「データサイエンティストやプロダクトエンジニアが、面倒な環境構築なしに、アイデアを即座に試せる環境」 を実現したいです。 LLM開発は「試行錯誤」がすべてです。エンジニアだけでなく、PMやビジネスサイドのメンバーもプロンプトを直接触れられることが、開発速度に直結します。 この要求を満たすため、以下の要素が重要です。 モデルの切り替え(Model Agnostic) 「Geminiで試したけど、AnthropicやBedrockだとどうなる?」をコード変更なしで、設定の切り替えだけで素早く試せること。 統一インターフェース プロバイダーごとに異なるAPI仕様(OpenAI / Azure / Bedrock / Vertex AIなど)を意識せず、統一されたSDK/APIで呼び出せること。 プロンプトのバージョン管理とプレイグラウンド Gitのように「v1.2のプロンプト」と「v1.3のプロンプト」をGUI上で比較実行できる環境。エンジニアに依頼せずとも、画面上でパラメータを調整して挙動を確認できること。 評価駆動開発(Eval-driven Development)のための環境 オフライン評価における実験管理やLLM-as-a-judgeなどを、Day1から行えること。 Open-weight Modelsの活用 必要なユースケースでは、GKE上のvLLMなどでOpen-weight Modelsを扱える選択肢を残すこと。 2. 運用時の信頼性(Operational Reliability) 「確率的なLLMを、確定的なエンタープライズシステムとして振る舞わせるための安定化機構」 が必要です。 PoCでは許されても、本番環境では「APIが落ちていました」「遅すぎます」は許されません。 この要求を満たすため、以下の要素が重要と考えています。 リトライとフォールバック(Fallbacks) プロバイダー障害時に別経路へ切り替えたり、高性能モデルがタイムアウトしたら高速なモデルで再試行したりする冗長化構成。 ただし、 フォールバックは「評価で許容できる」と確認できた組み合わせに限定 。(挙動差分が大きいと品質事故につながるため)。 スマートキャッシング(Caching) 同一リクエストにはキャッシュから応答し、レイテンシ短縮とコスト削減を両立。将来的にSemantic Cacheも検討。 レート制限と公平性 一部のヘビーユーザーがトークンを使いすぎて他のサービスに影響を与えないよう制御できること。 オブザーバビリティ 開発者がモニタリング環境の構築を意識せず、モデルの性能やリソース使用状況を確認できること。 3. 技術的統制(Technical Governance) 「組織としてリスクをコントロールし、野良AIや青天井のコストを防ぐためのガードレール」 を整備したいです。 この要求を満たすため、以下の要素が重要と考えています。 PII/機密情報のマスキング (Redaction) クレジットカード番号、メールアドレスなどがプロンプトに含まれていたら、LLMに送信する前に自動でマスキングする機能。 プロンプトインジェクション対策(Prompt Injection Mitigation) 入力/出力のフィルタリング(疑わしい指示の検知・遮断、システムプロンプトや機密情報の漏洩防止など)と、コンテンツポリシー(許可/禁止の基準)をプラットフォーム側で標準化する。 Tool Use(外部API呼び出し、DB参照、チケット発行など)を行う場合は、ツールのAllowlist化・引数検証・権限境界の設計などにより「実行制御」を行い、必要に応じてサンドボックス(隔離環境)で安全に実行する。 認証方式の統一化 全てのLLMリクエストをLLM Gatewayを通すことで、認証方式を統一化し、プロジェクト固有で認証部分を行う必要性をなくす。 コストの予算管理 (Cost Budgeting) 「プロジェクトAは月額◯◯円まで」といったキャップを設定し、超過しそうになったらアラートを出す仕組み。 監査ログ (Audit Logs) 「誰が」「いつ」「どんなプロンプトを」「どのモデルに」投げたか追跡可能にすること。 ここは強い統制になる一方、 ログの取り扱い(PIIの扱い、保持期間、閲覧権限、暗号化、マスキング後のみ保存など) も同時に設計対象。 プラットフォームの構成イメージ これらの要件を同時に満たすために、 AI Gateway(LLM Gateway) というアーキテクチャパターンを中心に据えることを検討しています。 イメージ図 アプリケーションとLLMプロバイダーの間に「ゲートウェイ」を挟むことで、開発者は自由にAPIを呼び出せます。一方で、裏側では自動的にログが取られ、セキュリティチェックが走り(統制)、キャッシュやリトライが効く(信頼性)という構成です。 設計原則 プラットフォームを構築・運用していく上で、以下の原則を大事にしたいと考えています。これらは Platform Engineering 、 セキュリティ 、 SRE / Observability 、 LLMOps の各分野から学んだものです。 原則 概要 Platform as a Product プラットフォームを「社内向けプロダクト」として捉え、利用者(プロダクトチーム)の体験を最優先に設計する。「インフラを提供する人」ではなく「開発者という顧客にプロダクトを届ける人」としてのマインドセットを持つ TVP(Thinnest Viable Platform) 初期スコープは「ガバナンスと可観測性」を解決する純粋なLLM APIプロキシに絞る。RAGやTool Useは後から。まずは「安全で、誰が使ったか、いくらかかったかがわかるAPI」を全社に民主化する Golden Path の提供 「推奨される使い方」を明確にし、その道を歩めば自然とベストプラクティスに沿える状態を作る。自由度は残しつつも、迷わないための道標を用意する Secure by Default LLMはプロンプトインジェクションやPII流出など従来とは異なるリスクがあるため、ガードレールをデフォルトで有効にした状態を標準とする。「セキュリティを意識しなくても安全」な状態を作る Observable by Default LLMは確率的に動作するため、入出力の追跡なしには改善のポイントが見えない。特別な設定なしで自動的にトレーシングとメトリクス収集が行われる状態を目指す Eval Driven(評価駆動) LLM開発ではリグレッションが頻繁に発生するため、「感覚」ではなく「評価」で改善を確認する。評価データセットの整備、CI/CDへの評価組み込み、LLM-as-a-Judgeによる自動スコアリングを開発フローに組み込む アーキテクチャ設計 現在、初期検証で構築しているアーキテクチャは下図のようになっています。 技術選定 AI Gateway まずはAI Gateway(LLM Proxy)の技術選定から着手しました。ここで満たしたい要件は、ざっくり言うと次のとおりです。 マルチプロバイダー対応 : Vertex AI / AWS Bedrock / GKE上のvLLM(セルフホスト)を同じ入口で扱えること 認証 : LLMプロバイダー側へのキーレス認証(OIDCなど)と、クライアント向けのVirtual API Key トラフィック制御と信頼性 : リクエスト数・トークン数ベースのレート制限、フォールバック、ストリーミング 統一インターフェース : OpenAI互換APIなどのスキーマ正規化、Embeddingsのサポート オブザーバビリティとコスト : OpenTelemetry連携、コスト追跡(チーム/キー単位の配賦)、(将来的な)セマンティックキャッシュ ガードレール : PII/DLPのマスキング(Redaction)を含む入力/出力のフィルタリングに加え、プロンプトインジェクション対策(ポリシー、検知/遮断、必要に応じたTool Useの実行制御) 10個強のツール( LiteLLM Proxy / Envoy AI Gateway / APISIX / Kong / Portkey.ai など)を調査した結果、現時点では LiteLLM Proxy が要件を最も素直に満たせそう、という結論になりました。 一方で、 Envoy AI Gateway もKubernetesネイティブで魅力的です。将来的に本格的な本番運用(GitOps前提の運用、より厳格なトラフィック制御、低レイテンシ)に寄せるなら有力候補です。しかし現段階では、初速を優先して LiteLLM +(認証を担う)Envoy Sidecar の構成から始めるのが現実的だと感じています。 LLM Observability Tool 現在利用しているDatadog LLM Observabilityは、プラットフォームでも引き続き中核の可観測性基盤として活用する想定です。AI Gateway 経由の呼び出しを起点に、レイテンシやエラー、トークン使用量などを一貫して可視化し、運用改善や評価(Eval Driven)に繋げます。 Envoy Sidecar vs Service Mesh Cloud Runのマルチコンテナ機能で、Envoy → Backend にする必要があるかどうかについては、代替案としてService Mesh(Istio・Cloud Service Mesh)が考えられます。 しかし、現状Service Mesh構成ではなく、この取り組みのために0からService Meshを構築することは、TVPの考え方に反します。そのため、Envoy Sidecarを採用することにしました。 AWS → GCPのキーレス認証 クロスクラウド連携で悩ましいのが、 AWS → GCP の認証 です。従来の Workload Identity Federation だと、GCP側のSTSを呼び出してアクセストークンを取得する必要があり、実装・運用の負担が大きくなりがちです。 そこで最近登場した、 AWS IAM Outbound Identity Federation を使って、 AWS STSが発行するJWTを、Cloud Run前段のEnvoyで直接検証する 方式を採用することにしました。 おわりに ここまで読んでいただきありがとうございます。 この構想には多くの不確実性があり、自由と統制のトレードオフとも向き合い続けることになると思います。「夢妄想」と銘打ったとおり、すべてが計画どおりに進む保証はありません。 それでも、「安全に、再現性を持ってLLMを活用できる状態をつくる」という軸だけはブレずに、2026年はタイミーのLLM基盤を前に進めていきたいと思います。 来年のアドベントカレンダーで、「あの夢妄想、現実になりました」と報告できることを目指して。 タイミーのMLOps・LLMOpsって面白くなりそうと思ってもらえた方はぜひ、お話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
こんにちは、タイミーのデータサイエンスグループでマネージャーをしている菊地です。 本記事では、タイミーのデータサイエンス組織が直面した「認知負荷」や「優先順位」の課題に対し、チームトポロジーの考え方を取り入れて、どのように体制を見直したかを紹介します。 具体的には、データサイエンティストをストリームアラインドチームから「コンプリケイティッド・サブシステムチーム」へと再配置した背景と、その後のチーム間連携を円滑にするための「プロトコル」の設計・運用についてお話しします。 はじめに タイミーの開発組織ではチームトポロジーに基づいた組織運営を行っており、ストリームアラインドチーム、プラットフォームチーム、イネイブリングチーム、コンプリケイティッド・サブシステムチームといったチームタイプに分かれて、日々の開発業務を行っています。 チームトポロジー 価値あるソフトウェアをすばやく届ける適応型組織設計 tech.timee.co.jp データサイエンスを用いた機能開発の初期フェーズでは、その立ち上げを軌道に乗せるために、データサイエンティストがストリームアラインドチームに所属し、プロダクト開発と並走する体制をとっていました。データサイエンティストがドメイン知識を深く理解し、ビジネス課題に対して即応性の高い分析やモデル構築を行う必要があったからです。 しかし、事業が急成長し、プロダクトが大規模化・複雑化するとともに、サブシステムとして運用しうるものが一定程度できてくるにつれて、「ストリームアラインドチームにデータサイエンティストが同居する」体制の限界が見え始めてきました。 そこで、 高度な専門性が求められる特定の領域 (審査システムや推薦システムなど)において、データサイエンティストをストリームアラインドチームから切り出し、コンプリケイティッド・サブシステムチームとして再編成する組織リデザインを行いました。 以下では、その背景にあった具体的な課題と解決策、そして運用で定着しつつある具体的な連携プロトコルについて紹介します。 課題:ストリームアラインドチームにおけるデータサイエンティストの認知負荷と専門性のコンフリクト 以前まで特定のプロダクト領域では、データサイエンティストがストリームアラインドチームの一員として活動していました。この体制には「ドメイン知識の獲得」や「デリバリーのスピード」というメリットがあった一方で、運用を続ける中で以下のような課題が顕在化してきました。 1. 認知負荷の高まり ストリームアラインドチームの取り組みは、ユーザーへの価値提供に集中し、高速にイテレーションを回すことが求められます。一方、高度なML/LLMシステムの開発・運用には、論文調査や実験設計、長期的な精度改善といった、通常の開発サイクルとは異なる時間軸と専門知識が必要です。 ストリームアラインドチームにおける日々のユーザーへの価値提供と高度なMLモデルの研究開発を、同時に同一チーム内で担うことは、脳のスイッチングコストが非常に高く、認知負荷の限界を超えつつありました。結果として、「機能は作れるが、モデルの精度改善やアーキテクチャの刷新に手が回らない」という状況が生まれ始めていました。 2. 優先順位の競合 ストリームアラインドチームは、その時々のプロダクトゴールに向かってバックログの優先順位を決定します。一方で、ML/LLMシステムには「一度作って終わり」ではなく、データ傾向の変化への追随や継続的な精度モニタリングといった恒常的な改善が不可欠です。しかし、こうしたタスクは直近のゴールには直接結びつかないことが多く、結果として構造的に優先順位を上げにくいという課題がありました。 例えば、MLモデルの定期的な再学習パイプラインの整備や、将来の施策に向けた技術検証(PoC)、論文調査などは、短期的にはユーザー価値に直結しにくいため、スプリントの中で後回しにされがちでした。さらには、正式なタスクとしてバックログに載せることを諦め、メンバーが個人的に時間を捻出して整備を行うといった「隠れた稼働」が発生してしまうこともありました。これにより、データサイエンティストの活動が見えにくくなったり、キャリア成長の機会が損なわれたり、技術的負債が蓄積するといった懸念がありました。 解決策:チームトポロジーに基づくコンプリケイティッド・サブシステムチームの組成 これらの課題を解決するため、チームトポロジーの概念におけるコンプリケイティッド・サブシステムチームとして、対象領域ごとに専門チームを新設しました。 コンプリケイティッド・サブシステムチームの役割は、「高度な専門知識を必要とする複雑なサブシステムの管理に責任を持ち、その複雑さを他のチームから隠蔽すること」です。 これにより、データサイエンティストはコンプリケイティッド・サブシステムチームに所属し、複雑なサブシステムの開発・運用に集中できるようになります。同時に、ストリームアラインドチームは「中身の複雑なロジック」を意識することなく、提供されたAPIを利用するだけで高度な機能をユーザーに届けることができるようになります。 Before flowchart TB subgraph SAT1 ["🔹 Stream-aligned Team"] direction TB DS1("📊 Data Scientist"):::ds Others1("👥 Other Members<br>(PdM, Designer, Eng, Scrum Master, etc.)"):::others end %% Styles classDef ds fill:#fff9c4,stroke:#fbc02d,color:black,stroke-width:2px,rx:5,ry:5 classDef others fill:#ffffff,stroke:#bdbdbd,color:black,stroke-width:1px,rx:5,ry:5 style SAT1 fill:#f8f9fa,stroke:#dee2e6,stroke-width:2px,rx:10,ry:10 After flowchart TB subgraph SAT2 ["🔹 Stream-aligned Team"] direction TB Members2("👥 Team Members<br>(PdM, Designer, Eng, Scrum Master, etc.)"):::others end subgraph CSub ["✨ Complicated Subsystem Team ✨"] direction TB DS2("📊 Data Scientist"):::ds end CSub == "API (X-as-a-Service)" ===> SAT2 %% Styles classDef ds fill:#fff9c4,stroke:#fbc02d,color:black,stroke-width:4px,rx:10,ry:10 classDef others fill:#ffffff,stroke:#bdbdbd,color:black,stroke-width:1px,rx:5,ry:5 style SAT2 fill:#f8f9fa,stroke:#dee2e6,stroke-width:2px,rx:10,ry:10 style CSub fill:#fff3e0,stroke:#ef6c00,stroke-width:3px,stroke-dasharray: 5 5,rx:10,ry:10 linkStyle 0 stroke:#ef6c00,stroke-width:3px,color:#ef6c00 インタラクションモードとプロトコルの明文化 組織を分けることで最も懸念されるのが、「サイロ化」と「連携コストの増大」です。これを防ぐため、基本的には X-as-a-Serviceモード を採用しつつ、状況に応じて コラボレーションモード を使い分ける運用としています。 基本方針:X-as-a-Service 日常的な開発・運用においては、コンプリケイティッド・サブシステムチームが提供するサービス(API、ドキュメント等)をストリームアラインドチームがセルフサービスで利用する形をとります。 ストリームアラインドチームとの連携境界における、コンプリケイティッド・サブシステムチームの主な責務は以下の通りです。 安定したAPIの提供と、SLA/SLOの維持。 専門的なロジックの隠蔽と、利用しやすいインターフェースの設計。 ドキュメントの整備(ストリームアラインドチームが自律的に利用できるようにする)。 ストリームアラインドチームは、いちいちコンプリケイティッド・サブシステムチームに「これどうなってますか?」と確認することなく、APIドキュメントを参照して開発を進めることができ、開発スピードを維持できます。 もちろん、API仕様書だけを投げ合うのが非効率な場面(新規機能開発や大きな変更時など)では、同期的な会議や一時的なスクラムイベントへの参加などを通じて、柔軟にコラボレーションを行っています。基本は疎結合(X-as-a-Service)を保ちつつ、必要な時には密に連携できる柔軟性を持たせています。 プロトコルの明文化 「X-as-a-Service」や「コラボレーション」といったモードを定義しても、実際の現場では「このタスクはどっちの責務?」「今はどっちのモードで動くべき?」といった迷いが生じがちです。 そこで、これらの実行を補完する役割として、特に密接に関わっているストリームアラインドチームとコンプリケイティッド・サブシステムチームの間で「チーム間連携プロトコル」というドキュメントを作成し、合意形成を行いました。 このドキュメントには、主に以下のような内容を記載しています。 各チームのミッションと責務の定義 : ストリームアラインドチームとコンプリケイティッド・サブシステムチームがそれぞれ何に責任を持つかを明記。 自律的に実行できる活動リスト : 連携や確認なしで進めて良いタスクを具体的にリスト化(例:公開API仕様内でのリファクタリングなど)。 連携が必要なケースとフロー : コミュニケーションが必要な具体的なトリガーと、その際の推奨連絡手段。 エスカレーションパス : 解決しない場合の判断フロー。 こうした具体的な「期待値調整」をドキュメント化しておくことで、日々のコミュニケーションコストを削減し、迷いを減らすことができています。 おわりに 組織構造は、その時点でのビジネスフェーズと技術的な複雑さに応じて進化させる必要があります。かつてはデータサイエンス的な要素を含んだ機能開発を行うため、ストリームアラインドチームにデータサイエンティストが在籍する体制をとっていましたが、フェーズの変化に伴い、コンプリケイティッド・サブシステムチームとして切り出す形がより適した状態へと変わりました。 今回のリデザインにより、データサイエンティストはより専門性を発揮しやすく、ストリームアラインドチームはよりユーザー価値に向き合いやすい体制が整いつつあります。特に、データサイエンティストからは「技術的な深掘りがしやすくなった」「コンテキストスイッチが減った」という声が上がっており、組織としての健全性も向上しています。 この事例が、拡大するエンジニアリング組織におけるチーム設計の参考になれば幸いです。 We’re Hiring! タイミーではデータサイエンティストをはじめ、一緒に働くメンバーを募集しています! カジュアル面談 も行なっておりますので、興味のある方はぜひお気軽にお申し込みください! https://product-recruit.timee.co.jp/
はじめに 前提:アウトカムに向き合う「プロダクトエンジニア」と組織構造 ① 「チームトポロジー」に基づくストリームアラインドチーム ② 「プロダクトエンジニア」という在り方 ③ 2sidesの顧客に向き合う複合ドメインのプロダクト なぜ私たちは「超人EM」を組織の前提とするのをやめたのか 役割のアップデート:「実行」から「診断」へ 構造①:診断 (Diagnosis) 〜 核心を見極める 〜 構造②:基本方針と行動 (Guiding Policy & Actions) 〜 「埋め方」のデザイン 〜 「個のスパイク」を組織のポートフォリオにする 仕組みで支える:AI活用と評価制度 ① AI・LLMによる「診断力」のブースト ② キャリアラダーとコンピテンシーの再設計 まとめ:Engineering Managementを「個人のスキル」から「組織の機能」へ 未来のエンジニアリングマネジメントのあり方を一緒に描いていただけませんか? はじめに この記事は Timee Product Advent Calendar 2025 の24日目の記事です。 株式会社タイミーでVPoEをつとめております、赤澤 a.k.a chango( @go0517go )です! 「ええやん!」が口癖なので、社内では「VP of Eeyan」なんて いじられ 呼ばれたりもしています。 さて、アドベントカレンダーも佳境の24日目。 今回は、私が以前登壇した内容をベースにしつつ、来年の「EMConf JP 2026」にProposalとして提出していたテーマのうちの1つである「チームで立ち向かうエンジニアリングマネジメント」についてお話しします。 Engineering Managementに関するテーマや内容は自分にとっても深く、私たちも常に試行錯誤しながら探索し続けている領域です。 今回のアドベントカレンダーでは、その「触り」となるエッセンスや、根底にある思想にフォーカスして書きたいと思います。 なお、こちらのProposalは残念ながら採択されませんでした涙…。ですが、タイミーはEMConf JP 2026のプラチナスポンサーとして協賛しております! 弊社のCTOである山口 a.k.a ZIGOROu( @zigorou )がスポンサーセッションで登壇しますので、タイミーの技術戦略やエンジニアリング組織論に興味がある方は、ぜひ会場でZIGOROuのセッションを聞いてください! それでは、急拡大する事業とプロダクト開発の中で私たちが描いた、「診断医」としてのエンジニアリングマネジメントについてお話しします。 前提:アウトカムに向き合う「プロダクトエンジニア」と組織構造 EMの役割についてお話しする前段階として、そもそもタイミーのエンジニアリング組織がどのような組織構造で、どのようなエンジニア像をもって開発しているかをお話しさせてください。 ① 「チームトポロジー」に基づくストリームアラインドチーム タイミーの開発組織は、『チームトポロジー』の考え方に基づき、特定の価値を提供する継続的な流れ(バリューストリーム)を対象とした「ストリームアラインドチーム」で構成されています。 これは、 エンジニアだけでなくPdMやデザイナーを含む6±2名程度の「職能横断型組織」 であり、DiscoveryからDelivery、つまり価値の探索と検証から実際の開発、そして運用までを一気通貫で担い、高速に仮説検証のサイクルを回すことを目的としています。 タイミーにおけるストリームアラインドチーム ② 「プロダクトエンジニア」という在り方 そして、そこで働くエンジニアに求めているのは、単に機能を作るだけの役割ではありません。私たちは「プロダクトエンジニア」という在り方を掲げています。 これは、「 プロダクトの提供価値を継続的に高めることでお客様の課題を解決するエンジニア 」と定義しており、全員がアウトカム(顧客への価値提供)に向き合うことを前提としています。 提供価値向上: 機能を作ることではなく、顧客課題を解決することに責任を持つ。 越境性: 自分の専門領域に閉じず、ドメインや役割を越えて知識を追求する。 オーナーシップ: 「How(どう作るか)」だけでなく、「Why(なぜ作るか)」「What(何を作るか)」の段階から関与する。 ③ 2sidesの顧客に向き合う複合ドメインのプロダクト さらに重要なのが、私たちが向き合っているプロダクトの特異性です。 タイミーは「ワーカー(働き手)」と「クライアント(事業者)」という異なる2つの顧客(2sides)に価値を提供するプラットフォーム であり、その裏側は複数のビジネスドメインが密接に連携する複合システムとなっています。 「スキマバイトのマッチングアプリ」として、UI/UXとともに想起いただくことが多いと思いますが、実はそのバックグラウンドには極めて広範な機能群が存在しています。 例えば、いくつか代表的な機能要素を見ても、QRコードによる出退勤、銀行API連携を伴う給与計算・振込処理、そして法令対応を含む労務管理など、これらすべてがなめらかな雇用体験と良いマッチングを実現するために不可欠な要素として統合されています。 つまり、タイミーのEMが管掌するのは、「職能横断で自律的に動き、Why/Whatから考え、これら複雑な複合ドメインのアウトカムにコミットするチーム」なのです。 2sidesの顧客に向き合う複合ドメインのプロダクト なぜ私たちは「超人EM」を組織の前提とするのをやめたのか さて、ここからが本題です。 上記のような複雑かつ高水準なチームを率いるエンジニアリングマネージャー(EM)には、どのような能力が求められるでしょうか? 一般的に語られる「EMの4つのマネジメント領域」を見てみましょう。 Technology: 技術的負債の解消、アーキテクチャ設計、生産性向上 People: 採用、育成、評価、目標設定、メンタリング Process: 開発プロセスの最適化、アジャイルの実践 Product: 顧客課題の発見、ドメイン知識、法要件の理解 知らず知らずのうちに、これら全てを一人で高い水準でリードできる「超人(スーパーマン)EM」を、理想像として求めてしまってはいないでしょうか? もちろん、各マネジメント領域においてプレイヤー性を高め続けることを、個人のキャリアとして追い求めることは重要であり、私自身もそうありたいと願っています。 しかし、同時に 組織としてその超人的存在を前提としすぎると「ひずみ」が拡大してしまいます。 全4領域で常に100点のプレイングができる人材を求めることは、現実には極めて困難であり、個人の負荷を過剰にします。その結果、採用基準も高止まりし、適切な人材が集まらなくなる。そうして、事業の急成長にエンジニアリング組織とそのマネジメントが追いつかないという、組織的な「ひずみ」が生み出されるのです。 なぜ、知らず知らずのうちに、そこまでの理想を求めてしまうのでしょうか? そもそもEMという職種は役割定義が曖昧になりがちな上に、タイミーの場合は多様なバックグラウンドを持つEMが中途入社で多く参画いただく状況でした(私自身もその一人です)。だからこそ、「この混沌を個人の力で解決してほしい」という期待が先行し、採用要件や期待値の中に、無意識のうちにこの「スーパーマン像」を投影してしまうケースがあると考えています。 私たち自身も過去を振り返り、そのような判断があったと振り返っています。 かといって、現実解として特定の領域、例えば「People Management」だけに単純に絞り込むこともできません。 顧客課題を深く理解するProductの視点、そして最適な実装を判断するTechnologyの視点。これらを欠いたままでは、「エンジニアリング組織」のマネージャーとして本質的な課題解決ができないからです。 同時に、一人の人間にすべての領域のリードを求めれば、マネジメントの人材不足はより顕著になります。 そもそも、 「あれもこれも全部やる」というのは、戦略ではありません。それは単なる「願望(Wish List)」です。 『良い戦略、悪い戦略』の著者、リチャード・P・ロメルトが指摘するように、戦略の本質は「何をやらないか」を選択することにあります。 タイミーのエンジニアリング組織では、「超人EM」という個人の頑張りに過度に依存する構造から脱却し、組織として持続可能な仕組みを作る必要があると判断しました。 役割のアップデート:「実行」から「診断」へ 「全てをやる」という願望(Wish List)から離れたとき、私たちの目の前に残った問いは明確です。 「では、限られたリソースで最大のアウトカムを出すために、今『何をするか』を誰が決めるのか?」 複雑で混沌とした状況の中で、無数にある課題から本質的な「急所」を見極め、チームの力をそこに集中させる。 自分で手を動かして全てを解決するのではなく(もちろんそれも重要な手段です)、「何を解くべきか」を正しく定義することこそが、この規模の組織におけるEMの最大の提供価値ではないか。 そう考えたとき、私たちの指針となったのが、戦略論の名著『良い戦略、悪い戦略』にある「戦略のカーネル」という概念でした。 これはタイミーのプロダクト開発組織においてしばしば用いられる、あらゆる戦略や方針を検討する際の「骨格」となっているフレームワークであり、私自身もタイミーにジョインした後、CTOのZIGOROuから注入された代表的なエッセンスです笑。 【参考:戦略のカーネルとは】 診断 (Diagnosis): 状況を単純化し、取り組むべき課題の「核心」を見極める。 基本方針 (Guiding Policy): 診断された課題に対処するための、全体的なアプローチ。 一貫した行動 (Coherent Actions): 方針に基づき、リソースを集中させた具体的なアクション。 私たちは今、これをベースに、EMの役割を「プレイヤーとして全てを実行すること」から、「チームが実行できるように『診断』し設計すること」へとアップデートしようとしています。 構造①:診断 (Diagnosis) 〜 核心を見極める 〜 EMの第一の責務は、Technology、People、Process、Productの全領域において、「何が問題の『核心(Kernel)』なのか」を高い解像度で見極めることだと考えています。 単に「課題リスト」を作るのではありません。「開発スピードが遅い」という現象があったとき、その真因は技術的負債なのか、意思決定フローなのか、それともメンバーの心理的安全性なのか。 無数にある課題の中から、そこさえ解けば状況が好転する「急所」を見抜くこと。この診断をエンジニアリングの現場で適切に行えることをEMの重要な役割だと考えております。 構造②:基本方針と行動 (Guiding Policy & Actions) 〜 「埋め方」のデザイン 〜 診断によって「何が足りないか(Gap)」が明確になれば、次はそれをどう埋めるか。 ここで重要なのは、「基本方針(Guiding Policy)」を定め、それに基づいた「一貫した行動(Coherent Actions)」に落とし込むことです。 その「埋め方」の選択肢は、決して「EMが頑張る」ことだけではありません。チームの状況に合わせて、最適な打ち手をデザインする必要があります。 プレイヤーとしてEMが補う(「オレが3人分になる...」) メンバーのケイパビリティ獲得を支援する(育成・学習機会の提供) 組織構造やリチーミングで解決する(チーム構成の変更) 外部からケイパビリティを獲得する(採用・外部の組織や企業との連携) 重要なのは、自分がスーパーマンになることではなく、診断結果に基づき、最適な「方針」を選び取り、迷いなく「行動」に移すことです。 逆に言えば、「自分はやらない(チームや仕組みに任せる)」と決める勇気を持つことでもあります。 個人の万能さに過度に依存するのではなく、チームとしての総力を最大化する道を選ぶ。これが今取り組んでいる(そして試行錯誤し悩みながら進んでいる!)私たちのエンジニアリングマネジメントです。 「個のスパイク」を組織のポートフォリオにする 「診断医」モデルにおいては、EM個人の「弱み」は個人としては、今後補強していく点であると同時に、組織としては「補い合うべき余白」になります。 私たちは、各EMのバックグラウンド(エンジニア、PdM、アジャイルコーチ・スクラムマスターなど)による「スパイク(突出した強み)」を歓迎し、それを個人のスキルではなく「組織のアセット」として考えようとしています。 Tech-oriented EM: 技術的な診断や意思決定の「構造知」を言語化し、他のEMに共有する。 Product-oriented EM: 複雑なドメインや法要件の読み解き方を形式知化し、組織全体のProduct理解を底上げする。 Process-oriented EM (Engineering Operations Manager): 開発フローやデリバリーのボトルネックを可視化し、チーム間の学習速度と成果再現性を高める。AI活用やリチーミング設計など、継続的改善のサイクルを仕組み化。 もちろん、現実的な運用においては、「チームが取り組む課題」と「EMの強み」が必ずしもパズルのように完璧にマッチするとは限りません。 特に現在のタイミーでは、EMが目標設定や評価も担う組織上の上長も兼ねています。心理的安全性や長期的な育成の観点からも、プロジェクトの都合だけで上長を高頻度に変えることは望ましくありません。 そこで重要になるのが、「EMs(EMチーム)間での相互補完」です。 担当チームの課題に対して、そのEMのケイパビリティが不足している場合、他の得意なEMがクロスで入って支援する。個人の不足を「個人の努力」だけで埋めるのではなく、「組織(EMs)の総力」でフォローする体制を構築しています。 さらに現在はテックリードなどの役割をあらためて定義、各領域のマネジメントをより委譲・分散していく体制についても、CTOや私(VPoE)、そして現場のEMたちと議論し、進行しています。 ここはまだまだ議論や方針を定めている最中で、まさにこれから推進していきたい「組織の伸び代」でもあります。 一人でフルスタックを目指すのではなく、EMチーム全体、そして組織全体でポートフォリオを組み、相互に診断を支援し合う。 これこそが、複雑化・巨大化する組織に対する唯一の対抗策だと信じています。 仕組みで支える:AI活用と評価制度 この新しいEM像を考え方で終わらせないために、いくつかの「仕組み」での実装に現在取り組んでいます。 ① AI・LLMによる「診断力」のブースト 全領域のキャッチアップを人間の脳だけで行うには限界があります。そこで私たちはAIを「診断アシスタント」としてフル活用しています。 コードベースの把握: DevinやCursorを用い、技術的な仕様や依存関係を高速に把握する。 組織状態のモニタリング: Slackのpublicな業務チャンネルでの重要なトピックや会話のサマリ、チーム全体のGitHubのアクティビティ傾向など、客観的な数値指標を参考にエンゲージメントの変化の予兆(診断材料)を提示する。 ② キャリアラダーとコンピテンシーの再設計 「スーパーマン」を求めない以上、評価基準も変える必要があります。 ここが今まさに私たちが挑戦している最前線なのですが、EMのキャリアラダーにおいて、「個人の実行能力(どれだけコードが書けるか、どれだけ仕様に詳しいか)」の評価軸をさらに拡張して、以下の能力を重視するコンピテンシー設計へとシフトを進めています。 診断の正確さ: 課題の核心(Kernel)をどれだけ深く捉えられているか。 チームへの移譲・設計能力: 成果を特定の個人に依存させず、再現性のある仕組みとして設計・実装できているか。 相互補完: 自身の強みを組織知として還元し、他EMを支援できているか。 「個人のスキル」ではなく「組織の機能」としてEMを定義し直す。この評価制度の設計こそが、超人EMへのアンチテーゼを完遂させる最後のピースだと考えています。 まとめ:Engineering Managementを「個人のスキル」から「組織の機能」へ 急拡大する組織と複雑なドメインに向き合う中で、私たちがたどり着いたエンジニアリングマネジメントの現在地は、以下の4点に集約されます。 役割の再定義 EMに求めることは、「自らが全領域を実行すること(超人的になること)」ではありません。「チーム全体で全領域を実行できるように、状況を『診断』し『設計』すること」です。 強さの源泉は「構造化」 個人の馬力に頼るのではなく、「診断 → 基本方針 → 行動」のサイクルを回し、課題解決を構造化できることこそがEMの強さであると考えています。 「個のスパイク」を組織の武器に 全方位完璧である必要はありません。EM個人の「スパイク(突出した専門性)」を歓迎し、足りない部分はEMチーム全体で相互補完する設計を進めています。 「個人のスキル」から「組織の機能」へ Engineering Managementを、属人化した個人のスキルではなく、再現性のある「組織の機能」へと昇華させること。これが、私たちの現在進行形の挑戦です。 この新しいEM像の実装はまだ道半ばです。だからこそ、私たちと一緒にこの挑戦を楽しんでくださる仲間を求めています! 未来のエンジニアリングマネジメントのあり方を一緒に描いていただけませんか? 私たちは今、これまでのエンジニアリングマネジメントを構造や仕組みで再現性持って継続していくというチャレンジの最中です。 「EMの仕事は負荷が高くて辛い」「一人の個人に求められる要素が多すぎる」という課題に対して、「チームで戦う」「診断と設計で価値を出す」というスタイルを確立したい。 タイミーではエンジニアポジションを全方位で全力拡大採用中です!そして今回お話しさせていただいたEngineering Managerポジションも特に注力しているポジションです。 採用ポジション:Engineering Manager 少し話聞いてみようかな、くらいの気軽さで私たちはとても嬉しいです、ぜひ気軽にお話しさせてください!明日25日の記事もお楽しみに! プロダクト採用サイトTOP カジュアル面談申込はこちら
はじめに この記事は Timee Product Advent Calendar 2025 の23日目の記事です。 背景 営業やマーケティングの現場では、連続変数を特定のしきい値で区切って2値のKPIとして扱うケースがあります。例えば、「月の購入金額が1万円を超えた顧客を『ロイヤル顧客』と定義する」といったケースです。ここで、このKPIに対する施策の効果測定を行う際は、「ロイヤル顧客への転換率」をアウトカムに設定し、ABテストで群間の差を検定するのが最もシンプルなアプローチとして挙げられます。 図1: Geminiもそう思います(2025/12/17, Gemini 3 Pro) 連続的な現象を2値データとして観察した場合は、連続的な潜在変数および誤差項のモデリングと、閾値を基準とした2値化によって定式化できます。例えば、誤差項にロジスティック分布を仮定した場合にはロジットモデル(ロジスティック累積分布関数)に従います[1][2]。本ケースもこれと同様に考え、施策効果の分布の推定が可能です。ただし、ビジネス上の定義としてはわかりやすいこの2値化処理は、同時に本来持っていた情報を捨てることになり、効果測定における検出力が低下する(正規分布に従う変数を中央値でカットした場合、同じ検出力を得るためにはサンプルサイズが1.5倍必要[3])と報告されています。 このようなケースではもとの連続量も併せてモニタリングすることが推奨されますが、本稿では連続量のままモデリングする手法の有効性検証に焦点を当てます。 具体的には、2値化されたアウトカムを2値として扱う場合と、連続量分布を推定してから事後的にKPIを計算する場合とで、効果測定の正確さがどう変わるかを比較します。 実験 1.分布の仮定が正しい一回試行での比較 仮想のECサービスを考え、「売上が1万円以上」をロイヤル顧客とみなし、顧客のロイヤル率を改善する施策をABテストした状況を想定してサンプルデータを作成しました。 具体的には、「非購入者(0円)」と「購入者(対数正規分布に従う売上)」が混在する売上分布を仮定し、以下のパラメータp, μ, σのもと、各グループで500顧客分ずつ作成しました。 パラメータ Control Treatment 購入率 p 0.50 0.53 対数平均 μ 8.0 8.20 対数標準偏差 σ 1.0 1.0 このとき、各サンプルデータが従う真の統計と施策効果は以下のようになります。 指標 Control Treatment 効果 期待売上 ¥2,457 ¥3,182 +¥724 ロイヤル率 5.65% 8.28% +2.62pt 次に、サンプルデータに対して以下の2つの手法でロイヤル顧客率に対する効果を推定し、真の施策効果を基準として比較しました。 アウトカム2値化: 売上が1万円以上か否かのフラグを立て、その比率の差を直接比較する。 アウトカム連続+ラベル事後計算: 真の尤度関数を用いて売上金額の分布を推定し、事後分布からロイヤル顧客の定義である「売上が1万円以上」を超える確率を計算して差を比較する。 2.分布の仮定が正しい複数回試行での比較 データが従う分布のパラメータを以下の範囲でランダムに変化させて作成しなおし、その他は1の設定を踏襲した実験を100回繰り返しました。そのうえで、2つの手法間で測定される効果の正確さを比較しました。 項目 値 購入率 p 0.6〜0.8 購入率 p への効果 +0.02〜+0.10 対数平均 μ 7.9〜8.2 対数平均 μ への効果 +0.05〜+0.20 対数標準偏差 σ 0.7〜1.1 3.分布の仮定が誤っている複数回試行での比較 2.と同様の手順でサンプルデータを20回作成し、各データに対して3通りの尤度関数(対数正規分布・ガンマ分布・パレート分布)を用いた効果測定をそれぞれ実施しました。そのうえで、各尤度関数間で測定した効果の正確さを比較しました。 結果 1.分布の仮定が正しい一回試行での比較 2つの手法間での結果の差を図2に示します。 図2: 2値化しないほうが分布の山が真値に近く、信用区間の幅も狭い。 2つの手法はどちらも真の効果をほぼ捉えていますが、「アウトカム連続+ラベル事後計算」手法(グラフ橙色)は真の効果である+2.62pt付近に鋭い分布でピークがあり、真値に近い効果を比較的高い確信度で捉えました。 2.分布の仮定が正しい複数回試行での比較 2つの手法を繰り返したとき、測定した効果の真値に対する差の比較を図3に、分布の幅の広さの差を図4に示します。 図3: 2値化しないほうが平均的に分布の山が真値に近い。 図4: 2値化しないほうが平均的に信用区間の幅が狭い。 「アウトカム連続+ラベル事後計算」手法のほうが平均的に真値に近い効果を推定しました。 3.分布の仮定が誤っている複数回試行での比較 「アウトカム連続+ラベル事後計算」手法について、尤度関数を変えたとき測定した効果の真値に対する差の変化を図5に示します。 図5: 尤度関数の当てはまりが悪いほど真の効果に対するバイアスが増加する。 尤度関数として真の分布と異なる分布を仮定した場合、当てはまりが悪いほど測定した効果が真値から離れる傾向があり、いずれも「アウトカム2値化」手法と比較して正確さが悪化しました。 結論 連続量を2値化したKPIに対しては、Beta-Binomialモデルを用いた2値KPIに対する効果測定を、複雑な分布仮定を必要としないロバストなベースラインとして採用できます。 より高い検出力を追求したい場合、連続量のまま分布をモデリングして効果測定し、事後分布からKPIを再計算するアプローチが有効な選択肢となりえます。 ただし誤った分布を仮定すると逆効果となるため、WAICによるモデル選定や閾値周辺の適合度の目視確認など、厳密なモデル選定が必要です。 参考文献 [1] Greene, W. H. (2003). Econometric Analysis (5th ed.), pp. 665-669. [2] C. M. ビショップ (2007). パターン認識と機械学習 上 (元田 浩 他 訳). [3] Cohen, J. (1983). The cost of dichotomization. Applied Psychological Measurement, 7 (3). おわりに タイミーではデータ分析を通じてプロダクトの成長を支えるメンバーを募集しています。ご興味のある方はぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
こんにちは。タイミーQAエンジニアの矢尻です。 この記事は Timee Advent Calendar 2025 シリーズ1の23日目の記事です。 「アドベントカレンダー」といえばキリスト教の待降節ですが、実は私、元 神主(神職) というちょっと変わった経歴を持っています。 「異教徒がアドベントカレンダーを書いていいのか?」と心配される方もいるかもしれません。しかし、日本の神道には「八百万(やおよろず)の神」という、あらゆるものに神性を見出す懐の深い概念があります。クリスマスも正月も祝う日本人の精神性において、このテックブログもまた、技術の神々に感謝を捧げる「祭り」の一環と捉えれば、何ら問題はありません(ほんとに?)。 さて、今日はそんな異色の経歴を持つ私が、 神社祭式とソフトウェア品質保証(QA)の驚くべき共通点」 について、少しマニアックに語りたいと思います。 神社は「巨大なレガシーシステム」 神職からエンジニアに転身して最初に感じたこと。それは「やっていることが本質的に同じだ」という衝撃でした。 神社には「祭式(さいしき)」という厳格なプロトコルが存在し、「式次第」というプログラムがあり、「祝詞(のりと)」という仕様書が存在します。これらが緻密に相互作用し、バグ(不作法)なく執り行われることで、初めて「祭り」というシステムが正常稼働(デプロイ)されます。 私がQAエンジニアとして日々システムに祈っている「平穏」は、神主時代に祈っていた「安寧」と、構造的に全く同じものなのです。 1. 「祓(はら)へ」と「デバッグ」:ケガレを除去するリファクタリング 神道には 「ケガレ(穢れ/気枯れ)」 という概念があります。これは罪や穢れ、気力が枯渇した状態を指します。これを元の清浄な状態(あるべき姿)に戻すのが「祓(はら)へ」です。 システム開発における「バグ」や「技術的負債」、あるいは「不安定なテストデータ」。これらはまさにシステムにおける「ケガレ」です。 修祓(しゅばつ): 祭儀の最初に行うお祓いは、本番環境(祭場)へ移行する前の 初期化処理 や スモークテスト です。 大祓(おおはらえ): 定期的に蓄積した罪穢れを祓う行事は、定期的な リファクタリング そのものです。 「祓へ」によって場をクリーンにしなければ、どんなに素晴らしい祝詞(機能)も神様(ステークホルダー)には届きません。QAがバグを見つけ出し修正を促す行為は、システムを「清浄」に保つための神聖なプロセスなのです。 2. 祭式をコードで理解する 神社の儀式はブラックボックスに見えますが、実は非常に堅牢なアーキテクチャで設計されています。 ここでは、神職が奉仕する「家内安全祈願祭」を、あえてエンジニアの皆様に馴染み深いコードに置き換えて紹介したいと思います。 身体的プロトコル:「進左退右」というコーディング規約 コードに入る前に、マニアックな仕様の話をさせてください。 神職が祭場を歩くとき、 「進左退右(しんさたいゆう)」 という厳格なルールがあります。「進むときは左足から、退くときは右足から」という決まりです。 「どっちでもいいだろ」と思われるかもしれませんが、これは 「オペレーションミスによる障害」を防ぐための物理的な制約 です。 上位(神前)に近い足を軸にすることで、体の向きが安定し、神主同士がぶつかったり(コンフリクト)、転んだり(クラッシュ)、神様に背中を向けたり(要求定義からの逸脱)するリスクを最小化しています。祭式とは、 人間の身体動作に実装されたコーディング規約 なのです。 Rubyによる式次第の実装 では、祭りの進行表である「式次第」をRubyのコードに落とし込みます。 原文のプロセスとコードのロジックが完全に1対1で対応している点にご注目ください。 【原文】家内安全祈願祭 式次第 参進(さんしん):祭場へ入る 修祓(しゅばつ):心身を祓い清める 献饌(けんせん):お供え物を捧げる 祝詞奏上(のりとそうじょう):願い事を申し上げる 玉串拝礼(たまぐしはいれい):拝礼する 撤饌(てっせん):お供え物を下げる 退下(たいげ):祭場から退く 【コード】KanaiAnzenService.rb class KanaiAnzenService include ShintoProtocols # 祭事は不可分な一連の処理であるため、トランザクションとして扱う def execute ( devotee :) ActiveRecord :: Base .transaction do begin # 1. 参進(さんしん) # ※Linter: 進左退右プロトコルに準拠すること enter_shrine(devotee, step_strategy : :shin_sa_tai_u ) # 2. 修祓(しゅばつ):初期化・クリーンアップ # ※ここが最重要。穢れ(Bug/Dirty Data)が残っていると後の処理は全て無効 unless perform_purification( target : devotee, level : :strict ) raise UncleannessError , " 祓い清めが不十分です。儀式を続行できません。 " end # 3. 献饌(けんせん):リソースロード # 依存関係順(米→酒→塩→水)にロードしないとエラーになる offer_shinsen( type : :sake_and_food , order : :strict ) # 4. 祝詞奏上(のりとそうじょう):コアロジック実行 # 言霊パラメータを神界へ送信 invoke_norito( type : :kanai_anzen , target : devotee) # 5. 玉串拝礼(たまぐしはいれい):ユーザーインタラクション # ユーザー(参拝者)自身によるコミット操作 guide_tamagushi_worship(devotee) # 6. 撤饌(てっせん):リソース解放 withdraw_shinsen rescue UncleannessError => e # 異常系:儀式の中断。再浄化(Fix & Re-test)が必要 handle_kegare(e) raise e ensure # 7. 退下(たいげ):プロセス終了 # 成功失敗に関わらず、最後は退室する exit_shrine end end end end transaction ブロックで囲んでいるのがポイントです。お祓いに失敗したまま祝詞だけ読んでも、それは儀式として成立しません(コミットされません)。実際の祭りでもロールバック(やり直し)されます。ACID特性が求められるのです。 3. 祝詞の仕様定義:Gherkin 次に、祭儀の核となる「祝詞(のりと)」です。 祝詞は、「誰が」「どういう状態で」「何をすれば」「どうなるか」を宣言するものです。これは、振る舞い駆動開発(BDD)における Gherkin記法 そのものです。 「家内安全」の祝詞の原文と、それをGherkinに翻訳したものを並べてみます。 【原文・Gherkin対応】 Feature: 家内安全 (Family Safety) In order to 平穏無事な生活を送るため As a 氏子/崇敬者 I want to 神の加護を得て災いを防ぐ Scenario: 祓い清められた状態で祈願を行う # 【原文】掛けまくも畏き(かけまくもかしこき)XX神社の大前(おおまえ)に # 【意味】言葉にするのも畏れ多い、XX神社の神様の御前にて Given ターゲット環境は "XX神社本番環境" である # 【原文】宮司 氏名 恐み恐みも白す(かしこみかしこみもまおす) # 【意味】宮司の[氏名]が、謹んで申し上げます And 実行ユーザー(Actor)は "認定神職" である # 【原文】此の氏子(うじこ)◯◯の家族(やから)一同 # 【意味】この氏子である[住所][氏名]の家族全員が And 対象オブジェクトは "氏子[住所][氏名]のFamilyクラス全インスタンス" である # 【原文】過ち犯す事無く 災い触れる事無く # 【意味】過ちを犯すことなく、災難に遭うこともなく When "HumanError" および "ExternalDisaster" イベントが発生しない条件を適用し # 【原文】夜の守り 日の守りに守り恵み給い # 【意味】昼も夜も守り恵んでいただき And "24/365" の監視体制(Protection)を有効化し # 【原文】平らけく安らけく 孫の代に至るまで # 【意味】平穏無事に、子孫の代に至るまで Then システム稼働状況は "平らけく安らけく(Stable)" であること And データ永続性は "孫の代(LongTerm)" まで保証されること # 【原文】家門(いえかど)高く広く 立ち栄えしめ給へと 恐み恐みも白す # 【意味】家がますます繁栄しますようにと、謹んで申し上げます And "家門(BusinessValue)" は右肩上がりにスケールすること 「言霊(ことだま)」とは、言葉にしたことが現実になるという信仰 ですが、エンジニアリングにおいても 「コード(言語)にしたことが実際の挙動になる」 という点は全く同じです。 正確な言葉(コード)で記述しなければ、システムは意図通りに動きません。 4. 式年遷宮という名の「大規模リプレース」 エンジニアの世界では、大規模なシステムリプレースのことを冗談交じりに「式年遷宮(しきねんせんぐう)」と呼ぶことがあります。 伊勢神宮で20年に一度行われる、社殿を新しく建て替える一大プロジェクトのことですね。 実はこれ、神道的な観点でも意図・目的が完全に一致しています。 式年遷宮の真の目的は、建物を新しくすることだけではありません。 「宮大工の知識と技術の継承」 こそが本質です。 20年というサイクルは、ベテランから若手へ技術を継承するのに最適な期間(世代交代の期間)として設計されています。 システムも同じです。どんなに堅牢なコードも、それを保守する技術者がいなくなれば(属人化すれば)いずれ朽ち果てます。 コードを書き直し、技術スタックを新しくすることは、システムという「神」を若返らせ、技術という「伝統」を次世代へ継承するための、聖なる営みなのです。 結びに代えて:「平らけく安らけく」の祈りを込めて 神道の祝詞によく登場する 「平(たい)らけく安(やす)らけく」 という言葉があります。 これは「波風が立たず、平穏であること」を願う言葉です。 私がQAエンジニアとしてリリース直前に願うこと。それは新機能の華々しい成功よりも先に、「システムがクラッシュせず、ユーザーにとって当たり前の日常(平穏)が守られますように」という祈りです。 しかし、神主の祈りは「神頼み」ではありません。 掃除をし、場を整え、身を清め(テストをし)、作法を極めた(バグを修正した)上で、最後の最後に捧げるのが祈りです。 「人事を尽くして天命を待つ」。このプロセスこそが品質保証の本質であり、それは「祭り」の準備と何ら変わりがないのです。 今年も残りわずかとなりました。 アドベントカレンダーという「祭り」を通じて、皆様と知見(?)を共有できたことを嬉しく思います。 来る新玉(あらたま)の年が、皆様そして皆様の開発するシステムにとって、バグなき清浄なものであり、 弥栄(いやさか) に栄え、 平らけく安らけく あらんことを、心よりご祈念申し上げます。 タイミーでは一緒に働く仲間を募集しています。ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
この記事は Timee Product Advent Calendar 2025 の22日目の記事です。 はじめに こんにちは!kazzhiraと申します。タイミーでプロダクトエンジニアとして働いています。 この記事では、AIエージェント開発をチームに定着させようと奮闘したストーリーと、そこで得た学びを語ろうと思います。 よってこの記事はAIの技術解説ではありません。 『AI推進』という答えのない課題に直面して空回りしたエンジニアが、どのようにして仕事を前に進めるコツを掴んだのかを記録したものです。 何かを推進する立場の方にとって学びや励みになればと思い、執筆しています。 背景 チームメンバーは全員がプロダクトエンジニアで、AI時代よりも前から開発経験があります。 主にフロントエンド、バックエンド、Androidのケイパビリティがあります。 Cursor、Claude Code、Devin、GitHub Copilot、Geminiを個々人の判断で利用可能です。 プロダクト組織ではAI活用が進んでおり、 私も「AI活用を進めて生産性を上げたい」という強いモチベーションがありました。 上司からもチャンスをいただけたので、即「やっていきます!」と推進をしていくことに。 推進で試行錯誤した3ヶ月間の話 これまで私は開発業務の遂行、個人で生産性を上げる取り組み、短期的な組織運営を経験してきました。 今回引き受けたAI推進は、チーム全体をスコープとする中長期の組織的な取り組みです。 このスコープでの取り組みで成功体験が少なく、私にとって新たな挑戦でした。 当初の状況を整理すると、組織としてはTipsは転がっているものの、AI活用の状況は個々人に閉じていました。 AIの技術進化は近年目まぐるしく、AIを中核にワークフローを組んだりサービスを作ってもすぐに陳腐化してしまうなど、不確実性が高い領域です。 この状況を認識しつつも悶々としたまま、2週間が過ぎました。そう、身動きが取れていない状態だったのです。このときの行動のループをまとめると、 推進って具体的にどうするの?自分の中で良さそうと思っていることを単に広めるってこと? ブレストして、共通項をまとめる… 結局それで何になるの?AI活用が今より進んでいるってどういう状態? 今振り返ると、焦りから完全に空回りしていました。 AI開発標準の作成エピソード 頭を悩ませているうちに時間が経過し、自分自身のモチベーションも下がっていることに気づきました。このことを上司に相談したところ、的確なフィードバックをもらいました。 「情報収集と分析が足りていない」(意訳) ハッとしました。 チームには情報がありません。当然、情報収集が必要です。 私はテックブログや時事ネタを眺め、それを手元で試したり、試さずに終わってしまったりしている状態でした。 「なぜやるのか」「どうやるのか」をチームに腹落ちさせるだけの材料も、 自分自身の確固たる言葉も持っていなかったのです。 その日から私は情報をかき集め、Geminiと相談しながら内容を深掘りし、知見を深めました。 80%くらいのAI開発標準v0.1を即座に作成し、メンバーからフィードバックを受けてブラッシュアップしました。 次に示すのはドキュメントで定義した開発フロー図の一部です。 前後のPhaseは本質と関係ないため図から除外しています。 核心としては、CursorやClaude Codeなどで実装されているPlanモードで実装計画とレビューを挟むことで、AIの出力を高品質にし、手戻りを減らす開発スタイルを言語化したものです。 コンテキスト用意の部分を解説します。 ガードレール設計 リポジトリ毎に規約が決まっていることが多いので、その参照を持たせます プロンプティング 役割や制限事項を含めた命令文を書きますが、コンテキストはガードレール、Design Doc、MCPサーバで補完できることが多いため、プロンプトの分量はそれほど多くなりません Design Doc作成 DB設計書、API設計書など必要に応じて設計書を作成します MCPサーバ接続 Figma MCPやGitHub MCPを利用して外部のコンテキストを取得します AIエージェント、推論モデルは目まぐるしく変化するため、そこに依存せず中長期的に運用できる内容を目指して作成しました。 AI開発標準v1.0は、フィードバックと改善が活発に行われ、知見が共有されたり目線が揃ったことで、個々人の生産性には多少の変化がありました。 しかしチームで提供する価値の面では大きな成果は上がりませんでした。 なぜならば、資料の説明は抽象的で、かつ現在地を示したに過ぎず、チームも具体的に動きようがなかったからです。 チームの課題や生産性のボトルネック、理想とする開発体験など、「なぜやるのか(Why)」「何をやるのか(What)」「どう実行するのか(How)」が、全くもって抜けていました。 この成果物は開発手法の共通項を抜き出したガードレールになっただけでした。 ガードレールがあるのは良いのですが、チームの状態としては相互理解や知見が少々増えて開発が楽になったに過ぎず、会社が「期待以上だった」と評価を下せるほどの成果ではありません。 スクラムに着想を得た推進の勘所 ここでふと、今まで長期に渡り実践してきたスクラム開発を思い出しました。 スクラム開発ではプロダクトゴールとスプリントゴールを設定して不確実性が高い環境でも継続して価値提供を実行します。 先ほど反省した通り、中長期の組織的な取り組みにもゴールとマイルストーンを設定し、計画的に進めることが大事なのだと気づくことができました。 日々やっているはずなのに、なぜできなかったんだろう、忘れてしまったんだろう…と落ち込みましたが、今では伸びしろだと考え直しています。 気づくといろいろなものが見えてきて、何をすべきかがわかります。 最近、上司から的確なフィードバックをもらいました。 「今のままでも前に進むとは思いますが、ゴールと計画を具体化した方がいいですね」 まさに!です。 まず、理想の開発体験をチームで話し合ってみることに決めました。 議論を進めるうちにチームでは次の結論が出ました。 作業さえ切り出してしまえば、実装はボトルネックになっていない リファインメントで議論が発散する時間が長く、収束に時間がかかる場合がある AIにはビジネス戦略、顧客課題、ユーザーストーリーが渡っていない。 ドメインの知識を詰め込んだGeminiのGem、もしくはNotion AIを用意することで、期待に近い出力を得ることができそうだ AIの出力が微妙な時は、整理されたコンテキストが足りていないことが多い。 仕様の記述もAIを中心に進め、レビューを開発者が行えば、質とスピードが担保できそうだ。 これらを満たすSDD(仕様書駆動開発)に、投機的に取り組んでみる これにより、以前よりも一歩前に進むことができ、次の具体的な計画を立てることができます。 明確な成果に紐づけるところまでは達成していませんが、以前よりも議論が活発になり、開発体験をより良くしていく動きができるようになりました。 推進を着実に進める方法 今回の試行錯誤から得た学びを箇条書きにすると、 なぜ、なにを、どのように、を突き詰めて課題の解像度を上げること 動く前に今わかる範囲での計画を立てること( AIは手段であり、まずは解決したい課題とゴールを定義しないと空回りする ) AI技術を定期的に取りこんでチームに適用してみる活動を行い振り返るループを作ること 何よりも自分自身がワクワクすること これは推進に限らず、あらゆる仕事で通じることですが、改めて勉強になりました。 抽象的な仕事を具体化して進めるコツが掴めたような気がします。 世には最近読ませていただいた ” **抽象度の高い仕事の進め方 ”** のように勉強になる記事がたくさんあるので、ぜひご覧になってください。 まとめ ここに至るまで、チームメンバーと上司、ストーリー上では触れなかった方々も含め、ご助力いただきありがとうございます。ここで感謝の意を表したいと思います。 引き続きワイワイ楽しみつつ一緒に進めていきましょう。 私はまだインパクトの大きい価値を生み出せてはいませんが、 推進のためにやることが明確になったので引き続き取り組んでいきます。 最後に、この記事を読んでくれた方の推進力になることを願っています。 ここまで読んでいただき、ありがとうございました! タイミーには、こうした挑戦と学び、そして発信を歓迎する文化があります。 ともに挑戦し成長していきたい方、興味があればぜひ1度お話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
こんにちは、タイミーのプロダクトアナリティクスチームでプロダクトのデータ分析をしている松下です。 この記事は Timee Advent Calendar 2025 シリーズ 2 の22日目の記事です。 はじめに 私の趣味はランニングで、仕事はデータアナリストです。 ランニングウォッチをつけてランニングをしていると多くのデータが溜まっていきます。 GarminDB という、 Garmin Connectからデータをダウンロードしてパースするライブラリを見つけたので、データベースに入れて改めてデータ分析をしてみました。 すると仕事で大事にしていることが、そのままランニングにも当てはまることに気づきました。 見るべき指標を選ぶこと 平均ではなく分布を見ること データの向こう側にある情報を処理すること どれもデータ分析の鉄則です。やっぱりそうだよな、と思いながら分析を進めていきました。 この記事では、ランニングデータの分析を通じて改めて実感した、データ分析で大事にすべきことについて書きます。 いつものランニングコース。車が少ない川沿いを走るのが好きです。 ランニングデータを分析してみた 最近のランニングウォッチはデータの宝庫です。 私はGarminのランニングウォッチを使っていますが、走るたびに以下のようなデータが溜まります。 距離、ペース、タイム 心拍数(平均、最大、ゾーン別の時間) ケイデンス(ピッチ) 気温 標高差 トレーニング効果、負荷 etc... BigQueryに自動同期する仕組みを作った GarminのデータをBigQueryに入れるために、以下のライブラリを活用しました。 github.com AIの力を借りながらパイプラインを構築できました。データを集めるハードルは、AI時代にどんどん下がっています。 github.com データで見えること①:見るべき指標を選ぶ 心拍数ゾーンでトレーニングする方法 ランニングには「心拍数」でトレーニングする方法があります。 心拍数ゾーンとは 心拍数を最大心拍数に対する割合で5段階に分けたもの。 ゾーン1(50-60%):ウォーミングアップ、回復走 ゾーン2(60-70%):脂肪燃焼、持久力向上。会話できるペース ゾーン3(70-80%):有酸素能力向上 ゾーン4(80-90%):乳酸閾値付近、レースペースに近い ゾーン5(90-100%):最大努力、短時間のみ維持可能 「ゾーン2で長く走る」トレーニングは、体への負担を抑えながら持久力を高める方法として人気があります。Garminのウォッチも心拍数ゾーンをリアルタイムで表示してくれます。 でも、私はペースを見ることにしました。 心拍数トレーニングにしっくりこなかった理由はシンプルです。 レースで求めているのは「心拍数」ではなく「タイム」だから。 心拍数は体調、気温、睡眠、ストレスによって大きく変動します。同じゾーン2でも、調子が良い日は5:30/km、悪い日は6:30/kmになることがあります。これでは「今日どれくらい走れたか」がわかりません。 一方、ペース(タイム)は嘘をつきません。5:00/kmで10km走れたら、それは紛れもなく「5:00/kmで10km走れる体」ができているという証拠です。 これは仕事でも同じ 見るべきは「施策を打てる指標」であり、「結果に直結する指標」です。 DAU(デイリーアクティブユーザー)を追っていても、それだけでは何をすればいいかわかりません。一方で、「新規ユーザーの7日後継続率」なら、オンボーディング改善という施策につながります。 心拍数は「体の状態」を表すデータ。ペースは「結果」を表すデータ。アマチュアランナーの私にとって、追うべきは後者でした。 データで見えること②:平均の罠と比較の重要性 練習の平均ペースを比較してみた 「じゃあペースで何を見ればいいのか?」 まず、レース前3ヶ月の練習の平均ペースを比較してみました。 レース 練習の平均ペース レース結果 熊本城マラソン2024 5:19/km 3:17:50(4:38/km) さいたまマラソン2025 5:08/km 3:16:51(4:36/km)ベスト つくばマラソン2025 6:27/km 3:29:28(4:56/km) 速く練習したほうが速いタイムで走れそうですが、ここはアナリストなら平均の罠が隠れていることに気がつくと思います。 平均の中身を見る 練習のペースを「速い(5分/km未満)」「中程度(5-6分/km)」「遅い(6分/km以上)」に分類して、その割合を見てみました。 レース レースペース 速い練習(%) 遅い練習(%) 総距離 さいたまマラソン2025 4:36/km 38.6% 2.8% 598km 熊本城マラソン2024 4:38/km 30.8% 0% 844km つくばマラソン2025 4:56/km 26.2% 29.6% 906km 発見 ベストが出た時(さいたまマラソン、熊本城マラソン)は、速い練習の割合が30%以上、遅い練習は0-3% つくばマラソンは練習量906km(最大)だが、遅い練習が29.6%もあり、ベストは出なかった 平均だけ見ても「中身」がわからない 熊本城マラソン2024の練習平均ペースは5:19/km。一見、ゆっくり目に練習しているように見えます。 でも中身を見ると、 速い練習30.8%、遅い練習0% 。緩急をつけた質の高い練習をしていました。 つくばマラソン2025の平均ペースは6:27/km。こちらも「ゆっくり練習」に見えます。 でも中身は、 速い練習26.2%、遅い練習29.6% 。遅い練習が多すぎて、平均が下がっていただけでした。 平均だけ見ても「遅い練習が多いのか」「緩急をつけているのか」わからない。分布を見なければ意味がない。 これも仕事で経験済み CVRの平均が上がっても、新規ユーザーだけ上がって既存が下がっていたら? 売上の平均単価が上がっても、高単価商品だけ売れて低単価商品が売れなくなっていたら? 平均だけを追うと、重要な変化を見落とします。 データだけでは見えないもの 身体性の重要さ ランニングデータを分析して一番再確認したのは、 身体性の重要さ でした。 心拍数180の苦しさは、データで見る「180bpm」とは全く違う体験です。 データを見る人と、実際に経験している人では、同じ数字を見ても解釈が全く違う。 これは仕事のデータ分析でも同じです。 自社サービスを自分で使う - ユーザー体験を肌で感じる 生ログを500件くらい見てみる - データの「手触り」を知る ユーザーインタビューに同席する - 数字の向こう側にいる人を想像する 商談・カスタマーサポートに同行する - なぜ契約が決まる/決まらないかを体感する データに現れる「前の段階」の手触りを知ることが、良い分析の前提条件だと思っています。 これは頭ではわかっていたことです。でも、自分のランニングデータを分析して、改めて強く実感しました。 おわりに AIには難しいこと 身体性は今のところAIが持つのは難しい領域です。 AIはデータを高速に処理し、パターンを見つけ、予測モデルを構築できます。SQLも書けるし、可視化もできる。正直、データを見る作業の多くはAIに代替されつつあります。 しかし、AIは自社サービスを使ったことがありません。ユーザーの不満を直接聞いたことがありません。 データの「手触り」を知っているかどうか。これが、AIと人間のデータアナリストを分ける決定的な違いになると思います。 データの手触りを大事にしながら、プロダクトに向き合いたい方。 ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
ogp こんにちは。データエンジニアリング部 DRE(Data Reliability Engineering)グループの つざき(tsu-san) です。 この記事は「 Timee Advent Calendar 2025 」シリーズ3の21日目の記事です。 今回はDREグループで導入したGoogle Cloudの PAM(Privileged Access Manager) についてご紹介します。 AIエージェントにGoogle Cloudの「権限」を預ける怖さ 最近DREグループ内では、開発効率を上げるために ローカル実行型 の AIコーディングエージェント(Claude Code / Cursorなど) を積極的に活用していこうという動きがあります。 ローカル実行型のAIコーディングエージェントは、実行ユーザーのローカル認証情報を使って自律的にコマンドを実行します。つまり、 ユーザーが持っている権限の範囲で、AIコーディングエージェントがGoogle Cloudのリソースにアクセスできてしまう 状態になります。 人間が毎回チェックすれば良いという話もありますが、AIが生成した複雑なコマンドを完璧にノータイムでチェックし続けるのは、精神的にもかなりの負担です。 「普段は閲覧のみ、必要なときだけ必要な権限を」へ タイミーのインフラ変更は Terraform + CI/CD が基本であるため、通常時は閲覧以外の権限は不要なはずです。しかし、現実には以下のような「編集権限が必要な瞬間」も存在します。 障害対応時の緊急オペレーション Terraform化されていないリソースの調査や一時的な変更 「AIを安全に使いたい」けれど、「いざという時は動きたい(=権限が必要)」。このニーズを解決するために導入したのが、Google Cloudの PAM(Privileged Access Manager) です。 Google CloudのPAM(Privileged Access Manager)とは PAMは、一言で言うと 「権限の時限付き貸し出し機能 」を実現する仕組みです。 特定の権限を、 「必要な時だけ」「承認を得て」「指定した時間だけ」 ユーザーに付与することができます。 PAMを導入して良かったこと 編集権限の完全廃止: 普段は閲覧権限のみにしておける。AIエージェントが万が一暴走しても、そもそも権限がないので被害が出ない。 監査ログの強化: 「誰が」「いつ」「何の目的で」権限を昇格させたかが明確にログに残る。 スムーズな承認フロー: チーム内での承認プロセスをGoogle Cloudの標準機能として組み込める。 導入後のフローと使用感 PAMのフロー図 導入後は、権限が必要になったらGoogle Cloudコンソールの「特権アクセス管理」画面から申請を出します。 申請: 理由を書いてリクエストを送信。 承認: チームメンバーに通知が届き、コンソール上で承認ボタンを押す。 作業: 承認された瞬間から権限が有効化される。 自動終了: 設定時間が過ぎれば、自動で権限が剥奪される。 このフローのおかげで、普段の作業でAIエージェントがうっかり破壊的な指示を出したとしても、物理的に権限がないのでエラーで止まってくれます。この「ガードレールがある安心感」は、開発スピードを落とさないためにも非常に重要だと感じています。 PAMで解決したこと PAMの導入により、DREグループでは以下の状態を作ることができました。 AIエージェントを安心して活用できる: 通常時は閲覧権限のみ、誤爆のリスクがなくて安心 運用の機動力は犠牲にしない: 緊急時はPAMで即座に権限を昇格できて安心 うっかりを仕組みで防ぐ: 人間もAIもミスをする前提で、システム側で安全性を担保できて安心 まとめ AIコーディングエージェントは非常に強力な武器ですが、編集権限を持った状態では安心して利用できません。 DREグループではPAMの利用により「緊急対応の迅速さ」と「最小権限」を両立することができ、AIと人間が安心して開発が可能な環境に近づくことができました。 「AIをフル活用したいけれど、編集権限を持っているのが不安」という方は、ぜひGoogle CloudのPAMを活用して、安全なAI開発環境を構築してみてはいかがでしょうか。 明日のアドベントカレンダーもお楽しみに! もし本記事やDREの取り組みにご興味があればぜひお話ししましょう! カジュアル面談申込はこちら プロダクト採用サイトTOP 付録:Terraformでの設定例 Terraformでの記述例を紹介します。 この例ではDREグループのメンバーが、必要に応じて「承認」を経てWriter権限をリクエストできるように構成しています。 # 1. PAMサービスエージェントへのIAMロール付与 resource "google_organization_iam_member" "pam_service_agent" { org_id = var.organization_id role = "roles/privilegedaccessmanager.serviceAgent" member = "serviceAccount:service-org-$ { var.organization_id } @gcp-sa-pam.iam.gserviceaccount.com" } # 2. 特権アクセスの設定(Entitlement) resource "google_privileged_access_manager_entitlement" "dre_admin" { entitlement_id = "dre-admin-entitlement" location = "global" max_request_duration = "3600s" # 最大1時間 parent = "organizations/$ { var.organization_id } " # 権限をリクエストできる対象(DREグループのアドレス) eligible_users { principals = [ "group:team-dre@example.com" , ] } # 一時的に付与する権限 privileged_access { gcp_iam_access { role_bindings { role = "roles/writer" } resource = "//cloudresourcemanager.googleapis.com/organizations/$ { var.organization_id } " resource_type = "cloudresourcemanager.googleapis.com/Organization" } } # 承認ワークフローの設定 approval_workflow { manual_approvals { require_approver_justification = true steps { approvals_needed = 1 approver_email_recipients = [ "user:data-dre-manager@example.com" , # 承認者 ] } } } # リクエスト時の理由入力を必須にする requester_justification_config { unstructured {} } depends_on = [ google_organization_iam_member.pam_service_agent ] } 実際に設定する際は、ユーザが作業に必要な最小の権限を付与するのが望ましいので、たとえば roles/bigquery.admin のようなサービスごとに権限を付与する特権アクセス設定を作成しましょう。
この記事は Timee Product Advent Calendar 2025 21日目の記事です。 データエンジニアリング部DSグループ所属の藤井と申します。現在タイミーで推薦エンジンの改善に取り組んでいます! この記事では、タイミーの推薦エンジンにおける候補生成で導入している ANN(Approximate Nearest Neighbor)と、その ANN用ベクトルを作る Two-Tower モデルを題材にします。そして、このドメインで重要なテーマのひとつである Negative Sampling 、特に In-Batch Negative Sampling を使ったモデル開発における課題と対策について議論していきます。 ANNはRAG(Retrieval-Augmented Generation)のバックエンドにおいても使用されることが多いので、ぜひ読んでいただけると嬉しいです! Two Towerモデル利用の背景 ここからは Two-Tower モデルの話に入っていきます。 推薦エンジンで推薦を行う際、推薦対象となる item v をすべての user u に対して brute force で厳密に計算すると、組合せ爆発により計算量が となってしまいます。そのため、件数が増えるにつれて、現実的なコストでは計算することが難しくなっていきます。 例として、日本の大学生300万人に対し、100万冊の本からベストな本を推薦する状況を考えましょう。この場合、「300万人×100万冊」で3兆通りもの組み合わせが生じてしまいます。推薦エンジンでの重たい計算や、LLM への API コールが必要なケースでは、このように全件をそのまま計算すると、非現実的なコストがかかる可能性が高いです。 ここで挙げた例のように、item数とuser数の組み合わせが多くなるケースでは、何らかの方法でうまく候補を抽出し、計算量を削減する必要があります。 この計算量の問題に対処するため、タイミーではANNおよびANNに使う推薦用のベクトル(埋め込み)を生成するために Two-Tower モデルを利用しています。 Two-Tower モデルと InfoNCE Loss のおさらい Two-Tower モデルでは、損失関数として InfoNCE Loss がよく使われます。 以下の InfoNCE Loss の式は、In-Batch Negative Sampling(「同じミニバッチ内の他アイテムをネガティブとして扱う」設定)を仮定した形になっています。 ここで、 : バッチ内 i 番目のユーザのベクトル : そのユーザに対する正例(ポジティブ)アイテムのベクトル : バッチ内に含まれる任意のアイテムのベクトル : コサイン類似度などの類似度関数 : 温度パラメータ : バッチサイズ 分子は「ユーザ と、そのユーザに対する正例アイテム との類似度」を、 分母は「同じバッチ内に存在するすべてのアイテム との類似度の総和」を表しています。 この式から分かるように、 どのサンプルをネガティブとして扱うか は InfoNCE の性能に直結する重要な設計要素であり、これまでに多くの研究が行われています。 本記事では、このうち Two-Tower モデル × In-Batch Negative Sampling という設定にフォーカスして話を進めます。 In-Batch Negative Sampling とは In-Batch Negative Sampling とは、あるユーザ に対して「 同じミニバッチ内の他ユーザの正例アイテム 」をネガティブサンプルとして兼用する手法です。 この方法では、ミニバッチ内で既に計算したアイテム埋め込みを負例として流用できるため、 負例のために追加でアイテムをサンプルして埋め込み計算(forward)するコストを抑えつつ 、多数のネガティブと比較できます。InfoNCEでは一度に複数のサンプルを比較するため、Negative Sampleの計算コストが無視できなくなる傾向にあります。 以下は具体的な手法です。 先ほどの InfoNCE の式の文脈でいうと、ユーザ ui に対して 正例(ポジティブ): ネガティブ: (同一バッチ内のその他のアイテム) という対応付けになります。(図1参照) 図1.In-Batch Negative Samplingイメージ図。 厳密には、バッチ内の他サンプルが「同一アイテム」または「同一ユーザのペア」である場合、False Negative となるのを避けるために、損失計算から除外(マスキング)する処理を行うのが望ましい ここからが本題です。 この In-Batch Negative Sampling + InfoNCE の構成は Two-Tower モデルの文脈において非常に一般的な構成ですが、実際のモデル開発においてはいくつか考慮すべき課題があります。 今日は、その課題の一部と対策例を議論していきましょう。 課題1: バッチサイズへの強い依存 InfoNCE Loss には、「相互情報量 I(X;Y) の下限を与える」というよく知られた評価式があります。[1] ここで N は「1 つの正例と一緒に比較されるサンプルの総数」です。 (* 厳密には独立負例を仮定して導かれる下界であり、in-batch negatives ではその仮定が必ずしも成り立たない点に留意されたい。) In-Batch Negative Sampling の設定では、1 ユーザあたりの比較対象はほぼ「バッチサイズ B 個」になるため、バッチサイズが小さいと、到達しうる相互情報量の下限も小さくなってしまいます。 その結果、モデルの性能がバッチサイズに強く依存するという問題が生じます。 対策例: 1. MoCo 型のメモリバンク / キュー この問題への対策一つが、MoCo に代表されるメモリバンク(キュー)方式です[2][3][4]*。 過去バッチのアイテム埋め込みをキューとして保持しておき、 現在バッチのユーザ埋め込みと比較するときに、そのキュー内の多数の埋め込みをネガティブとして利用する ことで、実効的なネガティブ数 Nを「バッチサイズ」ではなく「キュー長」まで拡張できます。 これにより、大きなミニバッチを組まなくても、多数のネガティブを確保しつつ学習できるようになります。 一方で、実装上のハードルは比較的高く、導入にあたっては慎重に検討する必要があります。 厳密には、最新の MoCo v3 [4] ではモデル構造の単純化(ViTへの適応)のためキュー(Memory Bank)は廃止され、SimCLRと同様の大規模バッチ学習に戻っていますが、同シリーズの重要な発展形として併記しています。 * 課題2: 出現頻度に由来するバイアス In-Batch Negative Sampling は「バッチに出てきたアイテム」をそのまま負例として使うため、バッチに登場しやすい=出現頻度の高いアイテムほどネガティブとして選ばれやすいというバイアスがあります。 その結果、人気アイテムは不当に類似度を押し下げられやすくなります。一方で、低頻度アイテムはそもそもネガティブとして登場しにくいため、学習で受けるノイズ(更新)が弱くなるという問題が生じます。 タイミーの文脈では、単なるアイテムの人気度だけでなく、エリア(地理)や職種によっても出現頻度が大きく異なるため、同様の構造のバイアスがより複雑な形で入り込みます。 対策例: 1. LogQ Correction In-Batch Negative Sampling では、popularity bias によりスコアがサンプリング確率 (学習時に負例としてサンプルされるアイテムvの周辺確率)に引きずられ、以下の形に収束してしまいます。 ここで r ( u , v ) は真の関連度を表します。 そこで、ロジットを としてあらかじめバイアス項を差し引くことで、人気度に依存しない本質的な関連度を学習させます[5]。 2. ランダムサンプリングによるネガティブ補完 In-Batch Negative Sampling だけに依存せず、別途ランダムサンプリングしたネガティブを足す/混ぜることで、人気アイテムだけにネガティブが偏らないようにする、というアプローチもあります。 この対策は比較的実装ハードルが低いです。 課題3: False Negative In-Batch Negative Sampling では、本来はポジティブであるべきアイテムがネガティブ側に紛れ込む(False Negative) ことが、かなりの確率で起こります。 有効バッチサイズやネガティブ数を増やしていくほどその発生頻度も上がるため、現実的には「避けきれないが、無視もできない」やっかいな問題です。 InfoNCE では、学習が進むと多数の easy negative はほとんど loss(=勾配)に寄与しなくます。そのため、性能を上げるには hard negative をしっかり集めることが重要になります。 しかし、良い hard negative ほどポジティブとの境界付近に位置するため、hard negative を攻めるほど False Negative を混入させやすくなるというトレードオフがあります。 False Negative が多いと、 本来近づけたいユーザ–アイテムのペアを、loss が「離せ」と強く押してしまう 結果として、似たアイテム同士が不自然に遠ざかり、リコールや一般化性能を削ってしまう といった形で、表現学習全体に悪影響が出ます。 筆者としては、False Negative の発生自体はある程度は仕方ない前提だと考えており、 「False Negative を完全に消しに行く」よりも、それによって勾配が暴れすぎないようにコントロールする仕組みを重視したいスタンスです。 図2. False Negative(=本来はPositiveとすべきSample)とHard Negative/Easy Negativeの位置関係のイメージ。一般的にFalse NegativeとHard Negativeは隣接しており、良質な境界ギリギリのHard Negative得ようとすると、同時にFalse Negativeを取得してしまうリスクが上昇する。 対策例: 1. Debiased InfoNCE (統計的な補正) 「ネガティブサンプルの中には一定確率 π でポジティブが混ざっている」という仮定を置き、Loss の分母からポジティブ成分の期待値を差し引くことでバイアスを除去する手法です [6]。 これにより、FN を無理やり遠ざけようとする誤った勾配の発生を統計的に抑制します。 2. False Negative Masking (高スコアの無視) 学習が進むと、モデルは FN(ラベルは負だが実は正例)に対して高い類似度スコアを出すようになります。 これを利用し、バッチ内のネガティブサンプルのうち、スコアが閾値を超えた(=モデルがポジティブだと確信している)ものを Loss 計算から除外(Masking)します [7]。 「怪しいものは学習に使わない」という割り切りにより、外れ値的な勾配によるモデル崩壊を防ぎます。 一方で、閾値が恣意的になりやすく、この閾値をどのように定義するかに難しさがあります。 おわりに ここまで、幾つかの課題とその課題に対する対策例を挙げてきましたが、モデルを学習する状況やデータによって、相応しい対策は異なります。手法をきちんと理解した上で運用することで、より良い候補生成用のベクトルを作っていきたいです。 We’re Hiring! タイミーではデータサイエンティストをはじめ、一緒に働くメンバーを募集しています! カジュアル面談 も行なっておりますので、興味のある方はぜひお気軽にお申し込みください! product-recruit.timee.co.jp 現在タイミーでは推薦エンジンを一緒に改善していくメンバーを募っております。 参考文献 [1] [1807.03748] Representation Learning with Contrastive Predictive Coding [2] [1911.05722] Momentum Contrast for Unsupervised Visual Representation Learning [3] [2003.04297] Improved Baselines with Momentum Contrastive Learning [4] [2104.02057] An Empirical Study of Training Self-Supervised Vision Transformers [5] Sampling-Bias-Corrected Neural Modeling for Large Corpus Item Recommendations [6] [2007.00224] Debiased Contrastive Learning [7] [2010.08191] RocketQA: An Optimized Training Approach to Dense Passage Retrieval for Open-Domain Question Answering
こんにちは!タイミーでバックエンドエンジニアをやっている福島です。この記事は Timee Product Advent Calendar 2025 の20日目の記事です。 みなさんは普段リファクタリングにどれくらい時間を割いていますか? 将来的な品質や開発スピードを担保するためには定期的なリファクタリングが必要ですが、普段の業務が忙しくてなかなか時間を割けない方も多いと思います。 そこで今回は、AIを活用して効率よくリファクタリングできないかを検証してみたので、その振り返りを兼ねてご紹介したいと思います。 リファクタリングの進め方 今回のリファクタリングは、直近取り組んでいた機能開発に関連するコードを対象にしています。 Cursorのチャットスペースを使い、以下の手順で進めました。 リファクタリング候補の洗い出し リファクタリング箇所の選定 実装方針を決定 実装 テストのカバレッジを確認 リファクタリング実装 テストの追加 リファクタリングの実践 先述した進め方に沿って、実行結果をまとめます。 1. リファクタリング候補の洗い出し AIに以下のプロンプトを投げて、リファクタリング候補を優先度順にまとめてもらいました。 機能Aの中でリファクタリングできそうな箇所、共通化できそうな箇所などを洗い出して、優先度順にまとめてください。 観点に以下を含めてください。 - 問題点 - 改善案 - 期待される効果 - 工数 優先度は以下の順で検討してください。 1. 保守性向上につながるか 2. 対応工数低めで対応できるか AIの回答(一部抜粋) ### 1. シリアライザー間のXXXロジックの共通化 - 対象ファイル: - … - 問題点: 同一ロジックが重複 - 対応案: ${クラスA}に${メソッドA}を追加し、シリアライザーから呼び出す - 効果: 変更箇所が1箇所に集約、保守性向上 - 工数: 1-2時間 ... ### 8. 有効期限計算ロジックの集約 - 対象ファイル: - … - 問題点: 有効期限計算が複数箇所に分散(TODOコメントあり) - 対応案: ${クラスA}を作成し、計算ロジックを集約 - 効果: 計算ロジックの一元化、テスト容易性向上 - 工数: 3-4時間 ... ## 推奨対応順序 1. 優先度:高の1-4を順次対応(合計5-8時間) 2. 優先度:中の5-7を対応(合計4-6時間) 3. 優先度:中-低の8-10は必要に応じて対応 特に優先度:高の1-4は対応工数が少なく、保守性向上の効果が大きいため、優先して対応することを推奨します。 トータルで12箇所ほど挙げてくれました。問題点と改善案も提示してくれたため、調査にかかるコストはかなり削減できたと思います。 2. リファクタリング箇所の選定 リファクタリングの優先度を検討した結果、「8. 有効期限計算ロジックの集約」を最初に着手することを決定しました。 主な観点は以下の通りです。 TODOコメントが残り(チーム内で既に問題意識がある) 設計の健全性を大きく損なっている 優先度に関しては、AIと人間の認識にズレが生じる結果になりました。 要因としては以下が考えられます。 対応工数に関する影響が大きくなってしまった AIに実装を任せるので、多少の差分は無視できる前提で指示するべきだった TODOコメントも考慮に加え、顕在的な課題として評価できると良かった ここは人間の判断基準を詳細に言語化して、プロンプトを磨き込む余地がありそうです。 3. 実装方針を決定 リファクタリング箇所が決まったので、「8. 有効期限計算ロジックの集約」の実装方針についてAIにサンプルコードを出力してもらい、それをレビューする形で方針を固めていきました。 主な観点は以下の通りです。 本当にリファクタリングの価値があるか 保守性向上につながる有効な共通化になっているか 逆にコードの可読性を損なっていないか やりたいことに対して必要最低限の差分になっているか また、この時点で「本当にリファクタリングの価値があるか」を再度見直すことも重要だと感じました。 例えば「1. シリアライザー間のXXXロジックの共通化」の実装方針を検討する際、いくつかの実装パターンを提示してもらいました。しかし、どれも局所最適な共通化に留まり、長期的な保守性向上にはつながらないことが判明しました。 こういったケースについても、実際のコードを見ながら解像度高く判断することで、無駄な実装を避け、効率的なリファクタリングにつなげることができます。 4. 実装 実装フェーズは3ステップに分けて進めます。 a. テストのカバレッジを確認 リファクタリングは、「ソフトウェアの外部から見たときの動作を変えずに、コードの内部構造を改善する作業」です。外部から見たときの動作が変わらないことを担保するため、まずはテストのカバレッジが十分かどうかをAIにチェックしてもらいます。 AIの回答(一部抜粋) ## テストカバレッジの評価 ### 十分にテストされている箇所 1. モデルAのメソッドa: 境界値テストあり 2. モデルBのメソッドa: 複数パターンのテストあり ### テストが不足している箇所 1. モデルAのメソッドb: 直接テストなし(xxx経由で間接的にテスト) 2. モデルBのメソッドb: ユニットテストなし(APIテストのみ) テストが不足している箇所を挙げてくれましたが、間接的にテストされており、必要なパターンは網羅されていたので、問題なしと判断しました。 b. リファクタリング実装 テストが十分だと確認できたら、安心してリファクタリングを実装できます。 実装方針についても既にすり合わせていたので、ほとんど手戻りなく完了しました。 c. テストの追加 最後に、今回は新規クラスを追加したので、その単体テストを追加してもらいました。 これで実装フェーズはコンプリートです。 結果として、有効期限計算ロジックを1箇所に集約することで、保守性とテスト容易性が向上しました。 クラス 変更前の主な責務(Before) 変更後の主な責務(After) 改善効果 Model A ステータス判定 有効期限の計算・判定 ステータス判定 単一責任の達成。 本質的なロジックに集中。 Model B ログ記録 有効期限の計算・判定 ログ記録 疎結合化。 インフラ層からドメインロジックを分離。 Serializer 表示フォーマット 有効期限の計算・判定 表示フォーマット 表示層の純粋化。 計算ロジックを排除。 Model C(新規) N/A 有効期限計算の集約 ロジックの変更箇所が1箇所に集約。 やってみた感想 調査の工数をほぼ0にできた どこを、なぜリファクタリングするのか 安全にリファクタリングできるか(テストは十分か) といった点を調査してまとめるのは、本来時間のかかる作業ですが、ここをAIにサクッとやってもらえたのは良かったです。 優先順位は人間の判断が必要 今回、AIが優先度低めに設定していたリファクタリングを最初にやる判断をしました。 先述したように、優先度の判断基準に関する指示は改善の余地がありそうです。 それに加えて、機能開発と並行してリファクタリングを進める場合、「現在進行中の開発とコンフリクトしないか?」という観点も必要になると思います。 リファクタリングの都合で機能開発のスピードを落とすわけにはいかないので、チームの開発事情と照らし合わせて判断できると良いですね。 チームでどう運用していくか リファクタリングは一度やって終わりではなく、継続してやっていく必要があります。 今回の取り組みを通して、工数をかけず安全にリファクタリングする手順は確認できました。 今後はチームとして安定したコード品質、開発スピードを担保するため、以下の2つに取り組んでいきたいと思います。 技術負債を可視化してチームで共通認識を持てるようにする 機能開発と並行したリファクタリングの実施を、チーム開発のサイクルに落とし込む さいごに この記事では、AIを活用したリファクタリングの実践例をご紹介しました。 AIの支援により、調査工数を大幅に削減しながら、安全にリファクタリングを進めることができました。一方で、優先順位の判断やチーム開発との兼ね合いなど、人間の判断が必要な部分も明確になりました。 今後もAIを上手く活用しながら、チーム全体でコード品質を維持・向上させていく取り組みを続けていきたいと思います。 AIを活用した開発改善や、チームでの継続的なコード品質向上に興味がある方、ぜひ一緒にお話ししませんか? プロダクト採用サイトTOP カジュアル面談申込はこちら
はじめに こんにちは。タイミーでエンジニアリングマネージャー(EM)をしているshuです。 (本記事は Timee Advent Calendar 2025 シリーズ3の19日目の記事になります。) 最近、社内のEMたちとHeidi Helfand氏の著書『ダイナミックリチーミング(Dynamic Reteaming)』の輪読会を行っています。この本は、従来の「チームは固定化されるべき」という常識を覆し、チーム編成を動的に変えることで組織の健全性と成長を促す手法について書かれた良書です。 読み進める中で、今年自分がアサイン責任者として対応した大規模プロジェクトの記憶が鮮明に蘇ってきました。 「あれ? あの時、必死で判断して実行したあの体制変更、まさにこの本に出てくる『アイソレーションパターン』そのものじゃないか?」と。 今回の記事では、今年発生した緊急プロジェクトでの実践を振り返りつつ、アイソレーションパターンの有効性と、そこで得られた「残された側のチームに起きた意外な副産物」についてシェアしたいと思います。 突発的な大規模プロジェクトと、急造チームの決断 今年、私が担当する領域で、大規模プロジェクトが突発的に立ち上がりました。 その性質は、EMにとっては胃が痛くなるようなものでした。 影響範囲が極めて広範囲に及ぶ 絶対に動かせないハードデッドラインがある 既存チームが片手間でこなせる量ではない 私はこのプロジェクトの立ち上げとチーム組成を担当することになりましたが、プロジェクトの性質に加え、タイミーのシステム特性や現在の開発チーム体制などを総合的に鑑みて、「既存の運用体制のままでは絶対に間に合わない」と判断しました。 そこで断行したのが、あるチームをベースにしつつ、プロジェクトに必要なドメイン知識やケイパビリティを持つメンバーを様々なチームから招集し、専任の「急造チーム」を組成するというリチーミングです。(個人的には、各チームの状況を鑑みながらメンバーを出してもらう、この調整業務が本当に非常に大変でした…) 後から本を読んで整理できたのですが、これは「アイソレーションパターン」と呼ばれる手法そのものでした。 アイソレーションとは、チームを意図的に切り出して分離・隔離し、既存のプロセスやルールから解放された違うやり方で仕事を進める自由を明示的に与えるパターンです。 主な目的: イノベーション: 新しい大胆なアイデアの追求 緊急事態: 予期しない問題への集中対処 停滞の打破: プロセスが重くなった「硬直化の罠」からの脱出 アイソレーションパターン このパターンについては、一般的な推奨事項は5つ紹介されています。その中で自分が重要だと考えているのが、以下の3点です。驚いたことに、今回の急造チームは無意識のうちにこれらのセオリーをなぞっており、それぞれがプロジェクトの成功に大きく寄与していました。 1. 専用スペースへの移動 本では物理的な部屋への移動が推奨されていますが、弊社はフルリモート体制のため、これは「専用チャンネルへの集約」として実践されました。 メンバーを既存チームから引き抜くと同時に、専用のSlackチャンネルを作成し、開発に関するすべてのやり取りや意思決定をそこで完結させるようにしました。オンライン上であっても、あたかも隔離された部屋にいるかのような没入環境を作り出すことで、コミュニケーションコストを最小限に抑えました。 2. プロセスの自由 「隔離」されたチームは、既存組織のルールに縛られず、最適なプロセスを選択できます。 タイミーの開発チームの多くは普段スクラム開発を採用していますが、今回のプロジェクトはハードデッドライン必達かつ手戻りが許されない状況でした。そこで、このチームに関しては普段のやり方に固執せず、PjM/PdMによる強力な進行管理のもと、ウォーターフォールに近い開発スタイルを採用しました。 このプロジェクト専用に最適化された独自のリズムで動くことで、迷いなくゴールへ突き進むことができました。 3. 邪魔をさせない メンバーが目の前の課題に集中できるよう、外部からの干渉を遮断することも重要です。 これについては、プロダクト組織のエグゼクティブ(CXOやVPoXなど)から、このプロジェクトが全イニシアチブの中で最優先事項であると定義・宣言してもらい、全プロダクトメンバーにその認識を持ってもらうことで実現しました。 トップダウンによる強力なバックアップがあったおかげで、他の運用業務や開発などの差し込みが入ることがなく、メンバーは余計なノイズに惑わされることなく開発に集中することができました。 当時は「間に合わせるためにはこれしかない」という必死の判断でしたが、結果としてアイソレーションパターンは極めて有効に機能し、厳しいデッドラインを守り切ることができました。 そして、このリチーミングにはもう一つ、私にとって嬉しい誤算とも呼べるポジティブな副産物がありました。 本には書かれていない「既存チーム」の進化 それは、EMとして最も懸念していた人を引き抜かれた側の状態についてです。 今回のケースでは、複数のチームからドメイン知識を持つメンバーが招集されました。私が管掌するチームからも、フロントエンド領域を専門とするメンバーが1人、プロジェクトにアサインされました。 専門領域を持つメンバーが抜けることで、「残されたチームでの開発は立ち行かなくなるのではないか?」という懸念がありました。 しかし、あくまで私の管掌範囲内での観測にはなりますが、蓋を開けてみると、そこには本には書かれていない意外な化学反応が起きていました。 1. 空白がオーナーシップを醸成 人が減ったことで、物理的にリソースが不足します。すると不思議なことに、「誰かが拾ってくれるだろう」という無意識の前提がなくなりました。 「自分が拾わないと落ちる」 そんな健全な危機感が生まれたように感じます。これはまさに、タイミーが大切にしている新しいバリューの1つ「ジブンゴト」が、極限状態で体現されたと思います。誰かに言われてやるのではなく、構造的な空白が、彼らのオーナーシップを引き出しました。 2. 越境文化がより強まった ここ1年半ほど、タイミーのSA(StreamAligned)チーム(※顧客価値に向き合う最小単位の開発チーム)では、領域を越境した開発が推奨されており、私自身もチームにそれを求めていました。特に今年は、AIコーディングツールの進化もあり、越境のハードル自体は下がっていました。 今回、フロントエンドの専門メンバーが抜けましたが、半分は意図的に、半分は状況的に、あえて即座にそのケイパビリティを持つバックフィルを用意しませんでした(もちろんうまくいかなかった時にサポートできるオプションは持ちつつ)。代わりに、メンバーにはこれを機に越境してほしいと伝えました。 その結果、移動したメンバーやFrontend Chapter(※職能ごとの横断コミュニティ)の力も借りながらではありますが、チームメンバー全体でフロントエンド領域のタスクを巻き取る動きが加速しました。リソースが足りないという状況が、結果としてチーム全体のフルスタック化を、実践レベルで前進させました。 3. MTGの発言量が爆増した 人数が多いMTGだと、どうしても一人ひとりの発言時間は少なくなってしまいがちです。 今回、リチーミングによりチーム人数が減ったことで、全員がより当事者としてスプリントゴールを目指す状況となりました。その結果、ほぼすべてのMTGでマイクをミュートにすることがなくなるほど、一人ひとりの発言量と議論の密度が劇的に向上しました。 まとめ:変化こそが、組織を強くする 今回の経験を通じて、アイソレーションパターンは単なる緊急時の対症療法ではないと痛感しました。 それは、重要なプロジェクトを成功させるための強力な武器であると同時に、既存チームに健全な揺らぎを与え、メンバーの新たな可能性を強制的に(しかしポジティブに)開花させるきっかけでもありました。 人が動くことで、組織全体の成果の総和は減るどころか、むしろ増える。 誰かが抜けた穴は、決してネガティブな空白ではなく、他の誰かが一歩前に踏み出すための「成長の余白」だったのだと思います。 本で理論を学び、現場で実践し、予想以上の成果を得る。EMとして、非常に学びの深い1年となりました。 組織の変化を恐れず、来年もダイナミックに挑戦していきたいと思います。 本質的な課題解決とメンバーの成長を両立させるダイナミックな組織運営に興味がある方、変化を楽しみながら成長したいと思っている方、ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
1. はじめに 本記事は Timee Product Advent Calendar 2025 シリーズ1 19日目の記事です。 こんにちは。株式会社タイミーでiOSエンジニアをしている hayakawa です。 普段はiOSアプリの開発を担当していますが、弊社では職種の垣根を超えて異なる技術領域に挑戦する「越境」が盛んです。また、開発プロセス全体でAI・LLMを活用する流れも加速しています。 今回は、自身の技術領域を広げるためと、チームのケイパビリティ向上のために、Androidの実装を担当しました。本記事では、その際の実践的な知見やAI活用のポイントについて共有します。 2. 筆者のAndroidに関する前提知識 実装開始時点での私のAndroidに関する知識レベルは以下の通りです。 言語: Kotlin(Swiftと似ているという認識程度) UI: Jetpack Compose(SwiftUIに近い宣言的UIフレームワークという認識)。また、従来はXML(iOSのXIBやStoryboardのようなもの)を使って構築する手法があることも、知識としては持っている。 非同期処理: Coroutines(CombineやSwift Concurrencyの概念で理解) 開発環境: Android Studio(基本的な操作方法も不慣れな状態) 「概念は理解しているが、具体的なAPIやIDEの操作は手探り」という状態からのスタートでした。 3. 今回挑戦した実装内容 今回担当したのは、以下の2つの機能実装です。 ① 条件に応じた注意書き表示ロジック サーバーレスポンスに含まれる「未来の時間情報」に基づき、UIを出し分ける機能です。 現在時刻から指定時間までの「残り時間」をカウントダウン表示する。 端末の「通知設定(ON/OFF)」を取得し、文言を切り替える。 ② 条件に応じたUI制御とデザインシステムの拡張 サーバーレスポンスに含まれる特定の値に基づき、View内のコンポーネントを制御する実装です。 デザインシステムに新たなカラーバリエーションを追加定義する。 既存のリスト表示(RecyclerView)の一部に、Jetpack Compose化したViewを組み込む。 組み込んだView内に追加のコンポーネントを表示する。 なお、同様の機能をiOS版でも私が担当しており、そちらは「実装1日、レビュー・マージまで2日」で完了しています。iOS版の実装時点では、Android版はキャッチアップも含めてその1.5倍ほどの工数で完了すると予想していました。 4. AI活用の勘所:メンタルモデルに合わせた翻訳 実装は Claude Code と協調して進めました。 ここで効果的だったのは、単にコードを書かせるのではなく、 「自分の持っているiOSの知識とマッピングさせる」 というプロンプトの出し方です。 プロンプトの工夫:「iOSエンジニア向けに説明して」 具体的には、以下のような指示を行いました。(※例なので実際に入力したプロンプトとは異なります) Prompt: 「{SwiftのAPI名}を使って {やりたいこと} を実装したい。これを {KotlinのAPI名} を使ったコードと、Swiftの概念と比較した実装方針とコードを提示して このように依頼することで、AIは「StateFlowはSwiftでいうCurrentValueSubjectに近い挙動です」といった補足を加えてくれます。これにより、単なるコピペではなく、挙動を正しく理解しながら実装を進めることができました。 5. ぶつかった技術的・文脈的な壁 AIの支援があっても、スムーズにいかない場面がいくつかありました。 ① RecyclerViewとComposeの共存 最も苦戦したのは、既存のRecyclerViewの中にJetpack Composeで作ったViewを組み込む部分です。 SwiftUIであれば UIHostingController 等で比較的直感的にブリッジできますが、Androidの既存実装(ViewHolder)の中に、ComposeViewをライフサイクル的にどのように正しく配置するか 、という点は構文の違い以上に「作法」の違いが大きく、AIの出力したコードをそのまま適用するだけでは、ビルドエラーやレイアウト崩れが発生しました。 ② モデル名の不一致(ドメイン知識の欠如) また、プロジェクト固有の「命名規則」の壁もありました。 例えば、iOSで定義されているモデル名が、Androidでは少し違う名前になっているケースがありました。 例) iOS: ServiceRequest Android: RequestedService 私がiOSの感覚で「 ServiceRequest を拡張して」とAIに指示すると、AIはプロジェクト内に RequestedService が存在することを知らないため、 新しく data class ServiceRequest を定義してしまいました。 これは「AIはプロジェクトの歴史や文脈までは(コンテキストに含めない限り)知らない」という典型的な落とし穴でした。 6. 人間(Androidエンジニア)との協調 AIが出力したコードは「動く」ものの、それが「保守性の高いコード」であるかは別問題です。 そこで、Androidエンジニアのチームメンバーに対して、「同期的な相談」の時間を設けてレビューを依頼しました。 この時、私が意識して聞いたのは「合っていますか?」ではなく、以下の質問です。 「期待通りに動くんですが、Androidの流儀としてもっと良い書き方はありますか?」 AIは汎用的な正解を出しますが、現場のベストプラクティス(例えば、よりモダンなライブラリの選定や、プロジェクト独自の拡張関数の活用など)は、人間の方が詳しいケースが多々あります。このプロセスを経ることで、コードの品質を担保しました。 7. まとめ 今回の挑戦で得られた知見は以下の通りです。 AIは「言語の壁」を限りなく低くする Swiftの知識があれば、適切なプロンプトでKotlinのコードを生成・理解することは容易です。 ドメイン知識とアーキテクチャの理解は人間が補う必要がある モデル名の違いや、既存コンポーネント(RecyclerView等)との整合性は、AI任せにせず人間がハンドリングする必要があります。 「もっと良い書き方」は人間に聞く AIで「0→80点」まで持っていき、最後の「80→100点(最適化)」を専門家との対話で行うスタイルが非常に効率的でした。 AIという強力なパートナーがいれば、iOSエンジニアにとってAndroid開発(あるいはその逆)は、もはや高いハードルではありません。今後も積極的に技術領域を越境していきたいと思います。 タイミーではiOSエンジニアやその他のポジションを含めて採用活動中です! プロダクト採用サイトTOP カジュアル面談申込はこちら
こんにちは。タイミーでPlatform Engineeringグループのマネージャーを務めている橋本です。先日Architecture Conference 2025で「AI × Platform Engineeringでスケーラブルな組織を作るには」というテーマで発表する機会がありました。本記事では、その内容をもとにブログ記事として詳細にお話できる部分も交えてお伝えします。 登壇内容詳細は以下リンクのspeakerdeckも見ていただけると嬉しいです 😊 speakerdeck.com とはいえ長いので、以下に登壇内容をサマライズしたグラフィックレコーディング風の一枚絵(feat. Google Nano Banana Pro)も掲載します。 登壇内容のサマリー サマライズしすぎると解像度が粗くなってしまうので(& サマライズに少し誤りが含まれるため 😢)文章で補足をさせてください。 成長するプロダクトと組織が直面する課題 他の会社組織でも見られることかもしれませんが、プロダクトの成長に伴い、機能の増加や依存関係の複雑化、ガバナンス要求の増加などが発生し、開発者の認知負荷が高まります。 タイミーにおけるPlatform Engineering(PFE)チームの役割は、こうした認知負荷をオフロードし、開発者が価値提供に集中できるスケーラブルな基盤を提供することです。しかし、ここに大きなジレンマがありました。 PFE × スケーラブルのジレンマ 現在、PFEメンバーは開発組織全体の約5%程度で、開発者と20倍近い人数差があります。開発者を手厚く支援しようとするとPFE自体がボトルネックになってしまいますが、かといって人を増やすのも簡単ではない。いわば「がっつり支援したいけれど、やりすぎるとパンクしてしまう」というジレンマです。 特定チームに深く入り込む「Embedded」型の支援は手厚いですがコストが高く、リソースが枯渇しやすい。一方、ツールや基盤を提供する「XaaS」型はスケーラブルですが、個別具体のコンテキストに対応しにくいという限界がありました。この一例として、弊社、古屋の ブログ記事 に書かれており、以下のようなお話です。 第一段階は私が作った本人でもあることから期待通りになることはすんなり確認できましたが、第二段階ではやはり S3 に関する知識が十分にない状態ではいくらサンプルコードがあっても書くのは難しいと改めてわかりました。 さて、現状はXaaS化を強力に推進しなければチームリソースが枯渇して回らなくなる、というところまでには至っていません。しかし将来、プロダクトや組織のスケーラビリティにPFEのスケーラビリティが追いつけなくなることが想定されます。 AIで突破する:新しい支援モデルの構想 そこで現在進めているのが、「このジレンマ、AIでなんとかならないか?」というアプローチです。とはいえ、この考え自体はあまり目新しさはないかもしれません。 具体的には、DevinのようなAIエージェントをチームの一員として機能させます。以下の絵が全体的なイメージです。なお、Devinを必ずしも使う必要はなく、CursorやClaude CodeなどのCoding AgentとコードのCloneによっても代替可能です。ここでは、ChatOpsな体験が良いこともあり、Devinを採用しています。 そして、左右で仕組みのカタマリが異なり、以下の絵のようになります。 右側:AIが調査・ドキュメント化 現在のリソース設定(As-Is)をAIが出力する仕組みです。ここでの”AI調査”はKiro CLI(Q Developerと呼ばれていたプロダクト)を中心に実現されます。なお 詳細は後述します。 AIはプロンプトに従ってAWS Resource Explorerなどを通じて、実際のクラウドリソースの設定状況(As-Is)を調査し、ドキュメントを生成します。 左側:人間が補足を記述 右側で生成されたドキュメントを元に「なぜこの設定なのか」というコンテキスト(Design Addendum)をPFEエンジニアが書き加えるフェーズです。ここで最大のポイントは、「設定値(As-Is)」だけでは不十分だということです。 「なぜその設定になっているのか(Why)」という背景情報は、設定ファイルの外側 にしかありません。 ドキュメント化のループと回答フロー 以下のようなループが回るイメージです。 AIが調査・ドキュメント化 人間が補足(Addendum)を記述 1 - 2を繰り返すループ AIが統合: これらを統合して、AIが開発者の質問に答える 開発者がAIに質問を投げかけると、Devinを通じてGitHub上の「As-Isの設定ドキュメント」と「Whyの補足情報」が統合されて回答されます。 例えば、開発者が「本番環境の〇〇という名前のS3バケット、なんでPublic Accessブロックされてるの?」と聞いた時に、AIが「それは〇〇というセキュリティ要件のためです」と即答できるようになります。また、ここまで背景を理解していれば、IaCコードの自動生成もスムーズになるため、柔軟な要件定義と実装出力(IaCコードを生成するなど)をAIが行うことも可能になるのではないかと考えています。 細かな実装について ここで、登壇で細かくお話できなかった以下の図の赤い点線枠内にフォーカスを当ててお話しします。 詳細なフロー図は以下になります。 Kiro CLI(Q Developer)は必要か? 今までの流れで「Kiro CLIを使うの?terraform/HCL + Coding Agent + MCPでもできるのでは?」と思われた方もいるかと思います。このブログ執筆時点では、Kiro CLIの方が適していました。AWSの設定確認をAIが行う上で必須となる awscli等の知識をKiro CLIは事前学習済みである ことがスムーズな仕組みに繋がっています。その他のCoding Agentを用いた場合でも AWS Knowledge MCP Server やInternet上の情報等を使うことによって同様の動きにはなるのですが、 オーバーヘッド・試行錯誤が多発する 点が無視できない(図で言う"いろいろ大変"な)部分でした。 なぜAWS Resource Explorerを使うの? Resource Explorerの詳細については、弊社、佐藤の ブログ記事 をご覧ください。AIにAWSリソースを調査させる場合、問題になるのはどのリソースが作成されているかという前提知識がないことです。正攻法でいくのであればAWSの全サービスに対してCrawling(list API)をしていくことになりますが、オーバーヘッドが大きく、regionも加わると対象は膨大です。Resource Explorerが管理するリソースは、ユーザー(我々)が作成したリソースがほとんどであり、Index化されたリソース情報を容易にリストで取得できることが利点です。Resource Explorerは各リソースの情報は持たず、あくまでどんなリソースがどのARNで作成されているかを得るためのIndexとして使っています。 SQLite(sqlite3)は何のために? 当初実装時は、AIにプロンプトを通じてResource Explorerを参照させていました。ただ、APIの返却上限が1,000件のリミットがあったり、ページネーションの挙動などが間に挟まっていると取得挙動が安定せず、あるタイミングで実行した場合には5,000件のリソース取得が期待されるのに、次は3,800件しか取れていないなど、件数が毎回変わる不安定さが見られました。 そこで、ローカルキャッシュとしてSQLiteを使い、ツールで定型的にResource Explorerから取得しsqlite3にデータを保持する仕組みとしました。AIはスキーマやデータ構造をコンテキストとして渡した上で対象をグループ(S3、IAM、RDSなど)化してSQLで取得し、調査をさせることが容易になりました。(もちろん、これらのツールもAIに生成・メンテナンスさせます) いろいろお膳立てをして満を持してAIが 上記のように、アレコレとお膳立てをしてAIが処理しやすい前捌きをしながら、ドキュメント化をさせる機構を作り上げています(まだ絶賛作っている最中で、試行錯誤のタイミングです)。今年の夏頃から徐々に作ったり試行錯誤をしていますが、AIの進化(Q Developerの登場)やAIが取り扱えるコンテキスト量の増加(Claude Sonnet4.5の1Mなど)などの外部環境により改善が一気に進むことを目の当たりにしています。CodingAgent / AI Modelの進化と一緒に暫くは改善・改良を進めていくことになりそうです。 AI時代の新しいPlatform Engineering この仕組みによって、これまで「コストが高いから乱発できない」としていた「Embedded(埋め込み型支援)」を、AIが肩代わりしてくれることが期待されます。AIがドメイン知識やインフラの現状を把握していれば、極端ですが24時間365日、各チームに「Embedded」し続けることができるのです。 これにより期待できる効果は以下のようなものであり、開発者に対する支援だけではなく、PFEチーム内の知識共有やマネージャー・監査部門による確認なども、より気軽に・低コストにできる未来があるかもしれません。 確認・学習コストの低下: 開発者がAI経由で「Why」を学べる 知識共有の加速: PFE内の知識がAIに集約され、担当交代やスケーリングが容易になる 監査・統制: 設定意図が明確になり、監査にも活用できる まとめ Platform Engineeringは開発者の認知負荷を下げるためにありますが、PFEチーム自体がボトルネックになりがちです。この「人のスケーラビリティ」の限界を、「AI支援によって突破する」。これこそが、AI時代の新しいPlatform Engineeringの形になるかもしれないと考えています。 AIを活用することで、これまでコスト面で難しかった「手厚い支援」を擬似的に実現し、開発者がフルサイクルに活躍できる環境を作る。タイミーでは、こうした新しいチャレンジに一緒に取り組んでくれる仲間を絶賛募集中です! プロダクト採用サイトTOP カジュアル面談申込はこちら
この記事は Timee Advent Calendar 2025 シリーズ 2 の18日目の記事です。 はじめに こんにちは、タイミーのDREチームのchanyouです。データ基盤の開発・運用を行っています。 社内向けのAIエージェントの開発プラットフォームを構築したので、その内容をご紹介します。 なお、この記事は人力で書きました。 「AIエージェント開発プラットフォーム」を作った背景 データ活用の新たなアプローチとして AI エージェントを位置づけ、そのために AI エージェント開発プラットフォームを作りました。ここでは、その背景に触れていきます。 データ基盤のこれまでと生成AI タイミーでは、RDB に保存されたマッチングの記録やCRM に保存された営業の商談記録といった多様なデータを BigQuery に集約し、あらゆる業務で活用しています。 DRE チームではデータの集約を担当しつつ、 BigQuery に集まったデータを dbt を使ってセマンティックレイヤー 1 という形で整え、 Looker で BI として社内に提供しています。 これまでは人間向けにセマンティックレイヤーを作り込んできましたが、複雑なロジックでも一貫した結果を出力できるセマンティックレイヤーは、生成 AI にとっても有用 2 だと考えています。 特に AI エージェントは業務に与えるインパクトが大きいと思われるので、セマンティックレイヤーをAIエージェントが参照できるようにしたいと考えました。 外部サービスを導入するか、内製か 外部サービスの導入で解決できる領域も広い一方で、社内データをセマンティックレイヤーを通して生成AIで利用するソリューションには、まだ決定的なものがない印象です。 生成AIを取り巻く環境の変化は早いとはいえ、ソリューションを待つのも時間がもったいないです。ここは内製に振り切って、AIエージェントが使える未来に到達してしまって、課題を先回りしてつぶしておきたいと考えました。 気軽に作って壊せる開発プラットフォームを作る 単体の AI エージェントで Looker に接続できる構成を磨き込む、という選択もできました。 ただ、将来を見据えると AI エージェントで解ける課題は山積しており、AI エージェントをいくつもデプロイできる構成のほうが望ましいです。技術的にも、 A2A プロトコルの実証など、試したいことは多くあります。 このことから、カジュアルに作って壊せる、社内向けの AI エージェントを早く手軽に開発・運用できるプラットフォームを作りました。 「AIエージェント開発プラットフォーム」の解説 利用イメージ 社内利用のためリッチなUIは求めておらず、普段の業務の延長で AI エージェントを利用できる状態を作りたかったので、ユーザーインターフェイスは Slack に振り切りました。 以下の画像のように Slack で利用できるようになっています。 Devin のようにSlack Bot にメンションをするとスレッドが作成されて、AIエージェントとやり取りできます。 画像にはありませんが、人間と会話しているスレッドの途中で AI エージェントにメンションすると、新しいスレッドを作成して会話を行うこともできます。 AI エージェントとの会話の単位をセッションと呼びますが、このプラットフォームでは Slack のスレッドごとにセッションを作成する方針としました。Slack の同一スレッドであれば、AI エージェントはコンテキストを汲み取って会話を継続してくれます。 Slack に振り切ることで、Webでチャットインターフェースを構える場合と違い、実際にAIエージェントが利用されている様子が確認できて、その場でフィードバックを受け取れたりサポートできたりして、開発者としても体験が良かったです。 インフラアーキテクチャ インフラアーキテクチャは以下の通りです。 graph RL subgraph Slack["Slack Workspace"] Bot[Slack Bot] User[User] end subgraph GCP["Google Cloud Platform"] AE[Vertex AI Agent Engine<br/>ADK] CR[Cloud Run<br/>Slack Bolt App] end User --> |Mention| Bot Bot --> |POST /slack/events| CR CR --> |Query| AE AE --> |Use tool| AE AE --> |Response| CR CR --> |Reply| Bot Bot --> |Display| User style CR fill:#ffeaa7 style AE fill:#74b9ff style Bot fill:#00b894 ユーザーインターフェイスとして Slack Bolt アプリケーションを構築し、その背後に AI エージェントフレームワークである ADK(Agent Development Kit)の実行環境を構築する構成としました。 Slack Bolt アプリケーションの実行環境は Cloud Run を、 ADK の実行環境は Vertex AI Agent Engine を採用しました。 Agent Engine には、AI エージェントとの継続した会話に必要なセッションストレージも内包されており、永続化のためのデータベースを別途用意する必要がなく、非常に手軽に AI エージェントを運用できます。 Cloud Run と Agent Engine が各エージェントごとにデプロイされる構成としています。 リクエストからレスポンスまでの流れは以下の図の通りです。 sequenceDiagram participant User as User participant Slack as Slack Bot participant CR as Cloud Run<br><br>Slack Bolt App participant AE as Vertex AI Agent Engine<br><br>ADK App User->>Slack: "@hello-world-agent 天気を教えて" Slack->>CR: POST /slack/events CR->>AE: クエリ送信 AE->>AE: エージェント処理<br/>ツール実行 AE-->>CR: 応答 CR-->>Slack: 応答を返す Slack-->>User: 応答を表示 コード管理 コード管理はモノレポ構成を採用しています。 Slack Bolt アプリケーションのコードは共通化しており、Slack Bot の挙動(何をトリガーに、どのように返信するか)は AI エージェントによらず共通としています。 AI エージェントの開発者は、 Slack のイベントハンドリングを意識せず、エージェントの開発に集中することができます。 プレビュー環境 AIエージェントの開発に限らず、Coding Agentのおかげで日々の開発スピードは格段に向上しました。 ただ PR がすぐに作れてしまうので、コードレビューがボトルネックになってくる場面が増えてきました。 レビュー負荷を軽減するために PR ごとにプレビュー環境を作成して、各ブランチの動作確認を Slack でできるようにしました。 Slack Bot 宛のメッセージで @hello-world-agent [PR-123] こんにちは のように [PR-番号] を含めることで、その PR の AI エージェントとして振る舞ってくれます。 Slack Bolt アプリケーションで PR タグの有無を確認して、タグを含む場合はプレビュー環境宛にルーティングする仕組みとしています。 プレビュー環境へのリクエストからレスポンスまでの流れは以下の図の通りです。 sequenceDiagram participant User as User participant Slack as Slack participant CR as Cloud Run<br><br>main participant PreviewCR as Preview Cloud Run<br><br>PR-123 participant PreviewAE as Preview Agent Engine<br><br>PR-123 User->>Slack: "@hello-world-agent [PR-123] 新機能をテスト" Slack->>CR: POST /slack/events CR->>CR: PR-123 タグを検出 CR->>PreviewCR: HTTP転送 PreviewCR->>PreviewAE: クエリ送信 PreviewAE->>PreviewAE: エージェント処理<br/>新機能で応答 PreviewAE-->>PreviewCR: 応答 PreviewCR-->>Slack: 応答を返す Slack-->>User: 応答を表示 「AIエージェント開発プラットフォーム」の成果 DRE チームではこの開発プラットフォーム上で、Looker で参照できるデータをもとに営業活動をさらにスムーズに行えるような AI エージェントを開発しています。全社的に展開して利用いただいており、まだ伸びしろはありますが、社内業務の効率化に寄与しています。 Looker を参照しているため、 AI エージェントの応答に含まれる数値に一定の信頼が置けています。これを取得したい指標ごとにクエリを用意するなどしていたら、心が折れていたと思います。セマンティックレイヤー様々です。 また開発者目線では、MCP Tool と Function Tool の使い分けやユーザーの認証情報の取り回し、マルチエージェントシステムのデザインパターンなど、 AI エージェントを使ったアプリケーションを開発する上で学ぶべき点が多々あります。これらの手法をすぐに試して勘所をスピーディに掴めるようになりました。 今後の課題 AIエージェント開発プラットフォームにより、作って使えるまでは爆速で行えるようになりました。 一方で、まだAIエージェントを評価する環境がプラットフォームとして整えられていません。 AIエージェントの評価は、プロンプトのチューニングや基盤モデルの変更の際のリグレッションを防ぐためにも重要なので、評価手法を確立してプラットフォームで下支えしていきたいと思います。 まとめ 今回開発したプラットフォームを通して、データ活用のアプローチとしてもAI エージェントは非常に強力であることが分かりました。しかし、AI エージェントがデータを使った業務を支えるためには、一貫した結果を扱えることが前提にあると実感しました。(毎回ブレブレの回答をされると信頼できなくて使えない) AI エージェント開発プラットフォームが整ったことで、さらにセマンティックレイヤーの重要性が増したと思いました。引き続きプラットフォームを育てつつ、セマンティックレイヤーの拡充も進めていきたいと思います。 AIエージェントを通したデータ基盤のさらなる活用に興味のある方、ご興味があればぜひお話しましょう! 下記よりカジュアル面談がお申込みいただけます。 product-recruit.timee.co.jp プロダクト採用サイトは以下よりご覧いただけます。 product-recruit.timee.co.jp セマンティックレイヤーとは、データ加工処理において、データをビジネス用語や概念に紐づけるレイヤーのことを指します。ビジネス用語や概念の定義をコードで一元管理し、タイミーでは Looker から参照するようにしています。これにより、例えば「売上」といった単純そうで意外と定義が揺れがちな指標の定義を固めておくことで、全社員が Looker を通して共通の指標を見ながら会話することができます。 ↩ もちろんBigQuery へのクエリを直接 Text-to-SQL させるアプローチもありますが、複雑なドメインロジックを全て Text-to-SQL させるのは、クエリ結果の信頼性を担保するのが難しいと考えています。 ↩
この記事は Timee Product Advent Calendar 2025 の18日目の記事です。 評価業務、面倒ですよね 社会人になってから、特に苦手になった言葉があります。 「個人目標」「評価」の2つです。 「自己評価」「振り返り」など会社によって呼び名は違えど、自身の四半期〜1年程度の期間に実施した業務や成果を上司に報告する機会は、正社員として働いている方にはほぼ必ず巡ってくることと思います。 私も例に漏れず、少なくとも15年以上は評価されたり評価したりしながら過ごしてきました。とはいえ、被評価者のキャリアアップなど目的は会社のためだけでは無いことは理解しつつ、評価期間に費やす時間・マインドシェアを削減して顧客への価値提供に投下するリソースを最大化する術が無いか、というテーマについて日々思考しています。 そんな中でやってきたのが、AI・LLMの波です。評価業務に割くリソースを最適化するチャンスと見て、私は飛びつきました。 というわけで、手探りで実施した自己評価業務におけるAI活用事例を紹介します。 自己評価におけるAIの使いどころ GeminiやChatGPTのようなAIは「私の四半期分の自己評価をまとめたドキュメントを作って」とプロンプトで依頼すれば、過去に自分が彼らに相談した内容からそれっぽいものを作ってくれます。ただ、実際の自身の活動をまとめる上では与えている情報量が足りないので、もっともらしい誤りの内容が出力されてしまうんですよね。 そこで、いかに私の情報をAIにたくさん与えるか、という観点で考えるアプローチにしています。情報源は自らがActionとしてたくさん書き出しておき、それらを会社制度に合わせた観点でまとめてスコア付けをする箇所をAIに任せる形です。 先に言っておくと、このアプローチにかかる労力は決して軽くはありません…。ただし、精神的な負担はかなり軽減された、と私は感じています。 実施手順 以下は2025年10月時点で自己評価をする必要がある組織を想定して記載しています。 AIはCursorというツールでSonnet 4.5(2025年10月時点)を利用して実施しましたが、ローカルにあるファイルを参照できるツールであれば他のツールでも応用可能だと思います。 自己評価の準備手順 自己評価用のディレクトリを作成(1分) 任意のディレクトリに作業用のディレクトリを作成( ~/Documents/workspace/cursor など)し、その直下に「202510_自己評価」というディレクトリを作成 評価に関係する社内ルールをMarkdown形式で書き出す(10分) 「キャリアラダー」ディレクトリ 社員が属するグレードごとに求められる要件をまとめた資料 全グレード分用意 面倒な場合は自分のグレード±1グレード分だけで良いかも バリュー.md ※2025年11月にバリューが更新されたため、現在のバリューとは異なっています 2025年10月時点の弊社のバリューは上記の4つ バリューのタイトルだけでなく、その詳細もセットで書いておく 個人目標ディレクトリを作成(1分) OKR_FY2025_2ndHalfディレクトリに、今期用のOKR目標2つ分のMarkdownを保存 弊社は「期待役割」という名称でも別の目標管理が実施されているため、期待役割_FY2025_2ndHalfディレクトリに今期用の期待役割3つ分のMarkdownを保存 日常的にアクションを書き溜めるためのディレクトリを作成(1分) 「Actions_FY2025_2ndHalf」ディレクトリを作成しました。 自己評価用ディレクトリのルート階層に、サブディレクトリごとの説明を書いたREADME.mdファイルを作成(15分) 上記1.で作成した作業用のディレクトリに内包しているディレクトリ・ファイルの説明用のMarkdownを「README.md」というファイル名で作成しました。 このディレクトリに含まれるファイルの概要は以下の通りです。 ## Actions_FY2025_2ndHalf FY2025下半期に実行した主たるアクションが一つ一つファイル化されているディレクトリ。 ## キャリアラダー 私が所属する企業であるタイミーの評価制度に用いられる、各グレードに期待される働きの定義群がまとまっているディレクトリ。 ## バリュー.md 私が所属する企業であるタイミーにおいて行動の基準となるバリューの定義。 ## 期待役割_FY2025_2ndHalf FY2025下半期の自身のグレードや職能を踏まえて自身に期待されるであろう役割を自ら想定した内容が記載されているファイルをまとめたディレクトリ。 期待役割は◯◯、◯◯、…のn軸から選択でき、その詳細は上記「キャリアラダー」ディレクトリに含まれるファイルにグレード毎に定義されている。 ## OKR_FY2025_2ndHalf FY2025下半期の目標として定めて取り組むOKR目標とその結果をまとめるディレクトリ。 日常的にアクションを書き溜める 評価対象期間(弊社の場合は3ヶ月)ずっと書き足していく必要があります。 1クォーターあたりだいたい10アクション程度の量感を目指して書いています。 個人目標に進捗があり次第、上記2.で書き出した個人目標のMarkdownファイルを更新 上記の手順をすべて実施すると、以下のようなディレクトリ構造が出来上がります。 202510_自己評価/ ├── README.md ├── Actions_FY2025_2ndHalf/ │ ├── アクション1.md │ ├── アクション2.md │ ├── アクション3.md │ └── ... ├── キャリアラダー/ │ ├── グレード1.md │ ├── グレード2.md │ ├── グレード3.md │ ├── グレード4.md │ ├── グレード5.md │ └── ... ├── バリュー.md ├── 期待役割_FY2025_2ndHalf/ │ ├── 期待役割1.md │ ├── 期待役割2.md │ └── 期待役割3.md └── OKR_FY2025_2ndHalf/ ├── OKR1.md ├── OKR2.md └── OKR3.md 自己評価をまとめる手順 「202510_自己評価」ディレクトリにself-assessment.mdを作成 self-assessment.mdに以下の情報を記入 # 前提 私のグレードは以下のとおりです。 - Grade: ◯◯ - Rank: ◯◯ # 自己評価スコア > Self assessment of Abilityは、以下の7項目から選択して採点して下さい。 > 期待通りが4で、それを軸に期待を上回ったか、下回ったを総合的に判断して下さい。 > > - 7. Extremely exceeds expectations > - 6. Greatly exceeds expectations > - 5. Exceeds expectations > - 4. Meets expectations > - 3. Less than expectations > - 2. Greatly less than expectations > - 1. Extremely less than expectations > > Self assessment of Valueは、以下の5項目から選択して採点して下さい。 > 期待通りが3で、それを軸に期待を上回ったか、下回ったを総合的に判断して下さい。 > > - 5. Greatly exceeds standard > - 4. Exceeds standard > - 3. standard > - 2. Less than standard > - 1. Greatly less than standard ## Self assessment of Ability **## Self assessment of Value(理想ファースト) ## Self assessment of Value(やっていき) ## Self assessment of Value(バトンツナギ) ## Self assessment of Value(オールスクラム) # 上記のスコアを付けた理由の深堀り ## 自己評価の背景 ## 自身の振り返り ### 期待役割に対する振り返り ### OKRに対する振り返り ### 総合的な振り返り** Cursorにself-assessment.mdを執筆するよう指示する 私はiOSアプリエンジニアをしています。 この会社の評価制度の中で、現在は自己評価期間となっています。2025年5月から2025年10月までの間に実施した業務と、期首に設定したOKRや期待役割の定義、更にキャリアラダーに基づいて、自己評価をself-assesment.mdファイルにまとめようとしているところです。 202510_自己評価ディレクトリのファイルを網羅的に参照して、私の自己評価業務を手伝うべく、このself-assessment.mdファイルの内容を埋めて下さい。 202510_自己評価ディレクトリに保存されているファイル群の概要は、202510_自己評価/README.mdにまとめてあります。 記入された自己評価をレビューし、違和感がある箇所を後続のプロンプトで手直しさせる 初回は自身の直感と異なるスコア付けがされていたので、こんなプロンプトで調整を加えていきました。 嬉しいんですが、本当にそうですか?さすがにほとんどの項目が最高評価だと、ちょっと疑わしいと感じてしまいます。もっと厳しい目線も加えてもらえませんか? 今のSelf assessment of Abilitのスコアは◯◯ですが、このスコアを+1するとしたらどんな懸念がありますか? 会社が用意した壁打ち用のAIにself-assessment.mdをレビューしてもらい、受けたフィードバックのうち妥当だと感じるものをCursorにプロンプト経由でフィードバックする 会社が用意した壁打ち用の生成AIに現状のself-assessment.mdをレビューしてもらいました。 以下のフィードバックを取り入れたいと思っています。 (以下、壁打ちAIのフィードバックのうち自身が共感した内容をコピー&ペースト) 以降、Cursorが手直ししたself-assessment.mdと壁打ち用AIの間を気が済むまで往復する 今期の自己評価のために用意したファイル群は、来期の目標設定でも役立つ 自己評価が終わるとすぐに待っているのが、目標設定業務です。 前期の評価に対して上司からもらったフィードバックを 202510_自己評価/self-assessment.md に記入しておくと、目標設定業務でそれが大いに役立つことになります。 具体的には、 202604_自己評価 ディレクトリを作って 202510_自己評価 と同様のディレクトリ構成を完成させた上で、以下のようなプロンプトでCursorに相談して目標設定を進めました。 @202510_自己評価/self-assessment.md ここに前期の自己評価と、私の上長から頂いたフィードバックが記載されています。 この内容を基に、202604_自己評価ディレクトリにOKRと期待役割を記入したいです。 どのように進めるのが良いでしょうか? 目標設定については詳細を省きますが、AIが目標設定の進め方を作業レベルまで落とし込んだり、OKR・期待役割のdraft版を提案してくれたりしたので、それらをレビューして調整を繰り返す形で目標設定を終えることができました。 感想 事前準備が全手動なので、トータルの労力としてはそれほどラクではありません。しかし、その事前準備で一番労力のかかる“日常的なアクションの記録”は、例えAIを活用しない場合であっても有効な手段ですし、実際に私は評価業務にAIを活用する前から実施していたことなので、AIを使うために大変になったわけではありません。 そして前述の通り、評価業務に挑む気持ちの面ではかなりラクになったと感じています。人間は事実を記録することに専念して、その事実が会社のキャリアラダーやバリューに沿っているかを客観的に評価する仕事をAIに任せたことで、評価業務においてクリエイティブな領域の多くをAIに頼れたからです。「やれば終わる」という作業的な仕事なら見積もり・見通しも立てやすいですしね。 直近の評価期間から、会社から公式に壁打ち用のAIが提供されたことも追い風になったなと感じています。 会社の評価指標情報は自身でそれなりに網羅的にAIに提供できているつもりですが、それでも壁打ち用AIにレビューさせてみると、別の観点でのフィードバックを受けることが多かったです。そういった評価観点の欠損をAI間で補うループが作れたことで、自身の労力を多く割かずともどんどん自己評価の精度が上がっていく工程は、気持ち良さすら感じる時間でした。 …ただ、たまに「来期は◯◯の研修を受けます」といった私が希望していないNext ActionもAIによって記入されていたので、AIによって記入された内容のレビューには気を抜けません。 こうしてAIを活用して制作した私の自己評価は上司のレビューを比較的スムーズに通過し、結果的に評価期間中も私が本来やりたいと感じていた業務に多くの時間を割くことができました。 開発業務をAIの力で効率化する話はよく挙がりますが、会社員として働くエンジニアの仕事は開発だけではないはずです。 この記事を読んだ皆さんに「自分が苦手な業務をどうにかAIに助けてもらえないか」と思考をしてみるきっかけにこの記事がなっていれば幸いです。 お話ししましょう! 私、岐部( @beryu )はタイミーでiOSアプリエンジニアをしています。iOSアプリ開発の中でのAI活用の情報共有だったり、評価業務の悩みを誰かに話したいだけでも結構ですのでw、ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら