TECH PLAY

株式会社メルカリ

株式会社メルカリ の技術ブログ

261

MySQLに高い互換性を持つデータベースのTiDBには、古いデータを自動的に削除するTTL(Time to Live)の機能があります。本記事では、これを活用しコスト削減および障害耐性の向上を実現した事例を紹介します 背景 メルカリでは、商品に対してコメントを付与することができ、値引きの依頼だったり、さまざまなやり取りを行うことができます。このコメントが、例えば公序良俗に違反すると想定される場合、お客さまがそれを「通報」する機能がありますが、メルカリ内部でも自動的にこれらを検知する仕組みが古くから実装され、運用に利用されています。 これらのコメントのデータは、歴史的経緯から古くはMySQL、現在はTiDBに格納されています。 自動検知の機能自体は、事前定義されたあるキーワードがコメントに含まれるかどうか、いわゆる「全文検索」によって実現されています。 : 全文検索クエリのイメージ SELECT table1.* FROM table1 FORCE INDEX(idx_xxx_xxx) \ WHERE (column1 like ''%a%'' OR column1 like ''%b%'' … ) \ AND (column1 not like ''%c%'' OR column1 not like ''%d%'' … ) AND ... \ ORDER BY created DESC LIMIT 10; またこの機能を動作させるには、多くのコメントに対し高頻度で多数の全文検索を実行する必要があり、このような使い方はもちろんMySQLにはあまり向かないものです。しかし、TiDBに移行した際にさらにこの負荷の影響が目立つようになりました。 初期の対応 TiDB User Day 2025でResource Controlの導入について紹介( 発表資料 )しており、詳細は割愛しますが、対象のクエリにヒント句でResource Groupを割当て、Burstableでない制約を加えることにより、TiKVでの優先度の制御と、TiDBでの多少の負荷の平滑化を実現していました。 しかしこの負荷は、定期的に実行されかつ実行間隔が短いものでしたので、実行を完了しなければいけないタイムウィンドウの制約が比較的厳しいものであることから、平滑化による制御の効果が限定的でした。 また、Resource Controlによる制御は、TiDBへのOLTPのワークロードに関しては比較的うまくいくものの、TiKVに対しては主に優先度でしか制御できず、リソースの隔離が不十分であるため、アプローチを変えて対応することにしました。 検討したアプローチ 問題のあるコメントの検知に関しては、コメントのデータが追記式で、後から編集できない(更新されない)というデータの性質上、ある程度最近のデータにのみクエリを発行できれば良いため、最近のデータだけをうまく処理するという方針を軸に、主に下記の観点から2点のアプローチを主に比較しました 既存のTiDBからデータが簡易に生成できる コストが妥当 クライアントの変更が少ない a. TiDBからTiCDCへ流通させたデータにKSQLを発行する TiCDCダウンストリームをKSQL DBとして活用 TiDBには TiCDC という、TiDBの実データを保存するTiKVの変更を取得し、ダウンストリームのデータベースに変更を伝播させるための、いわゆるCDC(Change Data Capture)の便利な機能があります。 MySQLであれば、例えば debezium といったソフトウェアがこれにあたり、TiCDCは変更イベントを以下のような様々なプロトコルで出力可能な柔軟さを持っています。 Avro Debezium Canal-JSON このTiCDCを使って、Debezium形式で下流のKafkaにデータを流せば、 KSQL というストリームデータに対してSQLを発行できる機能を活用し、インメモリでクエリを発行できる可能性があります。 KSQLの発行先であるKSQL DBのレコードはイミュータブルになります。 また、KSQLは全文検索に特化した機能はありませんが、全文検索のクエリも発行できます。 KSQL自体はすでに社内で活用/運用実績がある状況でした。 b. TTLにより一部のデータを保持する専用のTiDB Clusterを作成する まずは、必要なテーブルのみを持つTiDB Clusterを作成します。 TiCDCのレプリケーションタスクはChangefeedと呼ばれますが、テーブルの絞り込みには、このChangefeedの Table Filter という機能が活用できます。本ケースでは、コメントを保存するテーブルのみを保持するClusterを用意することになります。 次に、このテーブルのデータを最新のデータのみ保持するようにします。 TiDBには、Spanner同様、古いデータを自動的に削除する TTLの機能 があります。(MySQLにはありません)。この機能を活用すると最近のデータ以外は不要、という要件を簡易に達成できます。 TTLの機能をCluster単体で利用した場合は、特に追加の考慮は必要ありませんが、TiCDCを経由したデータに対して利用した場合は、追加の考慮が必要です。 すなわち、上流には存在する一方、下流には(TTLで削除されたため)存在しない、というデータが発生し、全てのイベントを伝播した場合、例えば、下流に存在しないデータに対しての削除が伝播し、エラーになるといったことが発生する可能性に対処する必要があります。 この問題に対しては、Changefeedに Event Filter という機能があり、特定のDELETEやUPDATEを無視する、といった設定が可能です。 : 上記のデータセットでEvent Filterがないとエラーになるクエリの例 DELETE FROM comments WHERE id=1 /* すでに下流にはデータがない */; UPDATE comments SET comment="good morning" where id=2 /* すでに下流にはデータがない */; さらに、TTLパラメータにより、保持するデータがメモリに収まるようコントロールできれば、実質的に多くのケースでインメモリに近い形で処理可能です。 なお、メルカリではTiDBのマネージドサービスである、TiDB Cloudを利用しており、ここで紹介したChangefeedのTable Filterおよび Event FilterはTiDB Cloudでも利用可能な機能です。 手法の決定 主にクライアントへの変更要求が少ないことから、TTLを用いる手法を選択することにしました。 万が一問題が発生した場合の切戻し、および暫定対処に関しても、クエリの発行先を、元のClusterに戻し、元のClusterのリソースを増やしてあげれば良いだけである、という便利さもあります。 ここで改めて、隔離した一部のデータセットを作成し、そこにクエリを発行するというアプローチを取った利点を確認します。 利点1: 構築が容易/短期で可能 特筆すべきこととして、TTLが十分短ければ、初期構築が非常に迅速、かつ容易に行えることが言えます。 既存のデータベースからある一部のデータを保持する別のデータベースを作成する際に、最も手間となるのは、既存のデータベースからのエクスポート/リストアから始まる初期データの作成ではないかと思います。 しかし、Event Filterで所定の構成をすれば、TTLが短い場合、下流に空のデータベースを用意し、その時点からデータの複製を始めれば、保持すべきTTLを待つだけでデータの用意が完了します。 利点2: 障害単位が独立し個別調整の余地が出る リソースを完全に独立させた専用のClusterを用意することで、障害の単位も分離でき、さらに、決まった使われ方をする独立したClusterに対して、積極的にリソースを活用するようチューニングが可能です。 もちろん、設定が同一ではない、非対称なものが生まれるのは運用における認知負荷が上がるという問題はあり、構成変更により得られる効果とのバランスをチームで納得のいくものにする必要があります。 結果 変更前後のTiKVの負荷について示します。 A) 変更前のTiKVの負荷 B) 変更後のTiKVの負荷(ピーキーな負荷が隔離され利用量が平滑化された) C) 新規TiKV with TTLの負荷 このように負荷は別のClusterに分離され、上位のスペックで運用していた既存のClusterの負荷が減少し、かつ安定したことから、既存のClusterのノード数を減らすことができました。 新規に別のClusterを作成しているものの、トータルコストとしても削減でき、障害に関するリスクも分離できました。 まとめ 本記事では、Changefeedのフィルター機能(Table Filter, Event Filter)、TiDBのTTLを活用し、一部のデータに対して、高頻度で発行される全文検索の負荷を、独立したClusterに分離することでコスト削減をした事例を紹介しました。 このアプローチでは、アプリケーションの変更および、構築、共に少ない変更ですみ、結果として早期に移行を完了することができました。 メルカリでは、TiDBを利用していますが、初期導入のフェーズから、この記事のような継続的改善のフェーズに入っています。現在、様々な取り組みをしており、近々別の記事で紹介していく予定です。 関連/補足 本論とは少しそれる、細かな検討事項について補足します。 TiDBの全文検索については、一部のリージョン、一部のサービスプロバイダ、一部のサービス提供形態で、試験的に利用できるものが提供されています。現状では選択肢には入りませんでした。また、商品に対するコメントについては、ある商品のコメントを表示する、コメントを書き込むというのが主な用途であり、そういった点からも元データとしてはこのデータのみを全文検索エンジンに格納するのは相応しくないと考えています。 https://docs.pingcap.com/tidbcloud/vector-search-full-text-search-sql TiKV MVCC In-Memory Engine については、B案の一部として試しました。今回のケースが、In Memory Engineに向いたケースではなく、「構成変更により得られる効果とのバランス」が悪かったため、今回は採用には至りませんでした。
アバター
こんにちは、メルカリCTOの木村(@kimuras)です。 今年は、ついに開催されたメルカリ主催のエンジニアイベント 「 mercari GEARS 2025 」 にて、Keynoteを担当しました。本記事では、その内容を改めて文章としてまとめ、皆さんにお伝えしたいと思います。メルカリがAI-Native Companyになることを宣言して以来、エンジニアリング組織に限らず、全社としてどのようにAI-Native化を進めていくのか、その指針についてお話しします。 ご存じのとおり、AI活用による生産性向上は、まだまだ不確実性の高い領域です。さらに新たな技術が次々と登場することで、今日述べる内容も、近い将来には更新が必要になるかもしれません。しかし、だからこそ「現時点で我々がどこを目指し、どのような方向性で進んでいるのか」を言語化し、共有しておくことは、この変革期において非常に重要だと考えています。 AI-Native化の推進は決して簡単ではありませんが、本記事の内容が、同じように挑戦されている皆様の一助になれば幸いです。 目次 全社をあげたAI-Native化とは 現状: 確かな変化、しかし「まだ道半ば」 発想の転換:「人間前提」から「AI前提」へ AI-Native化の前提条件:Knowledge Management AI-Centricな開発:Agent-Spec Driven Development(ASDD) 全社的なAI化:AI Task Force 未来のビジョン:AI化の先にあるもの 今後に向けて 全社をあげたAI-Native化 「プロダクト、仕事のやり方、組織すべてをAI中心に再構築し、AIの進化を最大限に活用することで、これまでにない成果を目指す」 (参考: 新年度のテーマは「Back to Startup」と「AI-Native」。12周年を迎えたメルカリが目指すこれからの姿 | mercan (メルカン) ) これは、社長である山田からの強い決意表明でした。 AIへの対応が遅れれば、競争環境の中で後れを取るリスクは避けられません。同時に、私たち一人ひとりの成長においても、大きな変化が求められています。AIによる生産性向上は、従来の評価基準では実現が難しかった新たな価値創造を可能にします。変化を柔軟に受け入れ、成長し続けられる人にとって、これは自身の価値を飛躍的に引き上げる絶好の機会でもあります。 そして、AI-Nativeな働き方を全社に浸透させるということは、単にAIツールを一律に導入することではありません。これまでの働き方をゼロベースで見直し、業務そのものをAIを前提とした形へ抜本的に進化させていくことが重要だと考えています。 現状: 確かな変化、しかし「まだ道半ば」 メルカリではすでに、社員の95%がAIツールを活用し、コード生成の約70%をAIが担うまでに進化しています。開発スピードも前年比で64%向上しました。数字だけを見れば、AIは確実に浸透しているように思えるかもしれません。 しかし、私たちは現在の状態を“AI-Native”だとは捉えていません。むしろ、ここからこそ本当の変革が始まると考えています。 最近よく議論されているように、「本当に生産性は飛躍的に向上したのか?」という問いに対して、私自身もまだ改善の余地は大きく残っていると感じています。そして、コーディングの生産性が向上しただけでは、組織全体の生産性は十分には高まりません。同じくらい重要なのは、コーディング以外の業務プロセスも含めて、AI前提の働き方に転換していくことです。 発想の転換:「人間前提」から「AI前提」へ 前述のとおり、AIを前提とした働き方を実現するためには、単にツールを導入するだけでは不十分です。私たちは、仕事に対する考え方そのものを根本から塗り替える必要があると考えています。 これまで私たちが直面してきた限界は、「人が行うこと」を前提に組み立てられたプロセスや仕組みによって生じていました。AI-Nativeな働き方とは、そうした前提条件そのものを問い直し、業務を“人が実行するタスク”から“AIと人が最適に協働するタスク”へと再設計していくことにほかなりません。 これまでの限界 これまでの仕事や組織のデザインは、多くが“人間前提”で設計されてきました。 つまり、人間の時間・集中力・処理能力といった制約を起点に、「その条件の中でどう成果を最大化するか」を軸に最適化されてきたのです。 たとえば、1日8時間労働、週休2日、1チーム8名構成、週次の定例会議、こうした組織の“当たり前”はすべて、人間の能力と限界を前提として形づくられてきました。現在も一般的な働き方であり、私たち自身もその枠組みの中で働いています。 しかし、AIを前提とした働き方とは本来どういう姿なのか。 そこを抜本的に考え直し、AI活用を進めながら、これまでの常識を一つひとつ疑い、新しい標準をつくっていく必要があります。 たとえば、 1人が複数ロールを効率的にこなせるようになれば、チームは8人よりも少ない人数のほうが、むしろ高い成果を出せるかもしれません。 AIによって単純作業が減り、人はより連続的で深い思考に集中できるようになると、脳の疲労はこれまで以上に高まる可能性があります。その場合、1日8時間労働ではなく、短時間で高集中の働き方のほうが高い生産性を生み出すことも考えられます。 このように、AI前提の働き方は、従来の“当たり前”を根本から再設計することを意味します。 AI前提の世界観 では、AIを前提とした働き方とは、どのような発想の転換なのでしょうか。 これまで新たなプロジェクトや事業を立ち上げる際には、前述のような「人間の限界」を前提として設計するのが一般的でした。特に人的リソースは最も大きな制約であり、どれだけ人を確保できるかが計画の起点になっていました。 しかし、AIが前提となる世界では、この出発点が根本的に変わります。 仕事や組織のあり方を、“人の限界から逆算する”のではなく、ビジョンや提供したい価値から逆算して設計することが重要になります。 すなわち、 「何を実現し、どんな価値をお客さまに届けたいのか」 という問いからスタートし、その実現のためにAIをワークフローへ組み込み、最適な仕組み・チーム構成・役割・データのあり方などを再設計していくという考え方です。AIはミッションを前進させる創造的なパートナーであり、チームの一員として存在します。 これこそが、私たちが目指す“AI-Native”の世界です。 AI-Native化の前提条件:Knowledge Management なぜKnowledge Managementが重要なのか 私たちもAI Coding Assistantをはじめ、さまざまなAIツールを導入してきましたが、当初想定していたほど生産性が向上しないという課題がありました。 その背景には、AI化を進める前に取り組むべき、より本質的な要素が欠けていたことがあります。それが、適切な情報、すなわちコンテクストの整備です。 特にAI Agentは、十分なコンテクストが与えられなければ期待どおりに機能しません。単純な指示だけでは精度の高い成果物を生成できず、手直しが何度も発生し、かえって時間がかかってしまうことすらあります。最終的には品質が低いアウトプットになってしまうケースも少なくありません。だからこそ、タスクに関わる背景知識、関連するレギュレーション、過去の意思決定プロセスや議論のログなどをコンテクストとして適切に提供することが不可欠です。 そうすることでAI Agentは、状況や歴史的文脈、そしてAI Agent利用者が求めるゴールを正確に理解し、より期待に近い成果物を生成できるようになります。結果として、AIを効果的かつ継続的に活用できる環境が実現します。 どのようなコンテクストが必要か 必要となるコンテクストは、AI Agentに解かせたい課題によって大きく異なります。したがって、「この情報さえあればよい」という万能のテンプレートは存在しません。ただし、コーディングを例に挙げると、以下のような情報は特に有効です。 Microservicesの依存関係 コーディング規約 設計書 関連する開発における過去の意思決定ログ コードレビューでの議論内容 これらのコンテクストをAI Agentに提供することで、依存関係を正しく考慮しながら、これまでの方針や意思決定と整合性のある設計やコード生成が可能になります。 最も重要なコンテクスト:意思決定情報 私たちが最も重要だと考えるコンテクストの一つが、意思決定情報です。 意思決定に関するコンテクストは本来きわめて重要ですが、実際には十分に整理されていないケースが多く見られます。SlackやGitHub、ミーティングメモなど複数のツールに議論が散在し、必要な情報を必要なときに取り出すことが困難になっているのが現状です。会議で決まった内容が適切に共有されず、後から意思決定の経緯をたどれない場合も少なくありません。 当社でもDesign Docにアーキテクチャや意思決定事項をまとめていますが、その判断に至るまでの議論は依然としてさまざまなツールに分散しています。その結果、「なぜその判断に至ったのか」という重要な背景が抜け落ちるリスクがあり、散在した情報を後から統合するには非常に大きな手間がかかります。 しかし、こうした意思決定情報はプロジェクトを適切に進めるうえで不可欠であり、AI Agentにとっても極めて重要なコンテクストです。AI Agentは、今後コーディングだけでなく、仕様書作成、デザイン、QA、リーガルチェック、セキュリティチェックなど、より広範な領域で活用されるようになります。その際に必要なのは、次のような情報です。 このプロジェクトの目的・狙いは何か 何が許容でき、何が許容できないのか 過去にどのような議論があり、何を重視して意思決定してきたのか AI Agentがこうした背景を理解しているかどうかで、アウトプットの品質は大きく変わります。適切な意思決定コンテクストが提供されれば、AI Agentは状況を正確に把握し、より高品質で一貫性のある成果を生成できるようになります。 この後に紹介するAI Agent Spec Driven(ASDD)でもSpecを決定した議論を録音しておき、それをコンテクストとしてSpecに提供することで、より高性能にAI Agentを活用できると紹介されています。 最初のSpecだけでは表現しきれていなかった背景やニュアンスが、レビュー時の対話には多く含まれています。この文字起こしログをCoding Agentに読ませてSpecを改善させることで、当初の記述では表現できていなかった文脈や設計の抜け漏れを補足し、より精度の高いSpecへと昇華させることができます。 (参考: Agent Specで小さく素早く回すメルカリモバイル開発現場 ) Knowledge Managementへの取り組み 現実には、こうした情報は十分に整理されておらず、多くが暗黙知のまま埋もれてしまっています。そこで私たちは、議論の記録や意思決定をできる限り構造化し、いつでもコンテクストとして活用できる状態にするため、Knowledge Managementの強化に取り組んでいます。 AIを前提とした働き方をつくると同時に、情報管理のあり方そのものを抜本的に見直しているところです。これが実現すれば、トップダウンの意思決定と、現場からの学びや提案といったボトムアップの動きがよりスムーズにつながり、全社としての意思決定速度も大きく向上します。 こうしたAI-Readable(本稿では、データが整備されており、AIエージェントが容易にコンテクストとして参照できる状態のデータを「AI-Readable」と定義します)なデータマネジメントを実現するため、私たちは現在、Notionに情報を極力集約する取り組みを進めています。 目的は二つあります。 散在している情報を一つの文書管理基盤に集約し、必要なときにコンテクストを簡単に取り出せる状態にすること 情報の残し方そのものを再設計し、AIによる議事録作成の標準化や、多様な情報資産の構造化などを通じて、AIが扱いやすいナレッジ体系をゼロから構築すること これにより、人間にとってもAI Agentにとっても理解しやすく再利用しやすい組織の記憶をつくることを目指しています。 この方向性を元に、現在、メルカリはNotionをCentral Knowledge Baseとして位置付け、ナレッジの中央管理型への移行を進めています。本記事の主旨と離れるので、細かくは記載しませんが、ツール選定に関しては、フロー情報(議事録など、メンテしない情報)とストック情報の両方に強いという点や、AIとの親和性の高さが大きなポイントでした (参考: メルカリが、AI時代にナレッジマネジメントに投資したわけ ) AI-Centricな開発:Agent-Spec Driven Development(ASDD) 現状の課題 私たちはすでに、ほぼ100%のエンジニアがAI Coding Assistantを活用しており、コード生成量も60%以上増加しています。しかし、冒頭でも述べたように、これはあくまでスタート地点にすぎません。 本質的にAIを活用するためには、開発プロセス全体をゼロベースで見直し、AIを前提とした開発プロセスへと再構築する必要があります。AI Coding Assistantの活用を進める中で、利用率は大きく向上したものの、以下のような課題が明らかになりました。 プロンプト品質のばらつき レギュレーションがないため、人によってプロンプトの質が大きく異なり、短時間で高品質なコードを生成できるケースがある一方、指示の反復が必要で、結果としてAIなしより遅くなるケースもありました。 コンテクスト収集の困難さ プロンプトの書き方を理解していても、必要なコンテクストを正確に収集できず、適切な情報量をAIに与えられないことが多く発生しました。 生成コード品質のばらつき 一部ではレビューしやすい高品質なコードが生成される一方で、品質が低くレビューが困難だったり、バグの温床になりやすいコードが出力されるケースも見られました。 使用ツールのばらつき 当初はCursor を全社導入しましたが、その後Claude Codeなど新たなCoding Assistantが登場し、エンジニアによって利用ツールが異なる状況が生まれました。そのため、ベストプラクティスを集約し、共有することが難しくなりました。 これらの課題の根底にあるのは、AIの使い方に関する共通レギュレーションが存在しないことです。そのため、チームや個人によってアウトプットの品質が大きくばらついてしまう状況が生まれていました。 目指す開発プロセス 私たちが目指す開発プロセスは、先に挙げた課題を解決したうえで、すべての開発プロセスにAIのポテンシャルが最大限活かされている状態です。 具体的には、次のような姿を想定しています。 コーディングだけでなく、スペック作成、デザイン、コードレビュー、QA/テストなど、あらゆる工程でAI Agentが活用され、開発全体が最適化されていること 各プロセスに必要なコンテクストが適切に整理・提供され、AI Agentが効率よくタスクを遂行できること 前述の課題が解消され、統一された開発プロセスとして標準化され、すべてのエンジニアが安定してAgentic Codingを実践できること これらを実現することで、特定のツールに依存しない、共通化されたAgentic Codingのワークフローが全エンジニアに浸透している状態をゴールとしています。 Doubleプロジェクト:ASDDの実現 私たちが現在進めているのが、DoubleプロジェクトにおけるAgent-Spec Driven Development(ASDD)です。「Double」という名称は、生産性を“2倍にする”というプロジェクトの目的に由来しています。 ASDDは、AI Agentに必要なコンテクストを正しく与え、適切なプロンプトで誰でも開発を進められるようにするための、AIフレンドリーな仕様フォーマットを整備する取り組みです。 そしてこれは、単なる仕様書ではありません。AI Agentやエンジニアが実際にコードを書けるレベルまで落とし込むための、実装指向の設計書を作成するためのテンプレートです。抽象的なアーキテクチャ設計ではなく、既存のコードベースやプロジェクトの流儀に完全にフィットした形で、以下のような具体要素を明確に定義します。 API定義 データモデル DBスキーマ 処理フロー テストシナリオ 具体的な実装手順(TODO) マイクロサービス間の依存関係 このテンプレートの目的は、「誰が・どのタスクを・どのファイルで・どのコードスタイルで実装するか」を明確にし、誰がAI Agentを使っても、同じ品質・同じ規約で実装できる状態をつくることです。言い換えれば、ASDDはチーム全体の実装プロセスを“再現可能な工程”にするための詳細仕様テンプレートです。 また、AI Agentが正確にコーディングできるよう、タスクの粒度を小さく保つなどの工夫もテンプレートに組み込んでいます。 (参考: Agent Specで小さく素早く回すメルカリモバイル開発現場 ) ASDDの活用範囲 ASDDのポイントは、コーディングだけのSpecではないということです。このSpecは全プロセスでAgentをフルに活用するためのベースとなります。 開発領域: バックエンド開発 フロントエンド開発 モバイル開発 品質保証: QAのテストケース自動生成 AI Review その他の領域: カスタマーサポートのスペック調査 リスクマネジメント コンプライアンスチェック PJ Aurora:UI自動生成 さらに、このAgent Specは、UIを自動生成するためのAI Agentの仕様としても活用されます。UI向けのAI Agentは「PJ Aurora」というプロジェクトとして開発が進められています。 Auroraは、プロンプトを与えるだけで、内製のデザインシステムを活用しながらUIを自動生成できる、非常に先進的な取り組みです。デザインの一貫性を保ちつつ、UI作成にかかる工数を大幅に削減できる点が大きな特徴です。 また本プロジェクトでは、生成されたUIが社内のデザイン規約に準拠しているかを自動でチェックするAI Agentの開発も進行しています。これにより、Agenticなデザインプロセスによる効率化と品質担保の両立が期待されています。 (参考: PJ-Auroraが描く未来と、UI品質評価を自動化するエージェント開発 ) コンテクストの重要性 ここで改めて強調したい重要なポイントがあります。Agent Specを作成する際に与えるコンテクストの質は、極めて重要です。ASDDの品質は、このコンテクストの品質に大きく依存しており、適切なコンテクストが与えられなければ、期待通りに機能しません。逆に言えば、質の高いコンテクストが整理・提供されてはじめて、ASDDは本来の効果を発揮します。 そのため、前述のとおり、このコンテクストを体系的に整備するためのKnowledge Managementプロジェクトも並行して進めています。これまでに作成された仕様書や意思決定の履歴、経営会議における意思決定情報などを整理・蓄積し、AI Agentにとっても人にとっても適切なコンテクストとして活用できる状態を整えています。 メルカリのナレッジ基盤に最適化されたエージェントが自動的に一次情報にアクセスし、詳細な実装計画を生成します。また別のエージェントが、実装計画がサービスのコーディング規約に沿っているか、計画が所定のセキュリティ観点をクリアしているかなどのさまざまな調査を行います。この2つのエージェントが交互に修正と評価を繰り返し、最後に要件や仕様における不確実要素が残った場合には、開発者に追加の質問を行います。このように、「AIのコンテキストに適切な一次情報を与える」ことをプロセスによって保証しました。 (参考: pj-double: メルカリの開発生産性向上に向けた挑戦 — AI-Native化が辿り着いたASDDとプロセス変革の全貌 ) ASDDがもたらす価値(Customer-Centricを極める) ASDDの本質的なポイントは、いわゆる直感的なVibe Codingではなく、Agenticなアプローチによって、誰でも再現性のある開発レギュレーションを実現できることにあります。私たちは社内に蓄積されたベストプラクティスを継続的に収集し、このAgent Specを育て続けることで、AI Agentのポテンシャルを最大限に引き出し続けられる開発環境を構築していきたいと考えています。 これが実現すれば、エンジニアに限らず、すべての開発に関わるメンバーが次のような状態を手に入れることができます。 より多くのタスクをこなせるようになる Trial & Errorを高速に回せるようになる 解決が難しいデザインや設計に、より多くの時間を使えるようになる お客さまに提供すべき新しい価値について、深く考える時間を確保できるようになる これまで私たちは「AI-Centric」という表現を使ってきましたが、人がよりお客さまの価値に集中できるようになるという意味において、これは本来私たちが大切にしてきたCustomer-Centricの究極の形であると、私は考えています。 全社的なAI化:AI Task Force 開発プロセス以外にも最適化の必要性 ここまでは主に、開発プロセスを中心としたAI Agent活用によるプロセス改善についてお話ししてきました。これにより、プランニングからコーディング、リリースに至るまでのスピード向上が期待できます。 しかし、実際のリリースまでを見渡すと、開発以外にも複数のプロセスが存在します。全体最適ができていなければ、どこかで必ず待ちが発生し、結果としてリリース全体のスピードは改善しません。 その代表例が、開発プロセスに付随して発生する関連チームによる各種チェックプロセス です。例えば当社では、プロジェクトの内容に応じて、リリース前に以下のような確認を行い、新しく開発したサービスの安全性や品質を担保しています。 リーガルレビュー PRレビュー セキュリティレビュー コンプライアンスチェック 究極的には、全社レベルでのプロダクティビティが向上しなければ、AIを活用してもリリース速度は頭打ちになります。そのため、開発プロセスに限らず、全社のあらゆるワークフローをAgenticなワークフローへと進化させていく必要があります。 理想的には、ASDDのSpecを活用し、これらの関連ワークフローについてもAI Agentが並列に処理を担うことで、大きなボトルネックを生むことなく、高速なリリースを実現できる状態です。その実現に向けて、私たちはコーディング以外の業務にも目を向け、Agenticなワークフローを横断的に構築していかなければならないと考えています。 PJ Socrates:Agenticな働き方の先駆け Agenticな開発を実現するうえで、その働き方の方向性をいち早く示してくれたのがPJ Socratesでした。Socratesは、いわばBI領域のAI Agentであり、社内に存在するさまざまなデータの取得や分析を支援する役割を担っています。 これまで、施策のアイデア検討やビジネス戦略を考える際には、お客さまの動向や売れ行きなどを把握するために、DB上の複数テーブルをJoinした複雑なクエリを書く必要がありました。こうした作業には職人的な知識や経験が求められ、BIやAnalyticsチームのサポートなしにデータを取得することは難しいのが実情でした。Socratesの導入により、必要な分析内容を自然言語でAI Agentに依頼するだけで、データ取得から分析までを自動で行えるようになりました。 当時はまだ「AI Agent」という考え方自体が明確でなかったこともあり、この体験は社内に大きなインパクトをもたらしました。AIは単なるタスクの自動化にとどまらず、データを取得し、分析し、さらには示唆を提示するところまで担える。つまり、AI Agentは自動化だけでなく、意思決定を含む高度なタスクも遂行できる存在であることが、具体的に示されたのです。 そして、これまで人が担ってきたタスクを可能な限りAI Agentに委ね、人は本来より多くの時間を使うべき領域に集中していく。そのような働き方の方向性を、全社として実感する大きなきっかけとなりました。 (参考: AI/LLMが拓くデータ活用の新時代:人間とデータ分析AI エージェントが協業する分析基盤へ ) AI Task Forceの発足 このAgenticな働き方を全社で実現するために発足したのが、AI Task Forceです。AI Task Forceは2025年7月に活動を開始しました。 AI Task Forceでは、全社を33のドメインに分け、それぞれの領域のワークフローをAI化することを目的に、各ドメインへエンジニア1〜2名、PjM 1〜2名をアサインしました。さらに、各ドメインにはドメインオーナーを配置し、AI導入に向けた方向性や方針に関する意思決定を担っています。 その結果、総勢約100名規模のメンバーがAI Task Forceに参画する体制となりました。ここでアサインされたエンジニアは、必ずしもAIのバックグラウンドを持つ人材に限定していません。あえてさまざまな領域のエンジニアを各部署から選抜し、互いに学び合いながら進める形をとっています。AI Task Force立ち上げ時の様子については、以下の記事でも紹介しています。記事中の写真からも分かるとおり、100名規模となると相当な体制です。 活動開始当初は、AI-Native化という不確実性の高いテーマに取り組むことから、目的や目標の明確化・文書化を重視し、全社およびTask Force向けにAll Handsでの説明会を高頻度で実施することを強く意識して進めてきました。 (参考: メルカリが本気で始めた「AI-Native」化。100名規模のタスクフォースが立ち上がるまで | mercan (メルカン) ) AI Task Forceの3つの責務 前述の参照記事にも記載されているとおり、AI Task Forceには大きく分けて3つの責務があります。 各ドメインにおけるすべての業務の棚卸し 棚卸し結果を踏まえた、将来のAI化に向けたビジョンおよびロードマップの策定 ロードマップに基づくAI化の実行 AI Task Forceは7月に発足し、現在までに33すべてのドメインにおける業務の棚卸しとロードマップ策定を完了しました。そして今まさに、各領域でAI Agent化に向けた具体的な開発フェーズに入っています。 33領域を横断して業務を棚卸しした結果、定義されたワークフローの数は約4,000にも上りました。もちろん、これらすべてを一律にAI化するわけではありませんが、各ドメインで策定されたロードマップに基づき、中長期的な視点で段階的にAI化を推進していく計画です。 AI Task Forceからの学び AI Task Forceはまだ道半ばではありますが、ここまでの取り組みを通じて、すでに多くの学びを得ることができました。ここでは、その中でも特に重要だと感じているポイントを振り返ります。 複数ロール間の連携強化 今回のAI Task Forceでは、従来の役割分担を超えた取り組みが生まれました。通常、Software Engineerはプロダクト開発を主に担い、リーガルやファイナンスといったコーポレート領域の業務に深く関わることは多くありません。しかし今回、そうした領域にエンジニアが入り込み、業務の棚卸しを行ったことで、次のような成果が生まれました。 エンジニアのフレッシュな視点により、現場では当たり前になっていた冗長な業務に対して、効率化のアイデアを提示できた 場合によっては、その業務自体を根本的に不要にできる可能性を示すことができた エンジニア自身にとっても、これまでにない経験となり、新しいチャレンジへのモチベーションにつながった このように、ロールを越えた協働は、業務改善だけでなく、人の成長や組織の活性化にも大きく寄与したと感じています。 不確実性との向き合い方 AI Task Forceでは、各領域ごとに業務の棚卸しを行い、AI-Native化に向けたビジョンやロードマップを策定してきました。しかし、無数に存在するタスクの中から大きな方針を定め、優先順位を決めることは決して簡単ではありません。実際、領域によっては、この意思決定に大きく悩み、時間を要したケースもありました。 別のADVENT CALENDAR記事の中で、@panoramaさんは次のように述べています。 しかし最終的には 「誰も正解がわからない。でも、手探りで失敗を繰り返したとしても進める価値がある」 のがAI-Native化だと考え直しました。 (参考: AI Task Forceで学んだ「不確実性との向き合い方」 ) 私自身、メンバーに苦労をかけてしまったのではないかと反省する気持ちもあります。一方で、たとえ時間がかかったとしても、この不確実性と真正面から向き合い、じっくり考えて答えを出すプロセスを経たことが、AIを単なるツールとして導入するのではなく、働き方そのものを見直すきっかけになったと信じています。 AI Task Forceをリードする立場として、私自身も不安を感じる場面は多くありましたが、悩みや不安を抱えながらも前に進んでくれたメンバーを、心から誇りに思っています。AI Task Forceのように不確実性の高いプロジェクトを進めることは容易ではありません。これから同様の取り組みを始める方には、ぜひ先ほどの記事も参考にしていただければと思います。 情報共有の難しさ 今回、33の領域をそれぞれ独立して進めたことで、各領域において迅速な意思決定が可能になった一方、反省点もありました。それは、各領域で得られたベストプラクティスやレトロスペクティブを、十分に共有できなかった点です。 33領域すべてで定例ミーティングを行うのは現実的ではありませんが、もし領域間でスムーズに知見を共有できる仕組みがあれば、全体の効率はさらに高められたはずです。各領域のロードマップが出揃った今だからこそ、進捗や学びをよりオープンに共有し、全社としてより洗練された進め方を模索していきたいと考えています。 同時に、この「情報共有の難しさ」もまた、Agentベースのアプローチによって効果的に解決できる課題の一つだと捉えています。 (参考: 【メルカリ本気の全社AI化】100人で2000人を改革するAIタスクフォースの全貌 / すべての仕事をAI-Native化 / 鍵は ) 未来のビジョン:AI化の先にあるもの メルカリのミッションと現在地 ここまで、私たちはAI Task Forceを通じて全社のあらゆる業務をAI-Native化する取り組みを進めていること、そして並行して、特に開発プロセスにおいてはASDDを軸にしたAgent化を推進していることをお話ししてきました。では、このようにすべてをAI-Nativeへと進化させた先に、私たちは何を目指しているのでしょうか。 メルカリは、「あらゆる価値を循環させ、あらゆる人の可能性を広げる」というミッションのもと、マーケットプレイス、フィンテックサービス、そして新たな事業を展開してきました。そしてこのミッションを真に実現するために、私たちにはまだ取り組むべきことが数多く残されています。 世界展開への道 近年、メルカリは 国際展開を本格的に進めており、台湾をはじめ、香港でのサービス提供も開始 しました。私たちはマーケットプレイスを世界へと広げることで、より多くのモノの価値を循環させ、世界中の人々の可能性を広げていくというビジョンを掲げ、着実に国際展開の基盤を築いてきました。一方で、実際にサービスをグローバルに展開しようとすると、どれだけスケーラブルな仕組みを構築したとしても、各国ごとのローカライズ対応や日々の運用を考えたとき、現在の社員数のままでは限界があるという課題意識も持っていました。 しかし、これまでに述べてきたように、AI Agentを最大限に活用し、一人ひとりの生産性や能力を拡張できれば、現実的な人数で世界展開を本当に実現することも決して夢ではない と、今では考えています。 これはマーケットプレイスに限った話ではありません。フィンテック領域においても、グローバルに展開される金融サービスを提供し、私たち独自の与信モデルを世界に広げていくことで、世界中の人々の可能性をさらに広げられるはずだと考えています。 @deeeetさんの記事にもあるとおり、現在メルカリでは、国際展開におけるサービスリリースと並行して、基盤開発にも非常に力を入れています。AI-Native化を進めるうえで、このようなアーキテクチャ整備を同時に行うことは、AI前提の開発プロセスをより効率的かつ持続可能なものにするために極めて重要です。 先日の事業戦略発表会において共有しましたが,今後更にメルカリの海外展開を加速させるためにグローバル版のメルカリアプリを先日リリースしました.このアプリは現在提供してる日本版・アメリカ版のメルカリとは異なる新しいアプリであり,またアプリだけではなくその裏側のバックエンド基盤も新たに再構築しています. (参考: グローバル展開にむけたアプリと基盤の再構築 ) 新たな価値の創造 そして、世界中の人々の可能性をさらに広げていくためには、既存のサービスにとどまらず、これまでにない新たな価値を提供するサービスを生み出し続ける必要があります。 これまでは、新規プロジェクトや新規事業を立ち上げる際、まず人的リソースが大きな制約となり、構想段階で断念せざるを得ないケースも少なくありませんでした。しかしこれからは、そうした前提となっていた限界を一度手放し、「実現したい価値」から発想し、次々と形にしていける世界へと変わっていくと考えています。 その中で、新しい事業づくりにおけるAI Agent の活用は、今後ますます重要なテーマになります。すでに私たちは、並行してさまざまな実験的な取り組みを進めていますが、その成果については、来年のメイントピックとして改めてお伝えしたいと思います。ぜひ楽しみにしていてください。 Customer-Centricの究極形 そして、先ほども触れたとおり、AI-Centricな組織を築いていくことで、私たちはより多くの時間とエネルギーを、「お客さまに提供したい本質的な価値」に向けられるようになります。これは単なる効率化ではなく、Customer-Centricをさらに突き詰めていくための進化だと考えています。 AIを前提に、より深くお客さまの価値に向き合う。それこそが、私たちが目指す「AI-Native Company」の姿です。 今後に向けて メルカリでは、AI-Native Companyを目指すことを全社方針として明確に打ち出しました。その取り組みの中核として、ASDDを中心にAI Agentを前提とした開発プロセスの再構築を進めています。さらに、開発領域にとどまらず、全社のあらゆる業務をAI-Native化していくために AI Task Forceを立ち上げ、組織横断での変革にも着手しました。 これらの取り組みは、まだ始まったばかりで道半ばです。しかし、不確実性と向き合いながらも一歩ずつ前進することで、人がより本質的な価値創出に集中できる組織を実現していきたいと考えています。 これは私たちに限った話ではなく、社会全体としてもAI-Native化は確実に進みつつあります。すでに多くの業務をAI Agent化している方も多いでしょう。一方で、会社の規模が大きくなるほど、全社的にAIを本質的に浸透させる難易度は高まると、個人的には感じています。だからこそ、来年は社会にとって「AI Agentをいかに本質的に定着させるか」が問われる一年になると考えています。 私たち自身も現在、AI Agentを効果的に活用するための実験を日々重ねていますが、来年はそれを一部の取り組みにとどめず、より広く、より深く浸透させていくフェーズに入ります。すでに始まってはいますが、改めて「AI-Native、すなわちAgentベースでまずプロセスを考える」という姿勢を、組織全体で言い続け、実践し続ける一年にしていきたいと思います。 また、本稿では十分に触れられませんでしたが、来年はAIに関わるセキュリティ、ガバナンス、コンプライアンスも、より重要なテーマになっていくでしょう。これらは、AIを安全かつ持続的に活用し、全社に浸透させていくうえで欠かせない要素です。 今後も、メルカリにおけるAI-Native化の進捗については、継続的に発信していきたいと考えています。最後までお読みいただき、ありがとうございました。そして今年も大変お世話になりました。どうぞ良いお年をお迎えください。
アバター
メルペイ インターンでの挑戦と学び:EGP Cardsと向き合った3ヶ月間 こんにちは。メルペイのGrowth Platformでフロントエンド・エンジニアとしてインターンをしている @Yusaku (宮田 優作)です。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の25日目の記事です。 私は2025年10月からインターンを開始し、今月で3ヶ月目になりました(図1)。 この記事では、インターン期間中に取り組んだタスクと得た学びについて紹介します。 図1:オフィスで撮影した私の写真 チームについて 私が所属する Growth Platform Frontend チームは、Engagement Platform(通称EGP)という社内向けマーケティングツールを開発しています。 このツールを使うことで、マーケターや プロジェクトマネージャーは、ポイントやクーポンなどのインセンティブ配布、ランディングページ(LP)の作成・公開、キャンペーン作成といった CRM業務をコーディング不要で簡単に行うことができます(図2)。 図2:EGPのノーコードエディタ(EGP Content) 今回のインターンではEGP Cardsという機能の向上に取り組みました。EGP Cardsは、Web・iOS・Androidのクロスプラットフォームで利用できるカード型のコンポーネントを作成・公開する機能です。 EGP Cardsは、いわゆるWebページのエディタ機能(EGP Pages)とは異なり、サーバがUIの構造を返却するというServer Driven UIアーキテクチャを採用しています。エディタ上で作成されたコンポーネントのコンテンツはJSONファイルとして保存され、各プラットフォームで共通のUIとして描画されます(図3)。 Server Driven UIとEGP Cardsのアーキテクチャについては、同じくGrowth Platformチームの@togamiさん、@Stefanさんの記事をそれぞれご覧ください。 WYSIWYGウェブページビルダーを支える技術とServer Driven UIへの拡張 Supercharging User Engagement: How Mercari is Using Server-Driven UI to Reduce Time-to-Market 図3:EGP Cardsの編集画面 タスク1 – Dry Run for EGP Cards タスク概要:Dry Runとは? Dry Runとは、変数を設定し、そこにデータを挿入することで、状態をエミュレートできる機能のことです。これにより、API呼び出しを記述したり実機で動作確認を行ったりする前に、コンテンツの挙動を確認することができます。 このタスクでは、EGP CardsでDry Run機能を利用できるようにする実装を行いました(図4)。 図4:今回実装した、EGP CardsのDry Run機能 動作の仕組み Dry Run機能は、以下の流れで動作します。 利用者がDry Runを有効化し、フィールドにモックデータを入力する エディタが構造ツリーを再帰的に走査し、動的にJavaScriptのコードを評価して変数を値に置換する 置換された値がキャンバス上に表示される 実装の流れ 以下の流れで実装を進めました。 EGP Pagesに既に実装されていたDry Run機能について、コードリーディングやロギングを行い、実装ロジックを理解する EGP Cards特有の仕様を理解した上で、同様に利用できるDry Run機能を実装する コーディングの際には、EGP PagesとEGP Cardsで共通利用できそうな処理を探し、適度にファイルを切り出すことで、可読性・保守性を意識した実装を心がけました。 タスク2 – Content Agent Improvement for EGP Card 背景:Content Agentの課題 EGPのノーコードエディタ(EGP Content)は、CardsのほかにもPagesやE-mailsなど、複数の種類のコンテンツを扱うことができます。 また、EGP ContentにはAIエージェント(通称 Content Agent)が導入されており、対話を通じてコンテンツの要約や書き換えを行うことができます(図5)。 一方で、当時のContent Agentは、コンテンツ種別ごとのエディタ仕様を十分に理解していないという課題がありました。その結果、UIが崩れたコンテンツを生成してしまい、利用者の期待通りのアウトプットを提供できない可能性がありました。 図5:Content Agentの会話処理パイプライン 実装の流れ この課題を解決するため、以下の流れで実装を進めました。 EGP Cardsの仕様やデータ構造を記述したプロンプトを作成する 作成したプロンプトを、Content AgentのAgent Layerで条件付きで注入する EGP Cardsには、メディアクエリに対応していないことや、すべての要素がFlexで構成されていることなど、いくつかの制約があります。これらの制約や期待される出力をプロンプトに明示することで、Content AgentがCardsに適したコンテンツを生成できるようにしました(図6)。 図6:EGP CardsでContent Agentを利用する様子 学んだこと チーム開発におけるアウトプットの出し方を学んだこと Dry Run 機能の実装を通じて、チーム開発におけるアウトプットの出し方について多くの学びがありました。実装の正しさや機能の完成度だけでなく、Pull Request(PR)の切り方やレビューの受け方が、チーム全体の開発効率や生産性に大きく影響することを実感しました。 具体的には、バグ修正やリファクタリングであっても、PRのサイズが大きくなりすぎる場合やタスクのスコープ外に及ぶ場合には、別のPRとして切り出すことでレビューコストを抑えられることを学びました。また、コードやPRコメントには、なぜその実装にしたのか、どのような選択肢があり、何をしない判断をしたのかといった実装意図を明示することが重要です。これにより、レビュワーとの認識齟齬を防ぎ、建設的なレビューにつながると感じました。 レビューを受けた際にも、指摘内容をすぐに修正として反映するのではなく、まずはレビュワーの意図を正しく理解することが重要です。場合によっては背景や前提条件をすり合わせた上で議論することで、より良い設計や実装にたどり着けることを学びました。これらの経験を通じて、個人としてコードを書く力だけでなく、チームで価値を届けるためのコミュニケーションや姿勢の重要性を強く認識しました。 メルカリカルチャーを実体験として理解できたこと メルカリでは、情報の透明性やフラットな意思疎通によって、個人に大きな裁量が与えられていると言われることが多いです。実際にインターンを通じて、その点を強く実感しました。一方で、個人的に特に印象に残ったのは、英語を前提としたグローバルな開発環境です。 これまで参加してきたインターンはすべて日本語環境だったため、ドキュメントやコミュニケーション、議論の場がすべて英語になる経験は非常に新鮮でした。グローバルなチームである以上、英語でのスムーズな意思疎通が求められることは理解していましたが、実際に業務の中でそれを実践し、議論や開発を進められたことに大きなやりがいを感じました。 実際の業務では、英語で書かれたREADMEや仕様書を読み込んだ上でPull Requestを作成し、設計意図や懸念点を英語で説明・議論しました。認識の齟齬を防ぐため、必要に応じて日本語での補足も行いながら、主体的にコミュニケーションを取ることを意識しました。この経験を通じて、メルカリのカルチャーは単なるスローガンではなく、日々の業務に根付いたものだと感じました。 技術的挑戦を通じて、学びの広がりを再認識できたこと これまで私は、フロントエンドを主な技術領域として、インターンや個人開発に取り組んできました。そのため、フロントエンド領域における学びは、徐々に頭打ちになりつつあるのではないかと感じていました。 しかし、EGPというツールに触れたことで、その考えは大きく変わりました。EGPは非常にインタラクティブでリッチなUIを持つだけでなく、その裏側では、ノーコードによるコンテンツの作成・配信の仕組みや、安全かつ効率的にAI Agentとやりとりを行うための設計など、複雑で奥深いロジックが支えられていることを知りました。 タスクでは、ある程度抽象度のある状態で要件を受け取り、自分で具体的な実装タスクへ分解した上で設計・実装を進めました。また、EGPの使い方をキャッチアップしている最中に、イメージのプレビュー機能があることで利用者体験が向上するのではないかといった改善提案も行いました。 さらに、Content Agentの改善では、今回のCards向け実装に閉じることなく、将来的にPagesやE-mailsなど他のContent typeにも展開しやすいよう、Typeごとにプロンプトを切り出す設計とし、可読性や拡張性を意識しました。エンジニアがプロダクトの将来を見据えて設計・実装することが、利用者体験の向上や業務効率化につながり、結果として事業価値に直結する点は、メルカリならではの魅力だと感じています。 おわりに 今回のインターンでは、EGP Cardsという機能の向上に取り組みました。インターンを通じて、技術的なスキルだけでなく、プロダクトの価値やチームとの関わり方を含めてエンジニアリングに向き合う姿勢を学ぶことができました。 実務を通して得たこれらの学びを、今後の開発や自身の成長につなげていきたいと考えています。最後までお読みいただきありがとうございました。
アバター
こんにちは!メルカリ Engineering Office チームの @kiko と @aisaka です。 この記事は、 Mercari Advent Calendar 2025 の24日目の記事です。 先日の t-hiroi の記事「 メルカリが、AI時代にナレッジマネジメントに投資したわけ 」では、メルカリが推進するナレッジマネジメント戦略について紹介がありました。その中で特に重要なのが、AI-Native な会社を実現するためには 「AI が正しく学習できるコンテクスト(文脈)を整える」ことが不可欠であるという点です。 この考え方を軸に、メルカリでは全社を挙げてナレッジマネジメントを再設計してきました。 また先日も発表がありましたが、ナレッジの蓄積・共有基盤としてNotion の全社導入を進めています。 メルカリがNotion 全社導入で「AI-Native」企業への変革を加速 私たちは、このNotionを活用した全社ナレッジマネジメント基盤の構築・運用を担当しています。 本記事では、メルカリがどのように Notion 上でナレッジを整理しているのか、そしてその基盤となる Notion Architecture ver1.0をご紹介します! Notion Architectureとは Notion Architectureは、Mercariグループにおける情報を 「構造的に」「一貫して」「AIが活用しやすい形で」 管理するための設計指針です。 日々蓄積されるナレッジを会社の資産として活用するためには、散在しやすい社内の情報を極力構造化し、AIがコンテクストとして活用できる状態にすることが最も重要です。 そのため Notion Architectureでは、組織ごとの柔軟性は確保しながらも、グループ全体では共通のデータベース構造・テンプレート・メタデータを用いて標準化を行いました。 これにより次の状態を実現します: 情報が散在せず、全社横断で検索・参照できる ドキュメント構造とメタデータをなるべく統一し、AIが学習しやすく メンバーが日々記録した情報が、自然とグループ全体の資産へと統合される Notion上でのKnowledgeの置き場所 今後も引き続きアップデート予定ですが、まずver1.0として整理した構造を紹介します。 Mercari WorkspaceにおけるTeamspace設計 MercariのNotion Workspace配下には下記2種類のTeamspaceを設計しました。 Group-wide Teamspace(全社員向け)→ グループ共通のナレッジ基盤を構成する領域 Business / Domain Teamspace(事業・ドメインごと)→ 各チームが自律的に運用しながらナレッジを管理する領域 この2層構造を採用した背景には、 事業・ドメインごとの文化に合わせた柔軟性 全社では AI が学習しやすい統一された構造の維持 という両立を実現したい、という狙いがあります。 また、メルカリは約 2,100 名規模のグループ会社であり、Teamspace が増えすぎると管理コストが跳ね上がります。そのため、Teamspace の種類を最小限に絞ることも重要なポイントでした。 Teamspace間のKnowledge構造 各 Business / Domain Teamspace は、それぞれが独立運用できるよう設計しつつ、Group-wide Teamspace とリンクした状態で情報が流れる構造 になっています。 こうすることで「柔軟な運用 × 集約されたナレッジ基盤」の両立を実現しています。 では、それぞれのTeamspaceが具体的にどのような役割を担い、どう連携しているのかを説明していきます。 以下では、Mercari Group Teamspaceと事業・ドメイン別Teamspaceそれぞれの目的と役割を整理しています。この2つのTeamspaceは補完し合い、全社のナレッジ基盤を支えています。 Mercari Group Teamspace 目的 全社共通のナレッジ基盤として、Mercari Group Teamspaceは、グループ全体の中核となる複数の共通データベースを保持しハブとして機能することを目的としています。 役割 共通データベースを保持し、文書を一元管理する ドキュメントテンプレート、メタデータ設計、カテゴリ定義など「全社標準」を提供する 事業・ドメイン別Teamspaceからのページ作成・参照を受け入れるハブとして機能する 事業・ドメイン別 Teamspace 目的 事業やドメインごとの運用自由度を確保しつつ、Group-wide構造とリンクされた状態で情報を発信・管理することを目的としています。 役割 Group-wide共通DBへの新規ページ作成を行う(=情報を正しい構造に流す) Group-wide DBのViewを表示・参照し、自部門に関連する情報を整理・活用する 必要に応じて事業独自のDBを保持し、ローカルでの文書管理を支援する ナレッジはどのように管理されるのか 標準化されたドキュメント構造とデータベース管理 なぜデータベースとテンプレートによる標準化が必要なのか おそらく多くの企業さんでも同様の課題を持っているかと思いますが、メルカリでは長年ナレッジが散在してしまう課題を抱えています。 例えば: プロジェクト資料の保存場所が統一されておらず、探すのに時間がかかる ドキュメントの構造や粒度が人によって異なり、AIが文脈を正しく理解できない こうした状態では記録した情報が活用されず、「書いたけど探せない」「探せないから新しく作る」という負のサイクルに陥ります。 メルカリのアプローチ:共通データベース × テンプレートによる自然な標準化 これを解決するため、Notion 上に作成されるすべてのドキュメントは、用途別に整理された共通データベース上で管理されます。 各データベースには目的に応じたテンプレートを用意し、文書構造・メタデータ・プロパティの標準化をしています。 こうすることにより 「記録すれば自然と整理される」ナレッジ基盤 の実現を目指しています。 Group-wide Databaseの設計思想 では、具体的にどのようなデータベース群を設計したのか紹介します。 Group-wide Databaseは、Mercariグループ全体で共通化されたナレッジ基盤の中核を担うデータベース群です。 情報をタイプ別に整理し、横断検索・AI活用・全社統一運用を支える目的で設計されています。 設計思想 目的 ドキュメント構造を統一し、あらゆる情報を一貫したフォーマットで再利用・検索できる状態を作る 方針 各DBは「用途単位」で分割する テンプレートを通じて文書構造・メタデータを標準化 同じフォーマットで記録・共有できるようにする (AIが学習しやすくする) テンプレート利用によるドキュメント標準化の推進 文書作成時は、各データベース(DB)に紐づいた新規ページ作成テンプレートを使用します。 ※ ここでのテンプレートは、Notion公式マーケットプレースのものではなく、Mercari Workspace内で管理される共通テンプレートを指します。 テンプレートを利用することで、文書構成、メタデータ、プロパティを標準化し、全員が同じ形式と用語でナレッジを共有できるようにします。 下記のような効果やメリットを見込んでいます。 コラボレーションの推進 プロセス変更への柔軟対応 AI が学習しやすい文書構造 Notion Architecture ver1.0のチュートリアル ここまで、Notion Architecture ver1.0の構造とその設計背景などを紹介してきました。 メルカリがどのように Notion 上でナレッジを整理しているのか、Notionの画面を投影しながら説明します。これからNotionを導入する方は、参考程度に。既にNotionを導入している方からは、先駆者として「おいおいこういう事が起こるから気をつけると良いよ」といったアドバイスをいただけると嬉しいです! おわりに 本記事では、メルカリが全社で取り組むナレッジマネジメントの基盤として構築しているNotion Architecture ver1.0の概要とチュートリアルを紹介しました。 Notion Architectureはまだ進化の途上であり、今後も組織の拡大や AI 活用の進展に合わせて継続的にアップデートしていきます! 最後になりますが、こうした全社規模のプロジェクトには、様々な方によるサポート、貢献が不可欠です。今回のNotion導入も組織、チーム、会社を跨いだ多くの関係者の皆さんの協力のおかげで実現できました。 特に、Notion導入を先にされていたSansanさんには、構造やテンプレート作成の際に大変お世話になりました。会社をまたいだ繋がりがあったのも本プロジェクトの醍醐味でした。 明日の記事はメルカリのCTO @kimuras さんによる最終記事です。引き続き最後までお楽しみください!
アバター
こんにちは。メルカリで暗号資産交換業を提供しているメルコインCTOのpoohです。 この記事は、 Mercari Advent Calendar 2025 の24日目の記事です。 メルカリグループ内で、CAST分析の取り組みが広がりつつあります。メルコインではすでに導入しており、他のプロダクトチームでも検討や試行が始まっています。 私はこれまで10年以上、SREとして障害対応やオンコール運用に関わってきました。 インフラ、SRE、データ基盤と領域は違っても、やってきたことは同じです。 障害が起きる。 振り返る。 再発防止策を考える。 それなりに真剣にやってきたはずなのに、 しばらくすると、よく似た構図の問題がまた起きる。 この違和感を、長い間うまく説明できずにいました。 再発防止は「サボられている」わけではない 最初に強調しておきたいのは、 多くの現場で再発防止はちゃんと考えられている、ということです。 レビューで拾えたはずだった QAの観点が足りなかった 想定が甘かった 次はもう少し丁寧にやろう どれも正論です。 真面目に向き合っている証拠でもあります。 それでも、思ったように再発防止が効かない。 これは意識や姿勢の問題ではない、と感じていました。 原因は、いつも「最後」に集まる 振り返りをすると、原因はどうしてもリリース直前や本番直前に寄りがちです。 QAで見落とした。 本番確認が足りなかった。 でも少し引いて見ると、違和感があります。 仕様を考えた人がいて、 実装した人がいて、 レビューした人がいて、 QA判断をした人がいる。 そのすべてを通り抜けて、 最後の工程だけを「根本原因」と呼ぶのは、無理がある。 この違和感に、はっきり名前をつけてくれたのがCAST分析でした。 Google SREが直面している「エラーバジェット0」の世界 CAST分析に興味を持った大きなきっかけの一つが、 Google SREが「エラーバジェット0のシステム」を前提に考え始めている、という話( The Evolution of SRE at Google )です。 SREの世界では、 エラーバジェットを使ってスピードと安全性のバランスを取ります。 一方で、Google自身が向き合っている現実もあります。 金融、規制対応、社会インフラ。 サービスが落ちてはいけない。 失敗が許されない。 それでも人が設計し、人が運用する。 today our products have losses that must never occur—error budgets of zero. The types of failures we need to prevent have evolved beyond what error budgets can effectively address. 現在では私たちの製品には絶対に発生してはならない損失、つまりエラーバジェットがゼロという状況が存在します。防止すべき障害の種類は、エラーバジェットが効果的に対処できる範囲を超えています。 エラーバジェットを持てないシステムでは、 「失敗は起きる前提でうまく付き合う」というモデルだけでは足りない。 その文脈で使われていたのが、CAST分析でした。 CAST分析は、問いを変える CAST分析が前提にしている考え方は、とてもシンプルです。 障害は、誰かの判断ミスで起きたのではない。 その判断を「正しい」と思わせる状況が積み重なった結果として起きる。 だから問うべきなのは、 なぜその判断をしたのか。 なぜその選択が合理的に見えたのか。 結果を知ったあとに 「あの時こうすべきだった」と言うのは簡単ですが、 それは後知恵バイアスです。 CAST分析は、 当時の情報、制約、前提の中での合理性を丁寧に扱います。 実際のCAST分析は、こう進む(抽象化した例) ここから、実際にメルカリで行っているCAST分析の一部を、 特定につながらない形で紹介します。 題材にしたのは、 既存のプロダクト施策に対する、ごく小さな運用変更 でした。 変更内容自体はシンプルで、 「影響範囲は広いが、作業内容は限定的」 と判断されていたものです。 結果としては、 お客さまがサービスを正しく利用できない状態が一定時間続いてしまいました。 従来の振り返りだと、こうなる 普通に振り返ると、こう整理できます。 必要な設定の一部が更新されていなかった レビューやQAで気づけなかった 本番確認が十分ではなかった 事実としては正しい。 でも、ここから出てくる対策はだいたい同じです。 チェックリストを作る レビューを強化する QAを必須にする 「もっとちゃんとやろう」で終わってしまう。 CAST分析で見えた構造 CAST分析では、原因を一点に絞りません。 システム全体の構造を見ます。 このケースで見えてきたのは、こんな状況でした。 過去は特定の設定だけ更新すれば問題なかった時代があった 仕様は段階的に変化していたが、手順や認識は更新されていなかった PM・エンジニア・QAがそれぞれ異なる前提をもとに判断していた PMが自分で設定や状態を確認する手段を持っていなかった システム上は「仕様通りの挙動」が続き、監視では異常と判定されなかった 誰かがサボったわけでも、 誰かが雑だったわけでもありません。 その構造の中にいれば、同じ判断をするのが自然 という状態ができていました。 出てきた再発防止策が、まったく違う ここが、CAST分析の一番大きな違いです。 出てきた提言は、 「誰が気をつけるか」ではありません。 不正な設定の組み合わせは、そもそも保存できないようにする 状態を人に聞かなくても確認できる仕組みを用意する 「施策が意図通りに機能しているか」を直接捉える指標を持つ 深夜や休日の切り替えを原則避ける 「軽微な変更」の定義を、工数ではなく失敗時の損失で考える すべて、 個人の注意力に依存しない改善 です。これらの提言には従来実施してきたretrospectiveででたものもあります。網羅性ある振り返りができるというのがお気に入りです。 経営陣の視点で見たときの意味 このCAST分析が、 経営陣が読んだときに意味を持つ理由はここにあります。 現場の誰かを責める話にならない なぜその判断が起きたのかを、構造として説明できる 再発防止が「人の問題」ではなく「組織と仕組みの話」になる 同じことが別のプロダクトでも起こりうると理解できる CAST分析は、 障害対応の手法というより、 プロダクト開発を安全にスケールさせるための考え方 だと感じています。 再発防止を、本当に機能させたいなら もし、 振り返りをちゃんとやっているのに、 同じ構図の問題が繰り返される。 対策が注意喚起やチェックリストに寄っている。 そんな感覚があるなら、 CAST分析は一度きちんと調べてみる価値があります。 銀の弾丸ではありません。 でも、問いの立て方が変わります。 それだけで、 再発防止は少しずつ、 本当に機能し始めます。 CAST分析、 ぜひ一度触れてみてください。 参考資料 チュートリアル 最初の15分ぐらいおすすめ ハンドブック 1-2章までは読みやすく、先を読みたくなります。 明日の記事は kimurasさんとYusakuさんです。引き続きお楽しみください。
アバター
こんにちは。メルペイ Payment Mobileチームで iOSエンジニアをしている @kubomi です。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の23日目の記事です。 はじめに 最近、自分の手でコードを書いていますか? AIに任せれば動くコードが出てくる「Vibe Coding」時代。便利な反面、私はこんな不安を感じるようになりました。 「このコード、本当に理解できてる?」 「雰囲気で理解しているつもりになってるのでは?」 同じ不安を感じているエンジニアの方々は、きっと多いのではないでしょうか。 AIがコードを書いてくれる時代だからこそ、AIを使って「学ぶ」ことは重要ではないか ——そう考えて私が試したのが、「AIにコードを書かせる」のではなく「AIに学習を設計させる」というアプローチです。 この記事では、私が実践した「AI駆動学習」の方法を、具体的なプロンプトとともに紹介します。AIを使ってオーダーメイドの学習計画・教材を生成し、プログラミング言語を体系的に学び直す方法です。 こんな方におすすめ: AIに頼りきりで自分の理解度に不安がある 新しい言語を体系的に学びたい 学習を始めても途中で挫折しがち 私の「AI駆動学習」サイクル 私が実践しているのは、学習のあらゆるステップでAIをフル活用する「AI駆動学習サイクル」です。このサイクルは4つのステップで構成されています。 Step 1: Plan — AIが学習プランを作る 公式ドキュメントを参照し、体系的な学習計画を作成してもらいます。何を・いつ・どの順番で学ぶかが明確になります。 Step 2: Learn — AIが教材を作って、人が学ぶ 学習プランに沿って、解説・サンプルコード・演習課題を含む教材を生成してもらいます。そのまま実行できるファイル形式で出力させるのがポイントです。 Step 3: Practice — 人が課題を実装して、AIがレビュー 教材の演習課題を自分で実装し、AIにコードレビューしてもらいます。ここが一番学びが深まるステップです。 Step 4: Track — AIが進捗管理 学習プランからTODOリストを生成し、進捗を可視化します。次にやることが常に明確になり、継続しやすくなります。 つまり、ほとんどAI任せの学習サイクルです。人間である私がやることは、教材を読んで理解し、課題を実装することだけ。それ以外の「プランニング」「教材作成」「レビュー」「進捗管理」はすべてAIに任せています。 ここからは、各ステップの詳細と、実際に効果的だったプロンプトを共有していきます。 準備するもの 今回使用するのは Cursor です。 CursorはVS Codeベースのエディタで、AIとの対話機能が統合されています。なぜCursorを選んだかというと、 学習プランの作成から、教材の生成、コードの実行、レビューまでがすべて1つの環境で完結する からです。 ChatGPTなどのチャットUIでも学習プランは作れますが、生成されたコードをコピペして別のエディタで動かす手間が発生します。Cursorなら、AIが生成したファイルをそのまま保存し、その場で実行して動作確認できます。この「シームレスさ」が学習の継続には重要でした。 Cursor以外でも、ClineなどのIDE統合型AIエージェントであれば同様のワークフローが実現できると思います。 準備ができたら、空のディレクトリを1つ作成してCursorで開きましょう。このディレクトリに、学習プラン・教材・進捗管理ファイルをすべて格納していきます。 Step 1: Plan — 学習プランを作る まずはCursorに学習計画を作ってもらいます。 使用したプロンプト: 公式ドキュメント(https://docs.swift.org/swift-book/)を元に、 10日でSwiftをマスターする学習計画を作って、mdファイルで出力して。 ここでのポイントは2つあります。 ポイント1:公式ドキュメントを参照させること。 これによって、断片的ではなく体系的な学習プランを組み立ててくれます。公式ドキュメントを基準にすることで、正確で網羅的なカリキュラムが得られます。 ポイント2:期間を区切ること 「10日でマスターする」といった期間を指定することで、学習量や内容を自然に調整してくれます。無理のないペースで進められるプランが、あっという間に完成しました。 生成された学習プランの例(抜粋) これだけで、何を・いつ・どの順番で学ぶかが明確になります。 Step 2: Learn — 教材を作る 次に、先ほど作った学習プランをもとに、日ごとの教材をCursorに作らせます。 使用したプロンプト: 学習プランを元に、各日の教材を作って。 各日ごとにディレクトリを作成して、その中に解説・サンプルコード・演習課題を含む実行可能な .swift ファイルを含めて。 このプロンプトのポイントは2つあります。 ポイント1:日ごとにディレクトリを分ける 日ごとにディレクトリを分けることで、学習プランと教材が対応し、管理しやすくなります。 ポイント2:実行可能なファイル形式で出力させること これによって教材が「ただの読み物」で終わらないのです。生成されたファイルをそのまま実行して試せる。すぐに手を動かして学習できる。ちょうど 教材とIDEが合体したような体験 になりました。 生成されるディレクトリ構成 swift-learning/ ├── README.md(学習プラン) ├── Day1/ │ └── 01_Basics.swift ├── Day2/ │ └── 02_ControlFlow.swift ├── Day3/ │ └── 03_Optionals.swift ... 生成された教材ファイルの例(抜粋) /* Day 1: Swiftの基礎と基本構文 Swift公式ドキュメント: https://docs.swift.org/swift-book/documentation/the-swift-programming-language */ // MARK: - 1. 変数と定数 print("=== 変数と定数 ===") // 変数(変更可能) var myVariable = 42 myVariable = 50 print("変数: \(myVariable)") // 定数(変更不可) let myConstant = 42 // myConstant = 50 // エラー: 定数は変更できません print("定数: \(myConstant)") ... /* 演習1: 変数と定数 - あなたの名前を定数として定義してください - あなたの年齢を変数として定義してください - 年齢を1つ増やして表示してください */ // ここにコードを書いてください /* 演習2: 文字列操作 - あなたの名前と年齢を使って「私の名前は[名前]で、[年齢]歳です」というメッセージを作成してください - 文字列補間を使用してください */ // ここにコードを書いてください コメントで解説が書かれており、サンプルコードのあとに演習問題が用意されています。コードを読んで、動かして、自分で書いてみる。この一連の流れが1つのファイルで完結します。 教材を読んでいて分からないことがあれば、その場でCursorに質問できるのもこの学習スタイルの強みです。「なぜここでXXXを使うの?」「他の書き方はある?」など、疑問点をどんどん聞くことで理解が深まります。 ただし、AIはハルシネーション(誤った情報の生成)を起こすこともあるので、必要に応じて公式ドキュメントと照らし合わせながら学ぶことをおすすめします。 Step 3: Practice — 演習課題をレビューしてもらう 3つ目のステップは、最も効果を実感できた「Practice」です。 教材に含まれる演習課題を自分で実装したあと、そのコードをCursorにレビューしてもらいます。 使用したプロンプト: 課題をレビューして、改善点を教えて。もっとSwiftらしい書き方ある? 「Swiftらしい書き方」というように聞くことで、その言語ならではの洗練された表現やベストプラクティスを提案してくれます。 理解度クイズ また、Cursorにクイズを出題させて理解度をチェックするのも効果的でした。 使用したプロンプト: 今日学んだ内容から5問クイズを出して。 すると、すぐに確認テストを作ってくれます。このように、アウトプット中心で学ぶことで、確実に身につく実感がありました。 Step 4: Track — 進捗管理 最後のステップは、進捗管理の自動化です。 使用したプロンプト: 学習プランをもとにTODOリストを作って進捗管理して。 学習プランからTODOリストを生成させ、1つ終わったらCursorに報告して更新してもらいます。 生成された進捗管理ファイルの例 # Swift学習 進捗管理 ## 📊 進捗サマリー - **完了**: 3/10日 - **進捗率**: 30% ## ✅ TODOリスト - [x] Day 1: Swiftの基礎と基本構文 - [x] Day 2: 制御フローと関数 - [x] Day 3: オプショナルとエラーハンドリング - [ ] Day 4: コレクション型 - [ ] Day 5: クラスと構造体 - [ ] Day 6: プロトコルと拡張 - [ ] Day 7: ジェネリクス - [ ] Day 8: クロージャと関数型プログラミング - [ ] Day 9: エラーハンドリングと非同期処理 - [ ] Day 10: 実践的なSwiftアプリケーション 進捗が可視化されるとモチベーションも保ちやすいですし、次にやることが常に明確になります。「今日はどこまでやったか」「明日は何をすればいいか」を考える手間がなくなり、学習のハードルが下がりました。 学習で挫折しがちなポイントの1つが「どこまでやったか分からなくなること」なので、ここをCursorに任せてしまうのはかなりおすすめです。 AI駆動学習のメリット この学習サイクルを実践してみて、いくつかのメリットを実感しました。 オーダーメイドの教材が手に入る 自分の理解度や使える時間に合わせて、カスタマイズされた学習プランと教材を作れます。「1日30分しか時間が取れない」「Python中級者のためのJava入門」など、自分の状況をプロンプトに書くだけで、かなりパーソナライズされた教材が出てきます。 アウトプット中心で定着する 教材を読むだけでなく、実際にコードを書き、AIにレビューしてもらうことで、理解が深まります。 継続しやすい 進捗管理をAIに任せることで、「今日は何をすればいいか」を考える手間がなくなります。学習のハードルが下がり、継続しやすくなりました。 新しい領域に踏み出しやすい 体系的に学べる安心感があると、これまで手を出しにくかった新しい言語やフレームワークにも挑戦しやすくなります。 まとめ AIの進化によって、私たちが自分の手でコードを書く機会はこれからますます減っていくでしょう。だからこそ、学ぶ時間を意識的に確保することが大事だと改めて感じました。 AIを使えば、自分の理解度や時間に合わせたオーダーメイドの教材を作れます。そのおかげで、新しい言語にも挑戦しやすくなり、担当領域の外へも踏み出せると実感しました。 私自身は、次のステップとしてAndroid開発に挑戦するためにKotlinを学ぼうと思っています。 Vibe Codingでコードを書かなくなった方、AIに頼りっぱなしで不安を感じている方、ぜひこの「AI駆動学習サイクル」を試してみてください。AIを使って学ぶという、新しい学習体験が待っています。 付録:そのまま使えるプロンプト集 実際に使ったプロンプトをまとめました。 [プログラミング言語] や [N] の部分を置き換えてすぐに試せます。 Step 1: 学習計画生成 公式ドキュメント([公式ドキュメントのURL])を元に、[N]日で[プログラミング言語]をマスターする学習計画を作って、mdファイルで出力して。 Step 2: 教材生成 学習プランを元に、各日の教材を作って。各日ごとにディレクトリを作成して、その中に解説・サンプルコード・演習課題を含む実行可能なファイルを含めて。 Step 3: レビュー 課題をレビューして、改善点を教えて。もっと[プログラミング言語]らしい書き方ある? 理解度クイズ 今日学んだ内容から5問クイズを出して。 Step 4: 進捗管理 学習プランをもとにTODOリストを作って進捗管理して。 明日の記事は poohさんです。引き続きお楽しみください。
アバター
はじめに こんにちは。メルペイPartner Platformチームでバックエンドエンジニアのインターンをしている @taki と申します。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の22日目の記事です。 Partner Platformチームではメルペイの加盟店向けの管理画面を開発しています。本記事では、インターン期間中に取り組んだタスクの一つである、管理画面の認証方式をマイグレーションした経験について紹介します。 背景 メルペイでは、加盟店向けに管理画面を提供しています。この画面では、店舗でのメルペイの取引履歴の確認など、さまざまな機能を利用できます。 既存の認証方式 現在の管理画面では、以下のようなフローの認証方式を採用しています。 ログイン : お客さまが送信したメールアドレス・パスワードを用いて、加盟店管理画面側で認証を行います。 リソース取得 : 認証が成功するとアクセストークンが発行され、そのトークンを用いて依存先の各マイクロサービスにリクエストを行います。 このロジックはシンプルですが、大きな課題があります。それは、他サービス(例えばメルカリShopsやメルカリAdsなど)の加盟店管理画面とは独立した認証体系になってしまっているということです。 そのため、例えばメルペイとメルカリShopsの両方を利用している加盟店のスタッフは、それぞれのサービスの管理画面で異なるアカウントを発行する必要があります。 新しい認証方式 そこで今回、この課題の解決に向けて、認証方式のマイグレーションを行いました。新しい方式の基本的なフローは以下の通りです。 ログイン : お客さまはまず認可サーバにメールアドレス・パスワードを送信し、認証を行います。ここで使用する認可サーバは、メルカリのIDPチームが提供しているものです。 トークンを要求 : 加盟店管理画面側から、認可用のトークンを認可サーバにリクエストします。 トークンを発行 : 認可サーバがトークンを発行します。 リソース取得 : 発行されたトークンを用いて、加盟店管理画面から依存先のマイクロサービスにアクセスします。 この方式では、認証・認可のフローが各サービスから分離され、共通の認可サーバに集約されます(下図参照)。これにより、将来的にはお客さまがさまざまなサービスの加盟店管理画面に、共通のアカウントでログインできるようになります。(メルカリShopsに関してはOAuthへのマイグレーションが別途で必要になります。) この仕組みは、技術的にはOAuth 2.0およびOIDC(OpenID Connect)というプロトコルを使用しています。以下では、OAuth 2.0について簡単に説明します。 OAuth 2.0とは OAuth 2.0は、サードパーティアプリケーションがお客さまのリソースに安全にアクセスするための認可(Authorization)プロトコルです。 OAuth 2.0の登場人物 OAuth 2.0では、以下の4つの登場人物が出てきます。 リソースオーナー(Resource Owner) : リソースの所有者であるお客さま。今回のケースでは加盟店のスタッフです。 クライアント(Client) : リソースにアクセスしたいアプリケーション。今回のケースでは加盟店管理画面(のBFF:Backend For Frontend)です。 認可サーバ(Authorization Server) : お客さまを認証し、アクセストークンを発行するサーバ。今回のケースではIDPチームが提供する認可サーバです。 リソースサーバ(Resource Server) : 保護されたリソースを保持するサーバ。今回のケースでは加盟店管理画面から呼び出される各種マイクロサービスです。 OAuth 2.0のフロー OAuth 2.0にはいくつかのフロー(グラントタイプ)があります。その中で、Webアプリケーションで最も一般的なのはAuthorization Code Flowというものです。今回実装したフローも、このフローを採用しています。 基本的な流れは以下の通りです。 認可リクエスト : お客さまがログインを試みると、クライアントはお客さまを認可サーバにリダイレクトし、認可を要求します。 ログイン : 認可サーバでお客さまがログインします。 認可コードの発行 : 認可サーバは認可コードを発行し、クライアントにリダイレクトします。 トークンを要求 : クライアントは認可コードを認可サーバに送信し、アクセストークンを要求します。 トークンを発行 : 認可サーバは、正当なクライアントからのリクエストかどうかを検証した上で、アクセストークンを発行します。 リソース取得 : クライアントはアクセストークンを使用して、リソースサーバのAPIにアクセスします。 先ほどの図ではこのフローを一部省略して描いていましたが、OAuth 2.0のフローを踏まえてちゃんと描くと以下のような形になります。 今回の開発内容 実装前の準備 実装に入る前に、まず要件を整理する必要がありました。具体的には、既存のロジックのどの部分をどの順序で変更するべきか調査し、チケットを切るところから始めました。 この際、参考にしたのがスキマバイト「メルカリ ハロ」の加盟店管理画面です。メルカリ ハロは最も早くOAuthによる認可を導入していたサービスでした。実際にメルカリ ハロの管理画面を触ってみた上で、メルカリ ハロへのOAuth導入時のドキュメント、および実装を照らし合わせながら理解することで、実装の進め方の解像度を大きく高めることができました。 残念ながらメルカリ ハロは2025年12月をもってサービスが終了しましたが、メルカリ ハロで行われたさまざまな技術的挑戦で得られた知見は、こうして他のプロダクトに生かし続けられるということを実感しました。 実装 実装の方針を立てた後、実際の開発に取り掛かりました。認可サーバ側の認証・認可のロジックはIDPチーム側で既に実装されていたため、今回の開発では加盟店管理画面のBFFにおける処理の実装がメインとなりました。具体的には、上の図の③のリダイレクトを受け付ける部分や、④⑤のトークン発行の部分などです。 OAuthのフローでは、加盟店管理画面のBFFは、ブラウザとの直接通信を多用します。例えば、ブラウザにリダイレクトを行わせたり、⑤で受け取ったアクセストークンをブラウザのCookieにセットしたりする必要があります。 そのため、これらの処理はサーバ間通信の仕組みであるgRPCサーバではなく、HTTPサーバで行うのが適切です。しかし、元々のBFFにはgRPCサーバしか存在しなかったため、新たにHTTPサーバを構築する必要がありました(下図の赤色部分)。 実装では、gRPCサーバと同一プロセス内の別ポートでHTTPサーバを立ち上げるようにしました。さらに、Kubernetesのポート公開の設定やGatewayのプロキシ設定を変更することで、無事にHTTPサーバを疎通させることができました。 続いて、新しく立てたHTTPサーバに、③や④⑤などのフローを行うためのエンドポイントを実装し、テスト環境でOAuthによる認可を動かすところまでを実現できました。 インターンの感想 メルペイでの約3ヶ月間のインターンを通して、強く感じたことは、メルペイのエンジニアは一般的なエンジニアの担当領域にとどまらず、事業側へのインパクトを解像度高く把握してプロダクトに関わっているということです。 実際、自分の周りのメンターの方々は、単に与えられた仕様を実装するのではなく、「自分の開発しているものが、お客さまにどのような価値をもたらし、その価値が事業の成長や収益にどうつながるのか」まで踏み込んで議論しながらプロダクトに向き合っていると感じました。 そういった視点を前提に、必要に応じて周囲のチームと連携しながら、仕様の見直しなども含めて主体的に開発を進めていく──このスタイルがマネージャー層だけでなく、一人ひとりのエンジニアにまで根付いていることは、自分にとって大きな驚きであり、とても魅力的な環境だと感じました。 そして、メルペイのエンジニアがこのような動きをできる理由の一つとして、メルカリ・メルペイにはVibe CodingやAgentic Codingが深く浸透しているということがあると感じました。「Coding Agentの登場によって、エンジニアの役割はアーキテクトへと変化していく」とはよく言われていることですが、メルカリではこの変化がすでにかなり進んでいると実感すると共に、自分もこのようなエンジニアを目指したいと感じる経験となりました。 終わりに この記事では、メルペイのインターンで取り組んだ認証方式のマイグレーション、そしてインターンを通して感じたことをまとめました。 インターン期間中は、この記事で述べた内容に限らず、技術的な面でも、それ以外の面でも、さまざまな学びを得ることができました。 残りのインターン期間では、OAuthの導入に関するQAを実施し、本番環境へのリリースまで完了させたいと考えています。 明日の記事は@kubomiさんです。引き続きお楽しみください。
アバター
こんにちは、メルカリのAI Task Forceでイネーブラー(Enabler)をしている @akkie です。 この記事は、 Mercari Advent Calendar 2025 の21日目の記事です。 すでにご存知の方も多いかもしれませんが、現在メルカリは「AI-Native」をテーマに掲げ、AIを基盤として組織とプロダクトを抜本的に変革する 取り組み を進めています。AI Task Forceは、メルカリをAI Nativeな組織へと変革するために立ち上がった100名規模のチームで、Enablerは「各領域でAI Nativeな業務変革を主導する役割」とされています。 既存のAI/LLMツールの活用はもちろん、プロダクトへのAI組み込みや、マニュアル作業が多い業務のDX推進など、その活動は多岐にわたります。 最近では、特に開発における生産性向上を目的として pj-double に多くのエンジニアが参加しています。 しかしこの記事では、生産性を上げるために「どうAIに効率的に仕事をさせるか」ではなく、AIを使わない部分の仕事について話したいと思います。 システムにAIを使わないに越したことはない AI Task Forceに居ながらこんなこと言っていいのか?と思うかもしれませんが、多くのエンジニアが、目的を達成するために「AIを使わないで済むなら使わないに越したことはない」に同意するのではないでしょうか。 よくあるジョークとして、コーディングしているエンジニアの様子を想像してみて、と非エンジニアの人に聞くと、目まぐるしく手を動かしてキーボードにコードを打ちこんでいる様子を想像する、けれど実際のエンジニアを見てみると、キーボードから手を離し頭を抱えながら、画面に大量に表示されたエラーをジッと見つめ原因を探っている時間の方が何十倍も長いということがあります。これは事実です。 最近ではまずAIが70%正しいコードを書いてくれるようになった分、なおさら人間はコードを打ち込むよりも「頭を抱えてコードが動かない問題の原因を探っている」時間の方が長くなったかもしれません。使っているライブラリの古いバージョンを前提にAIがコードを書いてきたり、サードパーティのAPI仕様を理解していなかったり、間違える要素はいくらでもありますし、AIの出力は下手に正しそうに見える分デバッグにも時間がかかります。 システム開発はいわば人間が行ってきたことを自動化することが仕事です。メルカリのアプリ開発も、これまで街中のフリーマーケットで人と人との間で行われていた商売をシステムで行うための大きな自動化に取り組んでいるとも言えるでしょう。 AIはその大きな助けになってくれますが、人間がAIに正しく意図を伝えられていないだけというケースも含めてまだ「70%正しい」くらいの出力を返してくるのが現状です。 それと比べて、シェルにコマンドを打ち込んだり、コードをDockerイメージ上で動かす作業はほぼ100%(もちろん環境要因で動かなくなるときはあるでしょうが)常に同じレスポンスを返してくれます。ターミナルを開いて “echo $(( 100 + 200 ))” と打てばいつだって画面には300と表示されるし、お金もかかりません。 「100+200の答えが知りたい」ときに、ChatGPTを開いて「100+200は?」と聞く人はいませんよね。たとえ聞いてもChatGPTは多くの場合正解を返してくるでしょうが、コストパフォーマンスや精度を考えるとこんなことをAIに聞くコードをシステムに組み込む人は居ないわけです。 また、数珠つなぎにAIに仕事を連携させていくと、その掛け算で精度は下がり、すぐに使い物にならなくなるでしょう。 つまり、仕事(特にシステム内で行うもの)は「AIを使わずとも自動化できるのであれば、使わないに越したことはない」ということが前提にあるはずです。もちろんAIの精度を上げる努力も必要ですが、決定論的なロジックで解決できる課題にAIを持ち込むべきではありません。AIは確率論だけれど、システムはできる限り決定論であるべきです。 AI Task Forceというチームに所属しているので、色んな組織から「これ、AIで解決できませんか?」という相談を受けます。しかし具体的に話を聞いてみると、「それはAI使わなくても解決できますね」という回答になることがよくありました。「アクセスログから◯◯の売上分析をしたい」、「人事システムに溜まった△△のデータを可視化・検索したい」、などはその例でしょう。AIにそれらをさせるのではなくそれらを実現するコードをAIに書かせる、という意味ではたくさんAIを利用することにはなりますが、一度きりでは済まないような作業をAI自身にやらせるのは悪手だと考えます。AIに魚を持ってこさせるのではなく、釣り竿を作らせるのがAIの良い使い方と考えます。 とにかく、どうしてもAIにしか解決が難しい課題にのみAIを使いたい。私にとってこの半年の仕事は、いわば「いかにAIを使わないで済むかを考える」ことでした。 また、AIを使うかどうかは内部の実装の話だけではなく、ユーザとのインタフェースにも同じことが言えます。何にでもAIを使うことがもてはやされる時代ですが、あえてAIを使わない選択肢をとることで向上する生産性もあります。あなたが提供しようとしている価値に、本当に自然言語によるユーザとのインタフェースは必要でしょうか?mcpサーバは必要でしょうか? UNIXコマンドの多くが対話型のコマンドを避け、パイプされた他のコマンドとの組み合わせによって自動化が容易になったように、自分の作っているものに自然言語による対話型インタフェースが必要かは常に慎重な見定めが必要です。 社内ツール開発における「9割」の正体 たとえAIを使って業務改善のためのツールを開発することが決まっても、大半の時間はAIと全く関係ないところに使われていることにも気が付きました。特にインフラ周りです。 LLMが当たり前に使われるようになるずっと前から、AIを使ったプロダクト開発においては**「データの収集やインフラ整備が工数の9割を占め、モデル自体の設計・改善は1割程度である」**と言われてきました。 この現実は、LLMが登場しAI技術が進化しても変わってないように感じています。 たとえば機械学習モデルが実際に価値を生むAPIとして、高可用性・低遅延・スケーラビリティを維持して稼働し続けるためには、モデルの学習や評価よりも多くの、複雑なインフラおよびMLOps作業が不可欠になります。 具体的にタスクを挙げてみます。 基盤・ネットワーク: コンテナ化 Kubernetes/サーバレス設定 DNS SSL証明書 ロードバランサ セキュリティ ネットワークセキュリティ 認証認可 シークレット管理 運用・監視 オートスケーリング ヘルスチェック Datadog設定 ログ収集 ABテスト DevOps CI/CDパイプライン IaC (Terraform/CloudFormation) モデルのバージョン管理 当然、これに加えて機械学習に与えるためのデータの収集のパイプラインや、BigQueryなどのData Ware House整備も必要になります。 こうしたタスクも当然AIの力で楽にはなるのですが、インフラ周りの設定は複数のGithub Repository、手動作業、目視での確認、試行錯誤などが必須となり、どうしても時間がかかってしまいます。GitHub Actionsを1行直しては試す、Terraformの設定を1行直しては試す、Kubernetesマニフェストを1行直しては試す、のような作業に膨大な時間を使った経験があるエンジニアも少なくないでしょう。 つまり、AIによって業務を改善しようと考えるときに、アプリケーションロジックをAIに効率的に書かせることだけではなく、こうしたインフラ・基盤周りの作業を決定論的に効率化しないことには生産性は大きく上がらないのではないかと考えています。 メルカリのAI Task Forceでは、各組織(エンジニアのいないチームを含む)にEnablerが1〜2名アサインされ、組織の業務を改善する助けをするというスタイルをとっています。 つまり、上記のタスクを基本的にはたった1〜2名で完遂しなければなりません。 「ここはSREにお願いして…」「ここはMLエンジニアに…」と専門家に依頼している時間はありませんし、非エンジニアの方々の課題を解きほぐし、仕様に落とし込むPMのような役割も求められます。そもそも自分の知らない領域のチームのドメイン知識を手に入れるためにも多くの時間が必要でしょう。 ここにさらに「AI固有の悩み」が乗ってきます。モデル選定、コンテキストエンジニアリング、そもそもGoogle ADKやPydantic AIなどライブラリの進化が早くて追いつくのが大変…など。 社内ツール開発の技術選定 そこで、私が半年間AI Task Forceでイネーブラーとして活動している間、そうした少ない人数で社内ツールを作るために頻繁に用いた構成を紹介します。 前提として、社内ツールにはメルカリのメインプロダクト、Microservicesほどのスケーラビリティや厳密な可用性は求められません。求められるのは**「開発スピード」「メンテのしやすさ」「低コスト」**です。 Google WorkspaceとGoogle Cloudを社内で使っていることが前提になっています。 1. Cloud Run + IAP (Identity-Aware Proxy) Google Cloud環境において、私が社内ツール基盤として圧倒的に頻繁に用いたのが Cloud Run と IAP (Identity-Aware Proxy) の組み合わせです。 なぜCloud Runなのか? Cloud Run を利用する主な理由は、その優れたコスト効率、スケーラビリティ、そしてシンプルなデプロイに集約されます。 Cloud Run の最大の利点の一つは、その高いコスト効率です。リクエストがないときは実行インスタンスがゼロになり、その間は課金が一切発生しません。これは、夜間や休日などアクセスが少なくなる時間帯がある社内ツールなどにとって、特に大きなメリットとなります。 また、どれだけ利用者が集中したとしても、Cloud Run は自動で必要な数のコンテナを起動し、トラフィックの負荷に瞬時に対応するスケーラビリティを備えています。これにより、ピーク時のアクセス集中によるサービス停止やパフォーマンス低下の心配をする必要がなくなります。 Cloud Run を使えばシンプルなデプロイが可能です。アプリケーションをパッケージ化した Dockerfileさえ用意すれば、あとは簡単なコマンド一つでデプロイが完了します。「レプリカセット!」「ライブネスプローブ!」「ホリズンタルポッドオートスケーラー!」といったKubernetesの呪文も覚える必要はありません。 また、DNSやSSL証明書の管理から解放されるだけでなく、サービスで重要な基本的なメトリクスやログも自動で収集されます。これらはすべてGCPコンソールからすぐに確認できるため、運用の負担が大幅に軽減されます。 IAPで認証を「実装しない」 社内ツールで最も重要なことの1つはセキュリティですが、認証ロジックを自前で実装するのは大変です。 IAP (Identity Aware Proxy) を使えば、Google Workspaceアカウントに基づいたアクセス制御をインフラ層で強制できます。アプリ側では特定のヘッダを見るだけでユーザーを特定でき、認証ロジックを書く必要がなくなります。 TerraformでLoad Balancerやバックエンドサービスを構成するための複雑なネットワーク設定を組むと長い時間のかかる作業が、Cloud Runなら以下のコマンドだけで「社内限定公開」の環境が整います。 # Cloud Runへのデプロイ(IAP有効化オプション付き) gcloud beta run deploy ${SERVICE_NAME} \ --no-allow-unauthenticated --iap \ --platform managed \ --project=${PROJECT_ID} \ --service-account=${SA_EMAIL} \ --region=asia-northeast1 \ --image=${IMAGE_ID} # IAPへのアクセス権限付与(社内ドメインや特定グループのみ許可) gcloud beta iap web add-iam-policy-binding \ --project=${PROJECT_ID} \ --member="例:group:[email protected]" \ --role=roles/iap.httpsResourceAccessor \ --region=asia-northeast1 \ --resource-type=cloud-run \ --service=${SERVICE_NAME} これだけで、Artifact Registryに上げてあるコンテナが、社内メンバーだけがアクセス可能な状態で立ち上がります。 (betaなので今後GAになった際にはコマンドが変わる可能性があります) Vertex AI (Gemini) へのアクセスも簡単 AIをツールから使う上で面倒なことの一つが、APIトークンの管理です。 Cloud Runならば、Cloud Runの実行Service Accountに roles/aiplatform.user を付与しておくだけで、APIキーの管理やローテーションを気にすることなくGeminiを利用可能です。 from google import genai # 認証情報が環境から自動取得されるためAPI Keyの指定は不要 client = genai.Client(vertexai=True, project="your-project-id", location="us-central1") model = "gemini-2.5-flash-lite" response = client.models.generate_content( model=model, contents="元気ですか?" ) print(response.text) n8nやDifyなどのノーコードツールも魅力的ですが、将来的な要件変更の柔軟性を考えると、Cloud Runによるコードベースの開発は「セットアップコストを抑えつつ、自由度を確保する」ための最適解の1つだと感じています。 2. データベース:Firestore と Google Spreadsheet 「高負荷なトランザクションが不要な社内ツールにおいて、月額数千円から1万円以上のコストがかかる Cloud Spanner や Cloud SQL はオーバースペックになりがちです。そこで、コストを最小限に抑える選択肢として Firestore と Google Spreadsheet が非常に役立ちました。 Firestore は、スキーマレスかつサーバーレスなデータベースで、完全従量課金のためスモールスタートに最適です。一方で、意外にも優秀な選択肢となるのが Google Spreadsheet です。 Spreadsheet を利用する最大の利点は、事実上のゼロコストで運用できる点にあります。Google Workspace 環境であれば追加費用はかかりません。Cloud Run の実行サービスアカウントに権限を付与するだけで、プログラムから容易に読み書きが可能です。 さらに、管理画面(Admin UI)を作る手間を省ける点も大きな魅力です。非エンジニアの担当者が直接データを閲覧・編集できるため、現場からは「使い慣れたツールで管理できてありがたい」という声も得られました。データ不整合のリスクという側面はありますが、数千行程度のマスタデータ管理などであれば、開発スピードとメンテナンス性を最優先した合理的な選択だと言えます。」 3. Streamlit ツール開発において、現在は Next.js がデファクトスタンダードと言えますが、社内ツールであれば Streamlit を採用することにも大きなメリットがあります。 最大の利点は、開発速度の圧倒的な速さと学習コストの低さです。Streamlit を使えば、データアナリストやエンジニアが Python を書く延長線上で UI を構築できます。フロントエンドとバックエンドの境界を意識せず、入力ウィジェットやグラフ、チャットインターフェースなどを数行で実装できるため、迅速な改善が求められる現場で真価を発揮します。将来的に非エンジニアがツール制作に携わる際や、AI エージェントが台頭して「ロジックさえあれば UI はチャットで十分」となる時代を見据えても、Python で完結するライブラリを選んでおくのは有利な選択です。 また、Python エコシステムとのシームレスな統合も無視できません。Pandas などのデータ処理ライブラリと標準で連携できるため、Next.js のように Python バックエンドとの間に複雑な通信レイヤーを設ける手間が省けます。同一の Python 環境内でデータを直接扱い、即座に UI へ反映できるシンプルさは、デバッグやメンテナンスの工数削減に直結します。 他の Python 製 UI ライブラリも検討しましたが、現時点では Streamlit が最も完成度のバランスに優れていると感じています。もちろん API 開発が必要なケースでは他の選択肢が必要になりますが、「開発効率」を最優先する社内ツールにおいて、Streamlit は非常に強力な武器になります。 諦めたこと もちろん、上記の技術を選んだことで諦めることにした部分もあります。 ミリ秒単位の「サクサク」した操作感 Cloud Runがコールドスタートするときには数秒の遅延が発生します。また、Streamlitで複雑なことをし始めるとどうしても動きがモッサリして、CacheやSessionの管理が厄介にもなります。 厳密なトランザクション管理や集計クエリ アクセス数が少ない社内ツールでは大きな問題は起きないだろうと考え、諦めました。 サービスの常時稼働 Cloud Runには常時稼働するオプションもありますが、一気にコストが上がり、従量課金のメリットが消え去ります。常にeventをListenするアプリやバックグラウンドでの重い非同期処理にはコストパフォーマンスが良くないでしょう。 まとめ・今後の展望 AI-Nativeな組織変革を達成するには、エンジニアと非エンジニア組織の協力が不可欠です。 この半年間、私はコードを書くだけでなく、現場の課題を聞き出し、それを技術で解決する「技術コンサルタント」のように働く時間が多かったように思います。 非エンジニアと密に連携し、効率よく価値を届けるためには、彼らにとってもフレンドリーな技術を選択肢に入れ、柔軟性の高い技術を選択し、また常に「本当にAIを組み込むことは必要なのか」を見極めることも大事です。 また、上述のような技術を使っても、まだ厄介なところは「CI/CD」で、個人的に改善しようとしているところです。 プルリクエストが作られれば自動的にPreview URLが生成され、マージしたら本番環境にデプロイされる。環境変数の値を変更したいときに数クリックでサクサクと変更ができる。まだまだ今は手動デプロイをすることも多いですが、そういったPaaS体験を上述の技術と合わせて達成することで格段に生産性が上がるだろうなと感じています。 進化の早いAIを活用し、現場の業務を最速で効率化していくフェーズにおいては、サーバレスソリューションをフル活用して「明日から使えるツール」を届けてみるのも悪くないのではないでしょうか。 明日の記事は@Kahlaさんです。引き続きお楽しみください。
アバター
はじめに この記事は、 Merpay & Mercoin Advent Calendar 2025 の21日目の記事です。 ntk1000 です。MerpayのKYCおよびPartner Platformチームのエンジニアリングマネージャーを務めています。 半年前、メルカリグループにおける開発者体験(DevEx)改善のための 全社的な取り組みを紹介 しました。四半期ごとの改善サイクルを設計し、エンジニアとEMから100%の参加を得て、Deep Work(集中するための中断されない時間)やCross-team Collaborationといった構造的な課題を特定しました。 最初の6ヶ月(FY25 Q4 → FY26 Q1)では、総合的な開発者体験指標は大きな変化がありませんでした。一部のチームで大幅な改善が見られたものの、多くのチームは停滞していました。この状況を踏まえてアプローチを見直した結果、直近の四半期(FY26 Q2)では全社的に指標が大幅に改善し、特にDeep Workの領域で顕著な向上を達成しています。通常は年間目標とされる改善水準も、今回は1四半期で達成できており、アプローチ転換の効果が明確に表れました。 本記事では、この9ヶ月間の実践と成果、そして組織全体でDevEx改善をスケールさせるための取り組みについて共有します。 改善のスケール:チームから組織全体へ 第1段階(FY25 Q4 → FY26 Q1):一部成功と全体停滞 FY26 Q1のサーベイでは、開発者体験指標が横ばいの組織がほとんどでした。 しかし、特定の課題領域やチーム単位でのデータを分析すると、改善に成功している事例も確認することができました。 成功事例の分析 Deep Workを例にとると、大幅に改善したチームの取り組みを調査した結果、以下の共通パターンがありました: 集中時間を確保する明確なポリシーを確立 ミーティングの整理、統合ルールの策定と実施 チーム全体の「ノーミーティングタイム」ブロックの設定 エンジニアの集中作業Dayを定期的に開催—月1回、2日間など完全にミーティングのない期間の確保 AI活用によるルーチンタスクの自動化 これらの取り組みに共通するのは、 チーム全体のコミットメントに支えられた、ポリシーベースの改善 です。 個人レベルの工夫ではなく、チーム全体で合意した構造的な変更として実装されており、 ポリシーベースのため素早い展開・適用が可能 という特徴があります。 一方でチーム単位での適用となるため、改善対応にばらつきがある・成功パターンの横展開が自然には起きないという課題もありました。 第2段階(FY26 Q1 → FY26 Q2):ボトムアップとトップダウンの融合 上記の課題を踏まえ、チーム単位の改善だけでは限界があることが明らかになったため、 ボトムアップとトップダウン、両方のアプローチを同時に機能させる 体制を構築しました。 2層構造での改善サイクルをまとめると下記になります。 ボトムアップ: FY25 Q4から確立していたチームレベルの改善サイクル: 主体 : Individual Contributor(IC)とEngineering Manager(EM) 特徴 : 小回りが効き、チーム固有の課題に素早く対応 チームがコントロールでき、かつ素早い対応ができる領域(Deep Work、Documentation、Code Maintainabilityなど)で高い成功率 トップダウン: FY26 Q2から本格的に構築した組織レベルの改善サイクルです: 主体 : VPoE、Director、Manager of Managers(MoM) 目的 : 個別チームでは解決困難な構造的課題への対応 組織横断での方針決定とリソース配分 成功パターンの標準化と横展開 具体的な取り組み事例 Fintech組織に所属するMerpay/MercoinではDeep Workへの改善要望が継続して高く、スコアも低い状況でした。 VPoE主導でDeep Work改善を組織としての注力課題に定め、下記のような取り組みを行いました。 Fintech内の各組織におけるDeep Work関連指標の可視化(Deep Workスコア、ミーティングが多い日や割り込みの割合) Deep Work改善事例の横展開とローカライズ 組織内での定例会議の見直しと統合 チーム間での成功事例の共有・標準化 追加サーベイを用いたより詳細な課題分析 EMへの改善実行サポート 進捗トラッキング 経営層へのレポート、非エンジニア組織への取り組み共有 個々のチームの努力だけでは変化しなかった組織平均が、VPoE主導のトップダウン施策とEM/IC主導のボトムアップ実行を組み合わせることで、 1四半期で約16%の改善を実現 することができました。この結果は経営会議でも報告しており、全社集会でも共有を予定しています。 Deep Work改善に有効であった集中時間を確保する明確なポリシーは、非エンジニア組織にも有効と考えられます。全社的なDeep Work改善につながることを期待しています。 また、今回は素早い展開・適用が可能なポリシーベースの改善がメインだったため、組織横断で効果が発揮されやすいということもあったと思います。今後は着手しやすい短期の施策だけでなく、長期的な対応を必要とするような難易度の高い課題にも取り組んでいく必要があると考えています。 DXからの学び 今回の取り組み方針を再設計する上で、 DX (私たちのDevExプラットフォームを提供する会社)によるプレゼンテーションで得られた知見が参考になったため簡単に共有したいと思います。 イニシアチブには構造が必要 プレゼンテーションで強調されたのは、多くのDevEx改善が失敗する原因は、チームの関心の欠如だけではなく適切な構造の欠如であるという点です。 成功には3つの要素が不可欠とされていました: 1:ビジネスケースの構築 開発者の痛みを説明するだけでなく、ビジネス成果に翻訳する: 組織のKPIに接続 : 時間損失、コスト、品質、定着率 規模での影響を定量化 : 例えば、1人の開発者がビルドごとに20分損失 × 700エンジニア = 重大なコスト 価値の解放を示す : 痛みの除去だけでなく、可能になること(より速い機能、より高い信頼性、より良い回復) 2:イニシアチブを適切に構造化 6-12ヶ月以上でタイムボックス : 本当の変化には時間がかかる。スプリントは迅速な成果を生むが習慣を形成しない。 自然なチェックポイントを設定 : ベースライン → 中間点 → 終了測定 チームが動員できるようにする : コミュニケーション、計画、実践の埋め込みに時間を与える 3:適切な指標を定義 Northstar KPI(組織の最重要指標) : 生産性、満足度、品質、定着率 リーディング指標 : チームが直接影響できるもの(例:ビルド時間、レビュー時間) ガードレール : ゲーミングを防止(例:PR数単独では人為的に膨張可能) 3つの不可欠な役割 すべての成功したイニシアチブには必要: エグゼクティブスポンサー : トップダウンのリーダーシップとビジネスアライメントを提供(例:VPoEの意思決定) チャンピオン : データで問題を枠組み化し、戦術的ガイダンスを提供(例:DirectorやMoMによる組織データ理解と方針決定) マネージャー : 時間を配分し、イニシアチブをチームレベルのアクションに翻訳(例:EMやICによるチーム改善) いずれかの役割が欠けていると、イニシアチブは停滞します。 可視性による持続可能性 イニシアチブが途中で停滞することを防ぐため、以下の仕組みが推奨されています: 可視化 : 進捗/進捗不足を示すダッシュボード 運営レビュー : 課題/アクション/成果を伴う定期的なミーティング 明確なリーダーシップ : 進捗の説明責任、ビジネスアラインメント 今後の課題 現時点で解決できていない課題があり、引き続き取り組みを進めています。 横展開の難しさ 成功パターンは自動的に広がりません。特にメルカリグループではプロダクトのフェーズや組織サイズがさまざまなので、例えば成熟した大規模組織へのアプローチとスタートアップフェーズの小規模組織へのアプローチが同じになるとは限りません。 現在の取り組み : 単なる成功事例の寄せ集めではなく、組織サイズやプロダクトのフェーズといった情報も併記することで、各組織が自律して適用可能なアクションを判別できるようにナレッジ整備を進めています。 長期的影響の測定 サーベイスコアと即時指標(ミーティング時間、中断頻度)は測定できますが、DevEx改善をビジネス成果(提供速度、品質、定着率)に接続することは依然として困難です。 現在の取り組み : DXスコア改善と各種サーベイ結果および定量データとの相関分析を進めています。まだ確定的な結論は出ていません。 複数四半期にわたる継続性 高い参加率は継続できていますが、サーベイ疲れや改善が進まない課題への不満も散見されるようになってきました。 現在の取り組み : DXのサーベイが肥大化しないように毎回調整、DX関連の社内イベントを実施して意義を定期的に伝える取り組みを続けています。 まとめ 9ヶ月前、この取り組みを開始した時点では、強いエンゲージメントを達成し、構造的な課題を特定し、アクションプランを作成しました。 現在は、初期の勢いを持続的な組織変革に変える段階にあります。一部のチームで大きな成果が出ている一方、課題に直面しているチームもあるというばらつきがある状況から、組織横断での改善を進めることができるようになってきました。 DevEx改善を組織全体にスケールさせるために必要な要素をまとめます: 構造的サポート (改善体制、役割の明確化) 文化的コミットメント (多方面でのリーダーシップ、定期的な可視性) 実用的なフレームワーク (チームが適応できる成功事例の展開) 改善スコアは指標であり目的ではないことにも引き続き注意する必要があります。 より重要なのは、チームが以下の能力を獲得したかどうかであり、結果としてビジネス成果を最大化することです: 日々の仕事での摩擦を特定する リーダーシップに明確に表現する 改善のために集団的アクションを取る 結果を測定し振り返る 継続的な実践としてのDevEx プロダクトの進化や組織サイズ・構造の変化、AIによる開発手法の変容といった動きに応じて、いち早く課題を特定して対処するためには継続的な実践が不可欠です。 目標は完璧なスコアを達成することではなく、開発者体験の問題を継続的に感知し対応できる組織能力を構築し、生産性を上げることです。 第1段階では全社的な開発者体験指標は横ばいでしたが、第2段階では大幅な改善を達成しました。 この変化が一時的なものでなく継続的な改善プロセスとして定着するように、引き続きこの取り組み自体も改善を進めていきます。 明日の記事は @takiさんです。引き続きお楽しみください。
アバター
こんにちは。メルカリのセキュリティエンジニアの@yuです。 この記事は、 Mercari Advent Calendar 2025 の20日目の記事です。 従業員の業務端末(MacBook)に利用しているデバイス管理ツールであるJamf Proの構成管理にTerraformを活用し始めた際の所見について紹介します。 概要 Jamf Proの構成変更は、macOS, iOSデバイス管理の改善に欠かせません。一方で、変更が手作業中心だと、レビューが重くなったり、作業ミスの余地が残ったり、変更の根拠や履歴が散らばったりしがちです。特にセキュリティの観点では「何時、誰が、何故、どのようなプロセスで、何を変更できるのか」のような5W1Hを明確にし続けることが重要になります。 そこで本記事では、Open Source Communityが開発・保守しているTerraform provider (※)を用いてJamf ProのリソースをIaC (Infrastructure as Code)化し、さらにGitHub上のPR (Pull request)を起点に terraform plan をレビューしてから terraform apply を実行する、PR駆動のGitOpsフローへ移行した取り組みを紹介します。 ※: https://registry.terraform.io/providers/deploymenttheory/jamfpro/latest/docs この手法自体は主要なクラウドサービスの構成管理では一般的な手法ではありますが、本件の様なデバイス管理ツール上での適用については例が少ないのが現状です。本記事では、この試みをいかにして実現したのかを紹介します。 この仕組みによって、変更内容はコード差分とplan出力として事前に確認できるようになり、適用は自動化されます。結果として「手順書ベースのレビューや手作業変更」から、「差分とplanを一次情報としてレビューし、承認後に安全に反映する」形へ移行できました。 背景:なぜ“セキュアな変更管理”が必要だったのか もともとJamf Proの変更は、手順書に沿った手作業が中心でした。この方法は丁寧に運用すれば回りますが、変更のたびに設計から実装までのリードタイムが伸びやすく、オペミスの余地も残ります。また、Jamf Proのリソースによっては変更履歴が十分に追えず、申請フローと実際の変更を機械的に突合できない、といった課題もありました。さらに、従来の申請フローでは「何をどう変えるか」が自然言語やスクリーンショットで記述されることが多く、変更内容が曖昧になりやすいという問題もありました。申請者・承認者・作業者の間で解釈が分かれた結果、意図と異なる設定変更やレビュー漏れが起きる余地が残ります。 (こちらの課題の一例については昨年の mSCPとJamf Pro APIによるmacOSセキュリティ設定の手動IaC化の試行 | メルカリエンジニアリング も併せてご参照下さい) さらに運用が進むにつれて、リソースの所管や背景(なぜこの設定が必要か)が 変更管理ツール、SlackやNotion、Google Docsなどに散在し、後から辿るコストが増えていきます。結果として、定常メンテナンスのために高い操作権限を人に付与し続ける必要が出やすく、攻撃面管理の観点でも悩ましい状態になりがちです。一方で、私たちはお客さま向けのプロダクト環境へ設定しているものと同じ高いセキュリティ及び管理基準を当社のコーポレート環境に対しても適用したいと考えております。 この状況を改善するために、私たちはJamf Proの変更を「コード化」し、「PRとレビューのプロセスに載せる」、そして「承認後に自動適用する」構造へ切り替えました。以降の章では、この GitOpsフローをどう設計し、どのように権限分離・承認・変更範囲のコントロールを実現したかを中心に説明します。 コードオーナーで「変更範囲」と「承認責務」を結びつける GitOpsでは、構成変更の入口がPRになります。つまり、レビューと承認の設計が、そのまま変更管理の統制になります。Jamf Proのように、設定変更が端末群に広く影響し得る仕組みでは、誰がどの範囲を見て、どの基準で承認するかを、運用ルールだけでなく “仕組み” に落とすことが重要です。 そこで有効なのが コードオーナー (※)です。コードオーナー を使うと、特定のディレクトリやファイルに変更が入った際に、指定したロール(チーム)がレビューに入ることを、リポジトリのルールとして強制できます。これにより「所管が曖昧」「気づいた人が見る」状態から、「この範囲はこのロールが責任を持つ」状態へ寄せられます。 ※: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners (掲載例) # CODEOWNERS (example) # Policies: local admin management /terraform/sandbox/policies/local-admin/** @sec-reviewers # Application update settings: owned by IT Dept. /terraform/sandbox/configuration-profiles/update-settings/** @endpoint-admins # Production: require multiple approvers /terraform/prod/** @sec-reviewers @endpoint-admins # Workflows /.github/workflows/** @sec-reviewers ここでのポイントは、ディレクトリ構造自体をレビュー境界に合わせることです。 GitHub Actions workflowの統制:applyの実行条件を絞る PR駆動のGitOpsでは、 terraform plan が “事前確認” で、 terraform apply が “本番反映” です。この2つを分けて考え、applyが実行され得る条件を狭くすることで、変更管理をセキュアにできます。 本件での設計の要点は terraform plan と terraform apply の実行ワークフローを分離し、承認前に本番反映 (apply)が起きない状態をBranch Protectionで担保することです。 具体的にはPR 作成時にはplanを実行し、レビュワーはコード差分とplan出力を一次情報として確認します。一方でapplyはmainブランチへのマージ後にのみ実行されるようにし、「承認済みの変更だけが反映される」状態をワークフロー条件とします。Branch Protectionに関わるセキュリティ上の論点については、補足として「 GitHubのBranch Protectionの突破方法 | メルカリエンジニアリング 」も併せて参照ください。 さらに、ワークフロー自体を保護することも重要です。GitOpsにおいてCI/CDは実質的に“実行主体”であり、ここが最重要の保護対象になります。そのため、本件ではplanとapplyのワークフローを分離し、それぞれが参照できるAPI権限も分離します。具体的には、planは読み取りに必要な範囲に限定し、applyは反映に必要な範囲に限定します。加えて、認証情報は特定のワークフローが特定の GitHubイベントで実行された場合にのみ、CI上で一時的に参照できるようアクセス制御を適用し、不要な露出を避けます。 最後に、 .github/workflows/** 配下の変更についても勿論レビューを必須にすることで、CI/CDの改変による統制の迂回を防ぎます。 この設計によって、「強い操作権限を常に人へ配り続け、手動での変更管理」状態から、承認プロセスに通った変更だけが自動で反映される状態への移行準備が整いました。Jamf Proは端末に対して大きな影響を与え得るため、変更管理をこの構造に乗せること自体がリスク低減になります。 移行:既存JamfリソースをIaCへ取り込む Import block / generate-config-out で「ゼロから書かない」移行にする Jamf Pro には既に多くの設定が存在しているため、IaC化を “ゼロから書く” 方式で始めると、次の問題が起きがちです。 現行設定の再現に時間がかかる 再現ミス(設定の抜け漏れ)が起きる 結果として、移行プロジェクトが止まりやすい そのため、本取り組みではTerraformのImport blockと -generate-config-out を活用し、既存のJamfリソースを起点にtfファイルを生成し、stateに取り込む流れを中心に据えました。 (コマンド例) terraform plan -parallelism=1 -generate-config-out=<generated>.tf このアプローチの利点は、移行を“正確性”と“スピード”の両立で進めやすい点です。運用移行では、最初から完璧な整理(理想のディレクトリ構成やモジュール化)を目指すより、まず「planが安定して読める状態」まで持っていく方が、その後の GitOps 運用に繋がりやすいと考えています。 なお、メルカリでは100を超えるJamf Proリソースがあるため、手動でimportブロック書くのも一定時間を要する可能性があり、事前に「Jamf Proのリソース情報を取得してimportブロックを自動生成する」プログラムを準備して臨みました。但し、こちらは Terraform provider側で将来 terraform query へ対応した場合は、該当コマンドへ置き換えが可能となります。 つまずきどころ1:構成プロファイルの差分が毎回出る問題 構成プロファイルでは、初回に *.mobileconfig をペイロードとしてJamf Proへ作成した際に、Jamf Pro側で PayloadIdentifier などの付加情報が追加されることがあります。結果として、次回の terraform plan で差分が必ず出る、という状況が起こり得ます。 例えば、GitHubプロジェクト側のmSCP (macOS Security Compliance Project)側で自動生成されるmobileconfigファイルをそのまま使う場合は本事象が発生します。 この差分は “危険な変更” というより、管理システム側の正規化(自動付加)により起きているため、運用としては次のように整理しておくと混乱が減ります。 「差分が出る=即apply」ではなく、まず差分の性質を分類する。 既存リソースは importを起点に扱い、変更時に差分を取り込む方針に寄せる 新規登録リソースも既存の正規化(自動付加)をsandbox環境などで検証の上、正規化された状態で本番へ適用。 これにより、GitOpsの価値である「planを一次情報としてレビューする」を維持しつつ、ノイズ由来の差分で運用が疲弊することを避けられます。 つまずきどころ2:Policy更新時の差分の見え方 Policy 更新時は、plan/applyで例えば Self Serviceに関する属性差分が表示されるなど、UI上の変更と一致していても“コード上の差分”として表現されることがあります。将来的にTerraform provider側の改修に伴い解消する可能性がありますが、それまでは差分が「意図した変更か」を判断するためのチェック観点を押さえ、Terraformを利用する関係者で共有出来る形にすることで、円滑な運用に繋げることが出来ます。 運用:属人性を減らすために“プロセスで残す” PRが「背景・差分・plan」をまとめた一次情報になる 従来、変更の背景(なぜ必要か)や手順、結果はSlackやGoogle Docs、Notionなどに散らばりがちでした。GitOpsへ寄せると、少なくとも変更の入口がPRに集約されるため、 PR記述 (なぜ変えるのか) コード差分 (何を変えるか) plan 出力 (何が起きるか) が、1つの場所に残ります。これは、コンテキスト散在や所管不明瞭の改善に直結します。 コードオーナー+レビューにより「気づいた人」から「責務」へ コードオーナーは単に“レビューを依頼する仕組み”ではなく、責務境界をコードに埋め込む仕組みとして機能します。結果として、特定のリソースに対して「どのロールが見るべきか」を継続的に維持しやすくなります。 変更履歴の可視化(通知)で“あとから追える”を当たり前にする GitOps では mainブランチが事実上の “唯一の正” になるため、mainの変更履歴を関係者が追える形にするのが重要です。mainの変更履歴をポストするチャンネルを用意してGitHubにアクセスせずともどのような変更が行われているかについてリーチし易い環境を用意しました。 導入効果 ここまでの取り組みを経て、私たちの運用が具体的にどのように変わったのかを紹介します。 1.ClickOpsからの解放 これまでの変更手順書に対するレビューでは、手順のWeb UIを頭でトレースしてレビューを行っていました。「この操作で意図した設定に変わるのかな?」「前提のステップや併せて変更するべきリソースはどこだろう?」という、ある意味想像力を働かせたレビュー必要でした。仮にsandbox環境でのテストをパスしていたとしても本番環境との僅かな差異によって予期せぬ挙動を招くリスクがあり、手順書作成からテスト、本番実装までのリードタイムも膨らんでいました。また、仮に完璧な手順書があったとしても、手作業中心では最後の最後でのオペミス(クリックやコピペ内容)というヒューマンエラーのリスクを内包していました。 移行後はPRのコード差分とterraform planの出力結果という一次情報が目の前にあるため、レビュー品質とスピードがあがりました。また、変更の反映も手作業では無く「プログラムによる確実な実行」がもたらした安心感はとても良いです。 2.監査・トラブルシューティングが容易に PRそのものが「変更背景・差分・実行結果」をすべて内包するログとなっています。いつ、誰が、何の目的・背景で変更したのかが main ブランチの履歴と紐付いて残るため、監査やトラブルシューティングの際も、迷わず一次情報へ辿り着けるようになりました。 3.仕組みで責任と権限の担保 コードオーナーによって、ディレクトリ構造とレビュー(承認)責務が紐付いています。また、「承認された変更のみが自動適用される」フローを構築したことで、将来的に「最小権限の原則」の実現に向けたよい準備となりました。 今後の展望 1. 管理対象リソースの拡大 Jamf ProのTerraform providerは有用ですが、開発途上の側面もあり、リソースタイプやリソースの構成によっては”差分ノイズ”と継続的に付き合う可能性があります。ノイズが多いとplanレビューの焦点がぶれ、レビュワーが疲弊する状況になりますので、まずはsandboxでの検証を継続しつつ、本番での管理(import)は段階的に広げる運用を継続予定です。 2. Jamfの機能追加に伴う拡張 将来的には通常のJamf Proリソース管理に加え、Jamf社が公式で開発している別provider (※)で扱える領域 (例: blueprintやcompliance benchmark)を含めて、デバイスの管理運用やセキュリティコントロールを改善できる余地があります。 ※: https://registry.terraform.io/providers/Jamf-Concepts/jamfplatform/latest/docs 2025年12月上旬現在、この機能を用いるJamf Platform APIはpublic betaのアナウンス待ちとなり、それまではWeb UIでの変更管理となります。 https://developer.jamf.com/platform-api/reference/getting-started-with-platform-api 3. 運用メンバー向けOnboarding 日常的に開発を行っているメンバーはGitOpsの活用が容易ですが、そうでないメンバーや別チームの関係者に対しても「使ってみようかな」と考えてもらえる仕掛けや、取りかかりし易い環境は大切です。エディタやGitHubの使い方や、Terraform特有の記法のガイドなど、一方的なドキュメントの連携だけで終わらせるのではなく、メンバーからのフィードバックによる改善など、関係者で利用促進のポイントを継続検討予定です。 まとめ Jamf Proの変更管理を、手順書・手作業中心の運用から、TerraformによるIaC+PR駆動GitOps (planレビュー→承認→apply) へ移行しました。 変更はPRの差分と terraform plan 出力を一次情報としてレビューできるため、レビューの質と速度を上げつつ、適用は自動化することでオペミスの余地を減らす設計にできました。 コードオーナーやワークフローの実行条件で「変更範囲」と「承認責務」を結びつけ、所管の曖昧さやコンテキスト散在に対しても、プロセスと履歴が残る形で改善を狙えるようになりました。 一方で、差分ノイズが出やすいリソース(例: 構成プロファイル)などの課題もあるため、importの方針や運用ルールを整備しながら、段階的に改善していきます。 近年、Jamf Proだけでなく法人向け他製品についても前述のようなセキュリティやガバナンス上の利点からGitOpsやIaCに関わる要素技術 (APIやTerraform provider)へ多大な投資が行われています。将来の製品選定基準の一つとして本要素を含めるのも良いかもしれません。 本記事が各組織のmacOS, iOS構成管理の課題検討の一助になれば幸いです。 最後に、メルカリでGitOpsをPolicy as Codeとして活用し、セキュリティとガバナンスを拡張することにご興味がありましたら、セキュリティチームの採用情報について mercari careers をご覧ください。 明日の記事は akkie さんです。引き続きお楽しみください。
アバター
こんにちは。メルペイバックエンドエンジニアの @kobaryo です。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の20日目の記事です。 はじめに メルカリグループは現在、AI Nativeな会社を目指しており、開発プロセスへの活用はもちろん、社内のさまざまな業務においてAIを使った効率化の取り組みが進んでいます。それ以前にも、プロダクト面ではメルカリの「 AI出品サポート 」やメルカリ ハロの「 かんたん求人作成 」とAIを活用した機能がこれまでに複数リリースされてきました。 そして今回、メルペイでもAI Nativeなプロダクトを実現すべく、2025年9月に「しゃべるおさいふ」機能のPoCを開始しました。この機能は一部のお客さま向けに限定提供しているため、体験できていない方もいらっしゃるかもしれませんが、本記事では、この「しゃべるおさいふ」機能のバックエンド設計について解説します。 まずは機能の概要を紹介し、その後にアーキテクチャや、LLMを利用するがゆえに発生する特有のポイントについて説明していきます。 「しゃべるおさいふ」機能とは 「しゃべるおさいふ」は、メルカリアプリのおさいふタブを開くと、LLMがお客さま一人一人の決済履歴やポイントの有効期限などをもとに、ひとことコメントを返してくれる機能です。 「◯◯ポイントがあと×日で失効するので、よく行くカフェで使いませんか?」といった実用的な提案から、画像のようにちょっとした雑談めいたコメントまで返してくれます。 近年のLLM活用はチャットUIのようにお客さまが能動的に行動する形式が主流ですが、この機能は「日常的なメルペイの利用の中でAIからのコメントが届く体験」がアプリ訪問や決済行動に寄与するのかを検証する狙いがあります。この機能によって「今日はいつもと違う買い物をしたけれど、どんなコメントが返ってくるのだろう?」と、決済体験を少しでも楽しくしたいと考えています。 アーキテクチャ ここからは、具体的な設計について説明します。PoCであることから、少人数・短期間での開発を前提とし、シンプルな構成を重視しています。 短期間でのリリースを実現するため、新たなマイクロサービスは作らず、既存サービスにエンドポイントを追加する形を採用しました。ただし、LLMへのリクエストはレイテンシが大きくなることが予想され、さらにPoCのため解放人数が動的に変化し、負荷の変動が大きくなり得ます。そのため、APIサーバーとは独立したworkerを設けて処理を非同期化し、他機能への影響を避けつつ、「しゃべるおさいふ」だけを容易にスケールできるよう設計しました。この構成によって、設計開始から社内テスト用の実装まで1ヶ月弱、そこからリリースまでにもおよそ1ヶ月とスムーズに進めることができ、短期間での立ち上げに大きく寄与しました。 大まかなフローは次のとおりです。   メルカリアプリがエンドポイントを叩くと、jobがPub/Sub経由でworkerに送信され、アプリ側はjob完了までポーリングする workerがお客さまの情報をもとにLLMに問い合わせ、生成したコメントを保存する 保存したコメントは、後述するコスト削減のためのキャッシュとしても活用されます。 実装におけるポイント ここでは、LLMを用いることで生じた課題と、その解決方法について解説します。LLMの設定により解決したものもあれば、そうではないものもあります。 フィルタリング LLM活用における最大の懸念点は、不適切または意図しない出力がそのままお客さまに表示されてしまうことです。LLM自身がある程度有害な内容を抑制するとはいえ、プロダクトとして避けたい表現は依然として存在します。 そのため生成コメントに対して、次の3段階のフィルタリングを行い、いずれかに該当した場合は再生成する仕組みにしています。   文字数制限 表示上の都合から、決済に関わる重要情報(バーコードや残高など)と干渉しない長さに収める必要があります。トークン数制限もしていますが、文字数とトークン数は必ずしも比例しないため文字数チェックも併用しています。 単語単位でのフィルタリング 明らかにNGな語句については、後述のLLMによるフィルタを通す前に弾くことで、レイテンシとコストを抑えています。 LLMによるフィルタリング 設定したポリシーを添えて、生成コメントを再度LLMに渡し、内容がポリシーに沿っているかチェックしています。 さらに、これらのフィルタリングが有効に機能しているかを検証するため、バックエンドでは任意のお客さまデータやプロンプトをrequest bodyとして渡し、それを基にコメントを生成できるQA用エンドポイントも用意しました。QAではポリシーに抵触しそうなプロンプトやデータを入力し、その返答を確認するサイクルを繰り返すことで、フィルタリングの有効性を検証しています。 コスト・レイテンシ LLMを利用するうえで、コストとレイテンシの問題は避けられません。この機能はお客さまの操作なしで自動表示されるため、リクエスト数が増えることが予想されますし、表示が遅れるとおさいふタブからの離脱につながります。 コスト観点では、LLM側の設定と仕様側の工夫の両面から対処しています。LLM側の設定としては、プロンプトの静的な部分と動的な部分を切り分け、前者をプロンプトキャッシュすることでコストを削減しています。仕様面では、1人のお客さまに対して1日に生成するコメント数に上限を設けることで、過剰な生成を抑えています。上限を超えた場合は、既に生成済みのそのお客さまに向けたコメントを再利用するようにし、推論コストを減らしています。ただし、体験面では「コメント→決済→コメント」というサイクルが心地よく回ることが重要なため、決済が行われた際にはこの上限を緩和する仕組みを取り入れています。これにより過剰な生成は抑えつつ、決済行動に応じたコメント更新の楽しさは損なわないよう工夫しています。 レイテンシ観点では、事前にバッチでコメントを生成しておく方法も検討できるものの、決済直後の情報がすぐにコメントへ反映される体験を重視し、リアルタイム生成を採用しています。ただし表示までに時間がかかると離脱につながるため、モデルやlocationの選定により、概ね3〜4秒以内に返答されるよう調整しています。 その他 これらの課題以外にも、いくつか工夫が必要な点があります。 1つ目は、お客さまにとってコメントが自然に感じられるかどうかです。たとえば、レイテンシの項で述べたように、決済情報を即座にコメントへ反映する仕組みはその一例です。また、LLMは現在の日付や時刻、日付から曜日への変換をしばしば誤るため、日時情報はバックエンド側で生成し、プロンプトとして明示的に与えるようにしています。さらに、ポイントのように時間経過で値が変わる情報を使用するコメントについては、キャッシュとして表示しないようにしており、自然さが損なわれないよう配慮しています。 2つ目は、モデルやプロンプトなどの設定を容易に変更できるようにすることです。しゃべるおさいふでは複数の LLMプロバイダのリクエスト形式に対応しつつ、コメント生成とフィルタリングの双方について、リリース作業なしでモデルやtemperatureなどの設定値を変更できる仕組みを備えています。また、ランダムに選択されるコメント種別、そのプロンプト、お客さまデータの組み合わせを宣言的に記述できるようにすることで、変更のしやすさも確保しています。 おわりに 本記事では、メルペイのPoC機能「しゃべるおさいふ」について、その概要と設計上のポイントを紹介しました。 LLMモデルが強化され、幅広いタスクを汎用的にこなせるようになってきた今、LLMを使ったプロダクトの差別化にはUXの工夫がますます重要になっていると感じます。この「しゃべるおさいふ」プロジェクトで得られたLLM のプロダクト活用に関する知見を基盤に、今後もLLM をプロダクトにどのように組み込むべきかを継続して探求していきます。 明日の記事はntkさんです。引き続きお楽しみください。
アバター
こんにちは。メルカリのバックエンドエンジニアの @amenbo と、プラットフォームチームの @siroken3 です。この記事は、この記事は、 Merpay & Mercoin Advent Calendar 2025 の19日目の記事です。 メルカリでは AI-Native company を目指し、さまざまな AI エージェントの導入や運用改善に取り組んでいます。開発者の生産性向上もその一環であり、コーディング支援ツールの積極的な活用を進めています。そんな中、今年の7月にAWSからPreview公開された「Kiro」の試験導入を進めています。 Kiro は従来の「vibe coding」を超えた、仕様書駆動の開発を実現する IDE です。ただ、新しいツールを組織に導入する際には、技術的な評価だけでなく、アカウント管理や課金管理といった運用面での課題にも向き合う必要があります。 本記事では、メルカリが Kiro をどのように導入し、Okta と AWS IAM Identity Center を連携させたアカウント管理の自動化をどのように実現したかを紹介します。 Kiro とは Kiroの概要 Kiro は、2025年7月に AWS からパブリックプレビューとしてリリースされ、11月に一般提供(GA)が開始された spec-driven development を特徴とする agentic IDE です。VS Code のオープンソース版である Code OSS をベースに開発されています。 従来の AI コーディングアシスタントは、その場その場で「なんとなくいい感じに」コードを生成する「vibe coding」と呼ばれるアプローチが主流でした。一方、Kiro は仕様書を中心に据えた開発フローを実現します。開発者は以下の3つのマークダウンファイルで構成される「Kiro Specs」を作成し、これを基に AI エージェントがコード生成や実装を支援します。 requirements.md : ユーザーストーリーと受け入れ基準を定義 design.md : 技術設計とアーキテクチャを記述 tasks.md : 実装タスクをチェックリスト形式で管理 Kiroの料金プラン Kiro の有償プランを組織で利用するには、AWS の AI コーディングアシスタントサービスである AWS Q Developer の Pro サブスクリプションプランを使用します。具体的には、AWS IAM Identity Center を通じてユーザーを管理し、Q Developer Proのライセンスを割り当てる仕組みになっています。 なお、2025年11月の GA 以降、Kiro は独自のサブスクリプション体系に移行しましたが、引き続き IAM Identity Center によるユーザー管理が必要です。このKiro 独自サブスクリプション体系への移行については、この記事の後半に述べます。 アカウント管理における課題と解決策 既存のOkta連携基盤 組織で Q Developer Pro のライセンス管理を行うには、AWS IAM Identity Center との連携が不可欠です。メルカリでは Kiro の登場以前から、Okta と Identity Center の連携を構築しており、社内のさまざまな AWS リソースへのアクセス管理に活用していました。 この連携では SCIM 2.0(System for Cross-domain Identity Management)プロトコルによる自動プロビジョニングを採用しています。Okta 上でユーザーやグループを追加・変更すると、その情報が自動的に Identity Center へ同期される仕組みです。 Kiro のアカウント管理にもこの仕組みを活用しました。Okta に Kiro 利用者用のグループ( AWS_kiro_JP_Users )を作成し、そのグループに Q Developer Pro のサブスクリプションを割り当てます。これにより、Okta のグループにユーザーを追加するだけで、そのユーザは Kiro が利用可能になります。 ただし、この時点では Okta へのユーザー追加自体は手動で行っており、利用申請があるたびに AWS 管理担当者がコンソールからユーザーを登録する運用でした。作業自体は数分で終わるものの、担当者の手が空いていなければ対応は後回しになり、申請者を待たせてしまうケースが発生しました。 AI エージェントによるアカウント発行の自動化 Okta との連携をさらに一歩進め、すでに Okta と連携している社内の AI エージェントを Kiro のグループを扱えるように設定し、申請プロセスそのものも自動化しました。 ユーザーは Slack から「I want kiro」のように AI エージェントに伝えるだけで、以下のフローが自動的に実行されます。 AI エージェントがリクエストを受け取る AI エージェントが Okta の API を呼び出し、ユーザーを Kiro グループ( AWS_kiro_JP_Users )に登録 Okta が SCIM プロトコルで Identity Center にユーザー情報を同期 Identity Center で Q Developer Pro アカウントが有効になる ユーザーが Kiro を使い始めた瞬間から従量制課金が開始される ▲kiro アカウント申請の仕組み ▲AIエージェントを用いたアカウント申請 この仕組みにより、AWS 管理担当者の手を一切煩わせることなく、ユーザーが自律的に Kiro を利用開始できるようになりました。 Q Developer Pro から Kiro への移行 2025年11月のアップデートと移行の必要性 2025年11月、Kiro は大幅なアップデートを経て一般提供(GA)が開始されました。このアップデートにより、Kiro は Amazon Q Developer から独立した製品となり、独自のサブスクリプション体系が導入されました。 先ほど説明した仕組みは GA 以前に実施したものであったため、既存の Q Developer Pro サブスクリプションを Kiro プランに移行する必要がありました。移行しない場合でも Q Developer Pro のサブスクリプションは引き続き有効ですが、Kiro 専用の新機能(Property-based Testing、Checkpointing など)は利用できない可能性があります。 移行手順自体は非常に簡単で、AWS Management Console から対象グループ(今回の例では AWS_kiro_JP_Users )を選択し、希望の Kiro プランを指定するだけです。グループ単位またはユーザー単位で柔軟に移行でき、段階的な移行も可能です。 なお、一度 Kiro サブスクリプションにアップグレードすると、Q Developer Pro には戻せません。 まとめ 本記事では、メルカリにおける AWS Kiro の導入と、Okta、AWS IAM Identity Center、AI エージェントを組み合わせたアカウント管理の自動化について紹介しました。 手動運用から始まった Kiro のアカウント管理は、既存の Okta と Identity Center の SCIM 連携を活用し、さらに AI エージェントと組み合わせることで、完全に自動化されました。この取り組みにより、以下を実現できました。 管理負荷の大幅な削減 : AWS 管理担当者の手作業がゼロに スケーラブルな運用 : ユーザー数が増えても運用コストが増加しない セキュアなアクセス管理 : Okta を中心とした統一された ID 管理とアクセス制御 また、2025年11月の Kiro GA に伴う Q Developer Pro からの移行もスムーズに完了し、新しい課金体系のもとで運用を継続しています。 今後、AI ツールの導入はさらに加速していくと考えられます。その際、技術的な評価だけでなく、運用面での自動化をどう実現するかが重要になってきます。本記事で紹介した Okta と Identity Center の連携パターンは、他の AI ツール導入においても参考になる取り組みではないでしょうか。 メルカリは引き続き AI-Native company としての歩みを進めていきます。今後も、開発者の生産性向上とスケーラブルな運用を両立させる取り組みを続けていきたいと思います。 明日の記事は @Yu Sasaki さんです。引き続きお楽しみください。
アバター
こんにちは。メルカリ IDP チームの @task(mima) です。本記事は メルカリアドベントカレンダー 2025 の 19 日目の記事です。 はじめに 株式会社メルカリには、グループ全体のシステムの認証と認可を統括する IdP が存在します。本記事では、この IdP における Dynamic Client Registration (以下 DCR とする) の活用事例をご紹介します。活用事例は大きく分けて以下の2つです。 Terraform を用いた OAuth / OIDC クライアントの宣言的な管理 MCP 認可フローにおける動的なクライアント生成 これらの紹介のために、本記事では DCR と関連仕様について触れた後、それぞれの事例について背景とメルカリでの利用例を紹介します。 いずれも認証認可の領域に携わっているエンジニア向けの題材ですが、調査した限りでは DCR 自体の利活用をしたケースは少なかったため、少しでも参考になれば幸いです。なお、認証認可における基本的な概念や用語については説明を割愛します。ご承知おきください。 従来の OAuth / OIDC クライアント管理の課題 メルカリの IdP は、メルカリグループの各サービスや、 メルカリと公式連携した越境EC事業者様 に応じて OAuth / OIDC クライアントを登録・管理する必要があります。これらの登録・管理に際して、従来以下のような手作業が必要でした。 クライアント情報を登録・編集を目的とした IdP のデータベースに対する SQL 実行 作成されたクライアント ID / シークレットの Vault での管理 そのため、変更時の人的ミスやオペレーションコストが従来の課題でした。これらの課題を解決するために、OAuth / OIDC クライアントを機械的に登録・管理する仕組みが必要でした。 そこで白羽の矢が立ったのが DCR でした。 Dynamic Client Registration (DCR) とは DCR は、OAuth / OIDC クライアントを動的に登録するための標準仕様です。これにより、API 経由での登録・参照・更新・削除が可能になります。 DCR に関連する仕様は以下の通りです。必要に応じて一次情報を参照してください。 クライアント登録 OAuth 2.0: RFC 7591 – OAuth 2.0 Dynamic Client Registration Protocol OIDC: OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 2 クライアント管理 OAuth 2.0: RFC 7592 – OAuth 2.0 Dynamic Client Registration Management Protocol 続いて、クライアント登録およびクライアント管理のための概要を紹介します。 クライアント登録フロー RFC 7591 で定義されている 抽象的な DCR のフローは以下の図 1 の通りです。 +--------(A)- Initial Access Token (OPTIONAL) | | +----(B)- Software Statement (OPTIONAL) | | v v +-----------+ +---------------+ | |--(C)- Client Registration Request -->| Client | | Client or | | Registration | | Developer |<-(D)- Client Information ------------| Endpoint | | | +---------------+ +-----------+ 図1: Abstract Dynamic Client Registration Flow(出典: RFC 7591 Section 1.3 ) この図の「Client Registration Endpoint」は、クライアントを認可サーバーに登録できるように設計された OAuth 2.0 のエンドポイントです。そして、このエンドポイントとの (C) のリクエストと (D) のレスポンスがDCR のメイン処理 です。(C) で「Client or Developer」が 「Client Registration Endpoint」 に対して、希望する登録メタデータを含むリクエストを送信します。認可サーバは、OAuth クライアントを登録し、(D) でクライアント ID、クライアントシークレット、登録メタデータなどを返却します。 上記フロー図の (A) と (B) はオプショナルなセキュリティ機構 です。 (A) Initial Access Token 「Client Registration Endpoint」 へのアクセスを制御するためのトークン 誰でも自由にクライアントを登録できる状態を防ぐアクセス制御機構 (B) Software Statement クライアントのメタデータを含む署名付き JWT 事前承認されたソフトウェアであることを証明 詳細は RFC 7591 Section 3.1.1 を参照 これらは (C) のリクエストに含めて送信できます。 具体的には、(C) と (D) の基本的なリクエストとレスポンスは以下のようになります。 リクエスト例: POST /register HTTP/1.1 Content-Type: application/json Accept: application/json Host: server.example.com { "redirect_uris": [ "https://client.example.org/callback", "https://client.example.org/callback2"], "client_name": "My Example Client", "client_name#ja-Jpan-JP": "クライアント名", "token_endpoint_auth_method": "client_secret_basic", "logo_uri": "https://client.example.org/logo.png", "jwks_uri": "https://client.example.org/my_public_keys.jwks", "example_extension_parameter": "example_value" } レスポンス例 : HTTP/1.1 201 Created Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "client_id": "s6BhdRkqt3", "client_secret": "cf136dc3c1fc93f31185e5885805d", "client_id_issued_at": 2893256800, "client_secret_expires_at": 2893276800, "redirect_uris": [ "https://client.example.org/callback", "https://client.example.org/callback2"], "grant_types": ["authorization_code", "refresh_token"], "client_name": "My Example Client", "client_name#ja-Jpan-JP": "クライアント名", "token_endpoint_auth_method": "client_secret_basic", "logo_uri": "https://client.example.org/logo.png", "jwks_uri": "https://client.example.org/my_public_keys.jwks", "example_extension_parameter": "example_value" } クライアント管理 RFC 7592 は、登録されたクライアント情報(Client Metadata)を管理(参照 / 更新 / 削除)する仕組みを定義しています。表1に示す通り、クライアント ID をパスに含む REST API として構成することができます。 表1: Client Metadata を管理する用途とリクエスト例 用途 リクエスト例 参照 GET /register/${clientID} 更新 PUT /register/${clientID} 削除 DELETE /register/${clientID} これらの仕様を踏まえた上で、活用事例の紹介に移りましょう。 活用事例1: Terraform を用いた OAuth / OIDC クライアントの宣言的な管理 背景 前述の通り、従来はメルカリグループの OAuth / OIDC クライアントを作成・運用するために、データベースに直接 SQL を実行してクライアント情報を登録していましたが、以下のような課題がありました。 変更履歴の追跡が困難 レビュープロセスの欠如 人的ミスによるセキュリティリスク 複数環境(開発・ステージング・本番)での一貫性の維持が困難 これらの課題に対処すべく、OAuth / OIDC クライアントを宣言的に管理する仕組みとして、Terraform と DCR を組み合わせた仕組みを導入しました。 実装概要 前提として、 Mercari Microservices Platform における Terraform 0.12 対応 で紹介されているように、メルカリでは社内のインフラストラクチャを microservices-terraform と呼ばれる1つのリポジトリで管理しています。この仕組みと DCR を組み合わせることで、Terraform の HCL (HashiCorp Configuration Language) で OAuth / OIDC クライアントを定義し、PR をマージすると自動的にクライアントが生成・更新・削除されます。 図2. Terraform を用いた OAuth / OIDC クライアントの宣言的な管理の概要図 例えば、以下の図 3 に示す通り、Terraform の HCL で宣言すると Plan 結果が GitHub 上にコメントとして表示されます。後はマージするだけで自動的に OAuth / OIDC クライアントが作成される仕組みです。 図3: 新しい OAuth / OIDC クライアント登録のための Terraform の HCL 表現とGitHub 上に表示される Terraform の Plan 結果 この仕組みにより、以下のメリットが得られました。 変更履歴の可視化 : Git によるバージョン管理 レビュープロセスの確立 : PR ベースのワークフロー 自動化 : マージ後の自動適用 IaC : 宣言的な管理による一貫性の確保 技術詳細 Terraform Custom Provider の実装などの技術詳細については、昨年の技術書典16で「OAuth 2.0 Client を Terraform Custom Provider で宣言的に管理してみた」と題して、 Unleash Mercari Tech! vol.3 に寄稿しておりますので、興味のある方はそちらをご覧ください。Terraform の Custom Provider 開発については、 公式ドキュメント も参考になります。 活用事例2: MCP 認可フローにおける動的なクライアント生成 背景 メルカリでは、AI-Native な会社への変貌のため、様々な取り組みを実施しています。その取り組みの一環として Mercari MCP サーバを立ち上げました。この MCP サーバは、2025年11月13日に開催された mercari GEARS 2025 にて、 ChatGPT からメルカリの機能を利用するデモが発表されました。 このデモでは、MCP サーバの認可のために DCR が利用されています。 メルカリでDCR を採用するに至った経緯 MCP の最新仕様である Authorization – Model Context Protocol – Version 2025-11-25 を追っている方は、「DCR は Client ID Metadata Document (CIMD) のフォールバックという位置付けなのでは?」と思われたかもしれません。その通りです。 実際に、 Authorization – Model Context Protocol – Version 2025-11-25 では、クライアント登録のアプローチは次の優先度に従うべき(SHOULD)とされています。 クライアント側で利用可能なサーバの事前登録済情報がある場合、それを利用 認可サーバがサポートしている場合、 Client ID Metadata Document (CIMD) を利用 認可サーバがサポートしている場合、フォールバックとして DCR を利用 他に手段がない場合は、ユーザにクライアント情報の入力を催促 DCR がこのような位置付けになっている理由として、以下の理由などが挙げられます。 登録されるクライアントが無制限に増えるため 登録エンドポイント自体が攻撃に利用されるリスクがあるため クライアントの有効性検証ができないため 詳しくは、 Evolving OAuth Client Registration in the Model Context Protocol | Model Context Protocol Blog をご参照ください。 この優先順位にもかかわらず、メルカリで DCR を選択した理由は以下の通りです。 実装時期の問題 : MCP サーバの実装を開始した時点では、CIMD の仕様がまだ確定していなかったため( Authorization – Model Context Protocol – Version 2025-06-18 では DCR は SHOULD 扱いでした) 既存実装の活用 : メルカリの IdP では、Terraform による管理のために既に DCR を実装済みであり、新規実装コストが低かったため これらの理由で当時は DCR を採用しましたが、複数選択肢のある今、それぞれの長所短所を考慮して選定することが好ましいでしょう。 実装フロー MCP サーバでの DCR 利用フローは以下の図 4 の通りです。 図4: DCR を利用する場合の認可フローを表すシーケンス図 図 4 のフローは以下の通り実行されます。 1.MCP クライアント(例: ChatGPT)がメルカリの MCP サーバへの接続を開始する 2.MCP サーバは、WWW-Authenticate ヘッダとともにステータスコード 401 を返却する 3-4. MCP クライアントは、MCP サーバから Protected Resource Metadata を取得し、認可サーバの情報を取得する 5-6. MCP クライアントが 認可サーバのメタデータエンドポイントを呼び出して、DCR エンドポイントの情報を取得する 7-8. MCP クライアントが、DCR エンドポイント経由で OAuth / OIDC クライアントを作成して、Client Metadata を取得する 9-14-. MCP クライアントは、生成された Client Metadata を使用して認可サーバとの間で認可コードフローを実行し、アクセストークンを取得する 15-16. MCP クライアントは、取得したアクセストークンでMCP サーバの機能にアクセスしてレスポンスを受け取る この仕組みにより、各 MCP クライアントに対して動的にクライアントを作成し、適切なスコープで認可を行うことが可能になりました。 おわりに 本記事では、DCR の活用事例として Terraform を用いた OAuth / OIDC クライアントの宣言的な管理 MCP 認可フローにおける動的なクライアント生成 の2点を紹介しました。 DCR は IdP を内製化している組織だけでなく、外部 IdP を利用する場合でも有用な仕様です。一方で、MCP 認可フローにおいては先述した優先順位を鑑みて選定すると良いと思います。 本記事が皆様の OAuth / OIDC クライアント管理の参考になれば幸いです。ここまでお読みいただきありがとうございました。 明日の記事は @yuさんです。引き続きお楽しみください。
アバター
こんにちは、Merpay の Payment Core チームで EM をしている komatsu です。普段はメルカリグループ全体の決済基盤や銀行接続まわりを担当しています。 この記事は Merpay & Mercoin Advent Calendar 2025 の 19 日目の記事です。 年末ということで、今回は Payment Platform がこの 1 年で取り組んできた 2 つの大きな進化の方向性を振り返ります。1 つは Checkout Solution による統合決済体験の提供、もう 1 つは 2B (法人向け) 決済への展開です。 背景: 決済ニーズの多様化 メルカリグループでは、C2C マーケットプレイスを起点としながらも、さまざまなプロダクトが展開されています。メルカリShops やメルカリNFT、さらには直近リリースした メルカリ グローバルアプリ など、2C の提供先が広がると同時に、スキマバイトアプリであるメルカリ ハロや広告事業であるメルカリAds、外部事業者がメルカリの商品をオファー経由で購入・再販する C2B (Consumer-to-Business) パートナーシップなど、2B の決済スキームも登場し、多様化しています。 Payment Platform は、こうした多様な決済ニーズに応えるため、これまでマイクロサービスアーキテクチャによる決済基盤を構築し、gRPC API を通じて各プロダクトに決済機能を提供してきました。 この 1 年では、さらに 2 つの軸で大きな進化を遂げています。 Checkout Solution – UI を含む統合決済ソリューションへ 背景: gRPC API を超えた、統合ソリューションという選択肢 従来、Payment Platform は gRPC API を通じて決済のバックエンド機能を提供していました。各プロダクトチームは、この API を利用して独自に決済フローや UI を実装していました。 この方式は柔軟性が高い一方で、いくつかの課題もありました。 開発負荷の重複 : 新しい決済手段を追加する際、各プロダクトが個別に UI や決済フローを実装する必要がある UX の分断 : プロダクトごとに決済体験が異なり、統一された UX を提供しにくい ローンチ速度 : 新規プロダクトが決済機能を実装する際、フロントエンドからバックエンドまで一から構築する必要がある これらの課題を解決するため、gRPC API に加えて、 UI を含む統合決済ソリューション という新しい選択肢を提供し始めました。これが Checkout Solution です。 Checkout Solution のアーキテクチャ Checkout Solution は、決済のフロントエンド (UI) とバックエンド (API) を一体として提供する統合ソリューションです。 上図のように、プロダクトは Checkout Solution の UI を組み込むだけで、決済手段の選択から決済完了までの体験を提供できます。バックエンドでは Payment Service をはじめとする既存の決済基盤と連携し、各決済手段の処理を実行します。 詳しいアーキテクチャについては、以下の記事をご覧ください。 決済基盤の新たな挑戦: 決済チェックアウトソリューションの開発 チェックアウトソリューションのバックエンドアーキテクチャ プロダクトチームは Checkout Solution を組み込むだけで、決済フローや UI を一から実装する必要がなくなりました。新しい決済手段の追加も、Payment Platform 側で対応すれば全プロダクトで使えます。 従来のプロダクトは引き続き gRPC API を使いながら、新しいプロダクトは Checkout Solution で迅速な開発とリリースを実現しています。 展開の歩み メルカリNFT での初導入 Checkout Solution は、まずメルカリNFT で初めて導入されました。新しいプロダクトのローンチにあたり、MVP として決済機能を素早く統合できることが実証されました。ユースケースごとの設定の切り替えや、プロダクト固有のコンポーネントの描画も含め、基礎となる機能が実現できました。 メルカリ グローバルアプリへの拡大 その後、先日公開されたメルカリ グローバルアプリでも Checkout Solution のサポートが始まりました。 グローバルアプリでは、日本のお客さま向けに提供しているメルペイの残高やポイント、メルペイのあと払いといった決済手段ではなく、海外のお客さま向けのクレジットカード決済機能を新たに開発しました。Cross Border (XB; 越境販売) 事業に必要な決済機能も、Checkout Solution を通して提供することでスピーディーに立ち上げることができました。 こうして、異なるプロダクト間で統一された決済体験を提供できるようになりました。 また、このタイミングは Payment Platform にとって初めての日本円以外の決済ユースケースでした。 日本円前提だったシステムの多通貨対応も行い、決済やその裏にある会計や帳簿も含めて今後のグロースに耐えうる基盤に進化を遂げました。 多通貨対応の詳細は近日公開予定の Guest post from FT payment platform — Engineering for Multi-Currency and Multi-Provider Payments をお楽しみに。 メルカリモバイルへの導入、サブスクリプション対応: Mandate の導入 グローバルアプリとは別の新しい導入先として、既存のメルカリモバイルの決済方法登録画面の置き換えも行いました。 これまでとは異なり、サブスクリプション型の決済スキーム対応のため、お客さま不在時に自動課金を行うための決済手段選択モードを追加し、 Mandate (継続的な課金への同意) という概念を導入しました。これにより、タイミングに依らないより自由な決済スキームの構築が可能となりました。Mandate の詳細設計については以下の記事をご覧ください。 多様な支払い手段と継続課金を安全に扱う「Mandate」の設計 2C から 2B へも拡張可能なアーキテクチャ また、Payment Platform には以前から、メルカリShops やメルペイ加盟店向けの 2B 精算の仕組みがありました。とはいえ、これらは法人が決済すると言うより、お客さまの決済によって資金が移動する先、というユースケースにとどめていました。そこにメルカリ ハロやメルカリAds が登場し、法人自身が決済を行うケース ^1 も出てきたことで、2B 決済のニーズがさらに多様化してきています。 Checkout Solution は現在 2C をメインに展開していますが、将来的にはこうした 2B 向けの決済でも活用できるアーキテクチャになっています。 Payment Platform があらゆる決済の裏側に加えて、カスタマイズ可能な UI も提供することで、新しい決済手段を追加するたびに各プロダクトが個別に開発する必要がなくなり、統一した UX をお客さまや加盟店に届けられます。 2B 決済への展開 2C 決済と 2B 決済の違い Checkout Solution でも 2B プロダクトのサポートを視野に入れているように、メルカリ ハロやメルカリAds をはじめとして、メルカリグループでは 2B の決済ニーズも増えています。 2B の決済体験を考えるうえで重要なのは、2C との違いを理解することです。 特に 2C と 2B では、アカウントや決済の座組が大きく異なります。 2C: シンプルな構造 1 人 = 1 アカウント 与信、請求、決済の単位が基本的に一致 2B: 複雑な構造 法人の下に支社・店舗・部署が存在し、木構造での管理が必要 与信、請求、決済の単位が異なる場合がある (例: 与信は店舗別、請求は支社単位) 座組が複雑で、柔軟な対応が求められる インボイス制度など 2B 固有の要件が存在 2B 決済のユースケース メルカリグループでは、すでにいくつかの 2B 決済のユースケースが存在しています。 メルカリ ハロ 「メルカリ ハロ」では事業者掛け払いというスキームを提供していました。メルカリが事業者の代わりにクルーに仕事完了時に給料を支払い、月末締め翌月払いで事業者から給与および手数料を回収する仕組みです。 詳しくは以下の記事をご覧ください。 メルカリ ハロにおける事業者請求払いの内製化 メルカリAds メルカリAds では、パートナー企業の広告をメルカリアプリに掲載し、月末締め翌月払いを請求書経由で行う仕組みを提供しています。 C2B 決済 C2B パートナーシップでは、外部事業者がメルカリの商品をオファー経由で購入・再販するビジネスモデルを提供しています ( 大黒屋とのパートナーシップ事例 )。 メルカリ出品者が販売しても売れ残った商品に対して、パートナー企業から買取リクエストが送信されます。出品者が承諾すると、メルカリが出品者から商品を購入し、その後パートナー企業に販売する C2B モデルです。 パートナー企業からメルカリへの決済は、与信に基づくオファーで与信枠内で行われ、月末締め翌月払いで請求されます。現在、パートナー数が限定的であることから与信枠の管理は Finance チームがスプレッドシートを中心に手動で行っています。 2B 決済基盤に求められる要素 2B の決済基盤、特に事業者請求払い (掛け払い) のような与信を伴う決済では、以下の要素が不可欠となります。 上図のように、決済から入金、会計処理まで一連のフローを支える必要があります。 決済および債権の管理 : 決済実行と売掛金の計上 与信管理 : 事業者ごとの与信枠の設定と残高管理、木構造での柔軟な管理 請求書の発行・送付・消込 : 適格請求書の自動発行と送付、入金管理と売掛金の消し込み (入金消込)、事業者ごとに異なる管理単位への対応 入金の受け取り : 入金管理 精算処理 : 月次での精算と会計処理 督促 : 未払いに対する督促処理 これまでの取り組み Payment Platform では、これらの要素を段階的に構築してきました。 外部サービスの活用 メルカリ ハロやメルカリAds のローンチ時には、外部企業が提供する掛け払いサービスを採用しました。ローンチの速度や与信管理の容易性・貸倒リスクを加味した結果、与信審査や貸倒リスクを外部に委譲し、スピーディーにビジネスを立ち上げることにフォーカスしました。Payment Platform としては、これまでの決済 API のインターフェースを保ったまま法人の与信を利用した決済手段である Invoice Payment を Payment Service に導入しました。 一部内製化と手動運用の組み合わせ メルカリAds では一部の企業に対して、外部サービスを使わない内製掛け払いソリューションを提供しました。決済時に Debt Service で債権を計上し、月次で Settlement Service を通じて精算する仕組みです。利用先を限定していたため、請求書の発行や消込は手動運用で対応しました。このタイミングでは、中長期の内製化や掛け払いプロバイダの多様化を見越して、外部サービスの掛け払いを利用する場合と内製掛け払いを利用する場合を抽象化した概念として Invoice Payment API を提供しました。 この取り組みにより、既存の Payment Service と Debt Service を活用した 2B 決済の基礎が築かれました。 Invoice Service のローンチ 2025 年には、2B に対する請求書の発行・管理・送付などを行う Invoice Service システムをローンチしました。これはメルカリAds やその他 2B プロダクトで内製掛け払いに移行していく際に必要となるだけでなく、メルカリ – メルペイ間の精算など、他のビジネスでも利用するための基盤として構築されました。 ここまでで実現できたこと これまでの取り組みにより、事業者請求払いに必要な要素のうち、以下がシステムとして整いました。 ✅ 決済トランザクションの管理 (Payment Service) ✅ 債権の管理 (Debt Service) ✅ 請求書の発行・送付・消込 (Invoice Service) ✅ 精算処理 (Settlement Service) ✅ バーチャル口座 (Virtual Account) による入金管理 (Bank Service) ❌ 与信管理 ← まだシステム化されていない ❌ 督促 ← まだユースケースがない 重要なのは、これらの多くがこれまでのメルカリのプロダクトのために構築した既存マイクロサービスを活用できている点です。汎用性の高い設計が、新しい決済スキームへの迅速な対応を支えています。 これから: 与信管理の内製化 前述の通り、現在 C2B の与信枠は Finance チームがスプレッドシートで手動管理しています。パートナー数が限定的な間はこの運用で対応できていますが、規模拡大に向けてシステム化が必要です。 手動管理では与信残高の即時更新が困難で、ヒューマンエラーのリスクや運用負荷が増大します。また C2B、メルカリAds など複数プロダクトで独自に与信管理を行うと、メンテナンスコストが増大し一貫性も保ちにくくなります。同じ法人が複数プロダクトを利用する場合、与信枠の重複管理や過剰付与のリスクもあります。 与信管理サービスのシステム化 これらの課題を解決するため、統一的な与信管理基盤をシステム化する計画があります。 与信管理サービス として、リアルタイムの与信残高照会・更新、複数事業で再利用可能な汎用設計、法人・支社・店舗といった木構造での柔軟な管理、既存決済基盤との一貫した会計処理を提供していく予定です。 与信管理が内製化されると、以下のように Payment Platform のマイクロサービス群が連携して 2B 決済を支えることになります。 この図から見えるのは、 既存マイクロサービスと新規サービスを組み合わせて全体のソリューションを構築している 点です。 これまでに構築してきた Payment Service、Debt Service、Settlement Service、Bank Service といった共通サービスは、それぞれが明確なドメイン責務を持つため、新しいユースケースでもそのまま活用できます。2B 特有の与信管理や請求書発行だけを新しいサービスとして追加し、請求書送付には Payment Platform 外の Notification Service を活用します。 各サービスは API を通じて疎結合に連携し、Payment Service が決済のオーケストレーションを担うことで、全体として 2B 決済ソリューションを実現しています。このアーキテクチャにより、新しい決済スキームにも柔軟に対応できる拡張性を持っています。 Payment Platform が目指す姿 Payment Platform は、メルカリグループにおける既存サービスのグロース・新規サービスのローンチを簡単に・早く・効率的にできるようにすることを目指しています。 スピード : 新規プロダクトが決済機能を素早く統合できる Checkout Solution のような統合ソリューションを提供することで、プロダクトチームは決済フローや UI を一から実装する必要がありません。 効率 : 各プロダクトの開発負荷を削減 新しい決済手段を追加する際、Payment Platform 側で対応すれば、すべてのプロダクトで使えるようになります。各プロダクトが個別に実装する必要がなくなり、開発効率が向上します。 一貫性 : 統一された UI/UX の提供 UI を含む統合ソリューションを提供することで、異なるプロダクト間でも統一された決済体験を届けられます。 拡張性 : 2C から 2B まで、あらゆる決済シーンをカバー 2B の決済ニーズをキャッチしながら機能を育て、汎用的なソリューションにすることで、メルカリグループの多様な決済ニーズに応えていきます。 まとめ この 1 年、Payment Platform は 2 つの大きな軸で進化してきました。 1 つ目は Checkout Solution による統合決済体験の実現 です。gRPC API に加えて、UI を含む統合ソリューションという新しい選択肢を提供することで、プロダクトチームの開発負荷を削減し、統一された UX を提供できるようになりました。また、多通貨対応も合わせて行い、今後のグローバルなプロダクト展開に耐えうる決済基盤の仕組みも加わりました。 2 つ目は 2B 決済への展開 という新たな挑戦です。2B 決済は始まったばかりの領域ですが、既存の 2C で培った強固なマイクロサービス群を活用しながら、段階的に基盤を構築しています。与信管理サービスによる与信管理の内製化により、2B 決済基盤が完成に近づいていきます。 Payment Platform は、これまで多様な決済ニーズに応えてきた実績を基盤に、今後もメルカリグループの成長を決済で支えていきます。 明日の記事は kobaryo さんです。引き続きお楽しみください。 関連記事 Checkout Solution を活用したメルカリの決済体験 Checkout Solution: Backend 編 Mandates for Recurring Payments: サブスクリプション決済を支える仕組み メルカリ ハロにおける事業者請求払いの内製化 大黒屋とのパートナーシップ
アバター
こんにちは。メルカリのPlatform Network team/SREの @mshibuya です。 この記事は、 Mercari Advent Calendar 2025 の18日目の記事です。 年の瀬って忙しくなりがちですよね。ただでさえ忙しいのに、Advent Calendar記事執筆の予定まで入れてしまい、半泣きでこの記事を書いています。いや、こうなるのはわかってはいたんですが、一年を振り返ってアウトプットの少なさに焦ってしまうとやはり記事執筆に名乗りをあげてしまうのですよね…。 さて、今回はKubernetes環境におけるネットワークのパケットキャプチャの話をします。筆者は現在前述の通り Network team に所属しており、そこではメルカリのプロダクト開発を支える様々なPlatformとしてのコンポーネント群のうち、ネットワークに関わるものを中心に扱っています。 メルカリでは数百を超える規模のマイクロサービスが稼働しており、そのサービス内外におけるネットワークコミュニケーションも複雑多岐にわたります。Network teamはその性質上、そういった環境で発生したネットワークに起因すると思われる不具合・問題の調査を依頼されることが多くあります。もちろん単純な設定不備などが原因の場合もありますが、問題が複雑で解決の糸口がなかなか見出せないような局面において、深い分析を行う手段を必要としていました。そこでパケットキャプチャが登場します。 こういった問題調査のための手法は、それ自身の実行手順が明確になっていなければいざ問題が発生した際に役立てることはできません。緊急度の高い障害が発生しているような状況下であればなおさらでしょう。今回確立したこの手法は、みなさまの環境においてそのまま適用可能とは限りませんが、それでも安定して実行できる調査手順を紹介しておくことは、みなさまがご自身の組織で同様の手順を作る際にも役立つであろうと考えたのがこの記事を公開する狙いです。 なぜKubernetesでのパケットキャプチャは難しいのか みなさまご存知の通り、KubernetesはハードウェアやOSといった様々なレイヤにおいて抽象化を提供しており、それによって開発者が生のリソースに煩わされることなくワークロードを実行可能な環境を提供しています。セキュリティ上、一般には利用者である開発者は生のノードにはアクセスできないようになっており、またその上で動くPodのようなワークロードもMulti-tenancyとして互いに隔離されています。そのため、昔のように単純にサーバ上でtcpdumpを叩けばおっけー、とはいかないわけですね。 また、Service Meshにまつわる難しさもあります。メルカリではIstioを導入していますが、クラスタ内の通信は基本的にmTLSによって暗号化されているため、そのままでは通信の中身を見ることができません。この点を考慮した手法を確立する必要があります。 こうしたKubernetesクラスタを含め、開発者が機能を簡単に素早くデリバリーするために必要な道具立て一式を提供しているのが我々Platformとしての立ち位置です。このようなネットワークにおける深いトラブルシューティングの必要性がいつ生じるかは予想できません。特別なPlatform特有の権限によることなく、必要であれば開発者がセルフサービスによってこのような調査を行えることも大事な要件としました。 Ephemeral Containersを活用したPodレベルでのキャプチャ 前述の条件を満たす手法として我々が確立したのが、Kubernetesの機能である Ephemeral Containers を活用した手法です。 Ephemeral Containers(エフェメラルコンテナ)は、Kubernetes v1.25でGAとなった機能です。ノード全体へのアクセス権限を持つことなく、実行中のPodのネットワーク名前空間などの共有リソース内に、一時的なデバッグ用コンテナを「外付け」する形でアタッチできます。これにより、tcpdumpなどのデバッグツールをアプリケーションコンテナ内に含める必要なくトラブルシューティングを行えるため、このようなパケットキャプチャに用いるにはうってつけです。NodeやCluster全体への特別な権限を必要としない点も大きなメリットで、Platformメンバーも開発者も同じ方法によって調査を行うことができます。 具体的な手順としては、下記のようになります。 Step 1. 必要な権限の取得 メルカリでは、 Carrier と呼ばれる一時的な権限取得を可能にする内製ツールによって、通常時は本番環境に対する操作権限を持たないZero Touch Productionを実現しています。 このため、本番環境における問題調査においてパケットキャプチャを実施する際には、対象となるPodに対する操作権限を持つRoleをまず取得する必要があります。 上記Roleには、Ephemeral Containersに対する操作を行うために必要なpermissionを事前に付与しておきます。 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: example-role rules: # ... - apiGroups: [""] resources: ["pods/ephemeralcontainers"] verbs: ["create", "delete", "deletecollection", "patch", "update"] Step 2. Ephemeral Containerの起動 権限が得られたら、対象となるPodに対してEphemeral Containerをアタッチします。ここではパケットキャプチャも含む、ネットワーク全般のトラブルシューティングに対応したリッチなツールセットがインストール済みのnetshootを用いています。 kubectl debug -it -n <your-namespace> <target-pod> \ --image=nicolaka/netshoot \ --custom=./root.yaml --container=netshoot-debug ここで、ファイル ./root.yaml には事前に以下の内容を準備しておきます。 securityContext: runAsUser: 0 runAsNonRoot: false これにより、コンテナ内でtcpdumpを実行するための必要条件である「rootとしてnetshootコンテナを実行する」を実現します。大して長い内容ではないので、本当はコマンドラインにインラインで書いてしまいたいのですが、今のところkubectl debugの引数としてはファイルを渡すことしかできないようです…。 Step 3. キャプチャの実施 無事にnetshootコンテナのシェルが開いたら、キャプチャをスタートできます。ここではファイル /tmp/capture.pcap に書き込んでいます。 tcpdump -i any -w /tmp/capture.pcap Istioが有効化された環境化においては、この -i any がポイントとなります。トラフィックは eth0 だけでなく、iptablesによってリダイレクトされた仮想インターフェースをも通るため、これらを取りこぼさないように全インターフェースを対象にしています。eth0のみをキャプチャすると、mTLSによって暗号化済みの内容しか取れないため、調査の目的に対し不足することが多いでしょう。 単純に全トラフィックをキャプチャするとデータが膨大となってしまい得ます。ここでは詳細は触れませんが、tcpdumpのオプションによってキャプチャするパケットをフィルタできるため、調査しようとしている問題に関係するパケットにできるだけ絞り込んでキャプチャするとその後の調査が楽です。もちろん、絞り込みすぎると「必要なデータが取れてなかった」というトレードオフになります。 Step 4. ファイルの回収 上記によってEphemeral Containerにファイルが作成されるので、ローカルよりkubectl cpでダウンロードすれば完了です。Step 2でつけたコンテナ名を指定するのをお忘れなく。 これでキャプチャしたデータの分析に移れます。 kubectl cp -n <your-namespace> <target-pod>:/tmp/capture.pcap ./capture.pcap -c netshoot-debug 慣れてきたら、Step 2-4までをワンラインで行ってしまってもいいでしょう。このような見た目になります。余計な出力がファイルに混入しないよう -iq を使い、また標準エラー出力を捨てています。 -G 10 でキャプチャを行う秒数を指定しています。 kubectl -n <your-namespace> debug <target-pod> -iq --image=nicolaka/netshoot --custom=./root.yaml -- bash -c 'tcpdump -i any -G 10 -W 1 -s0 -w - 2>/dev/null' > tcpdump.pcap Nodeレベルでのキャプチャ 上記Podレベルでのキャプチャ方法とは別に、GKE NodeにSSHし CoreOS Toolbox を用いてパケットキャプチャを行う手順も整備済みです。が、Nodeに対しSSHを行える権限を持つ必要があること、また前述のようにIstioのトラフィックは暗号化されたものしか取得できないこともあり、あくまで補助的な位置づけです。主にPlatformメンバーがNodeレベルでしか観測できないようなトラブルシューティングに用いることを想定しています。 Step 1. 必要な権限の取得 メルカリではKubernetesクラスタをGoogle Kubernetes Engineによって構築・運用しています。まず、GKEノードにSSHするために必要な権限を、前掲のCarrierを用いて取得する必要があります。該当プロジェクトに対し下記の権限があれば十分なはずです。 roles/compute.instanceAdmin.v1 roles/iam.serviceAccountUser roles/iap.tunnelResourceAccessor Step 2. Nodeの特定 kubectl get podコマンドで、対象Podがホストされているノード名を確認します。 $ kubectl get pod -n <your-namespace> your-app-pod-7f5b7f7d9f-abcde -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES your-app-pod-7f5b7f7d9f-abcde 2/2 Running 0 2d1h 10.1.2.3 gke-cluster-1-node-pool-1-a1b2c3d4 <none> <none> Step 3. toolbox環境に入る gcloud compute ssh を使用してノードにSSHし、 toolbox コマンドで、デバッグツールが揃ったシェル環境に入ります。 gcloud compute ssh --project <your-project> gke-cluster-1-node-pool-1-a1b2c3d4 # On the GKE node $ toolbox Step 4. キャプチャの実施 toolboxシェル内でtcpdumpを実行します。ホストのルートファイルシステムは /media/root にマウントされているため、キャプチャファイルはノードの /tmp に相当する /media/root/tmp/ に保存します。 -i any で全インターフェースからキャプチャを行うことを指定し、フィルタとしてStep 2で確認したPodのIPアドレスを指定します。 # Inside the toolbox shell $ tcpdump -i any -w /media/root/tmp/node_capture.pcap host 10.1.2.3 Step 5. ファイルの回収 toolbox シェル ( exit )、SSHセッション ( exit ) の順で終了し、ローカルマシンからgcloud compute scpでファイルを手元にコピーします。 gcloud compute scp --project <your-project> gke-cluster-1-node-pool-1-a1b2c3d4:/tmp/node_capture.pcap ./node_capture.pcap こちらのNodeレベルでのキャプチャはまだ実際の調査で利用した実績はありませんが、こうして手順として整備しておけばいざ問題が発生した際も落ち着いて調査に入れます。 まとめ この記事では、メルカリにおけるKubernetesパケットキャプチャのプラクティスについて紹介しました。 とりわけPodレベルにおいては、Ephemeral Containersを活用することで、セキュリティと利便性のバランスを取りながら開発者が自身でトラブルシューティングを行える手順を整えています。 Podレベル (Ephemeral Containers) Nodeレベル (Toolbox) 主な用途 アプリケーション固有の問題調査、mTLS化された通信内容の確認 Node全体に関わるネットワーク問題(CNI、iptablesルールなど)の調査 必要な権限 比較的低い (Podレベルの権限) 高い (NodeへのSSHアクセス権限) Istio環境でのトラフィックの可視性 暗号化前の平文トラフィックをキャプチャ可能 暗号化後のトラフィックしかキャプチャできない 対象の絞り込みやすさ 調査対象のPodに直接アタッチするため、トラフィックの特定が容易 複数Podが稼働するため、対象Podのトラフィックを分離するのが比較的困難 推奨される利用者 アプリケーション開発者、SRE Platformチーム、SRE セルフサービスへの親和性 高い (開発者が自身で調査可能) 低い (強い権限が必要なため限定的) 今回ご紹介した内容をさらに発展・一般化したお話を来年3月開催の SRECon26 Americas において「It’s Not Always the Network (But Here’s How to Prove It): Kubernetes Packet Capture for SREs」というタイトルで発表予定です。いや、まだ実感がないというか信じられないのですが、ProposalがAcceptされたという連絡はいただいたので、登壇しにシアトルに行ってくると思います…。 パケットキャプチャを行った次のステップとしては、実際にキャプチャしたデータを分析するフェーズが待っています。紙面の都合上、また筆者がその分野ではまだまだ修行中ということもあり今回は触れませんでしたが、今後またなんらかの知見を共有していけたらと思います。 最後までお読みいただきありがとうございました。明日の記事はamenboさん・siroken3さんによる「AI-Native開発を加速する AWS Kiro の導入と、Okta を活用したアカウント管理の自動化」となります!引き続きお楽しみくださいー
アバター
はじめに こんにちは。メルペイの Balance チームでインターンをしている @minato です。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の18日目の記事です。 2025年10月からメルペイでバックエンドのインターンを始め、3ヶ月目になります。 本記事では、インターン期間中に取り組んだタスク、得ることのできた学びについて紹介します。 取り組んだタスク 今回のインターンでは、債権データを管理するマイクロサービスにおいて、これまで同期的に行っていた債権残高の更新処理を非同期処理へと移行するタスクに取り組みました。 以下、非同期処理へ移行するに至った背景、設計、実装、負荷試験について説明していきます。 背景 メルペイでは現在、世界共通のプラットフォームを提供する「 メルカリ グローバルアプリ 」プロジェクトが進められています。これまで国ごとに限定されていたプロダクトをグローバルに展開するにあたり、これまでになかった量の Transaction が集中することが想定され、負荷分散機能の検討・開発が必要となりました。 このような理由から、僕は、負荷分散を必要とする機能の一つである債権の作成機能の改善に取り組みました。 債権データの作成プロセスでは、債権を作成した後、該当する債務者の債権残高を更新する必要があります。なので、債権データの作成リクエストが連続して行われた際、特定の行やカラムに更新が集中してしまい、その箇所が hotspot となり、以下の問題を起こします。 高負荷が特定の行に集中し、ロック競合が多発する 更新待ちが発生し、スループットが低下する この問題を解決するために、債権残高をリクエスト中に同期的に更新するのではなく、非同期で更新することにしました。非同期化することで、本来複数の Transaction で処理されるはずの複数の Request による債権残高の更新を、一つの Transaction でまとめて処理することができ、hotspot 問題を解決することができます。 設計 大まかな設計としては、債権残高の更新処理が発生した際に債権更新イベントテーブルへレコードを作成し、worker がそのテーブルを取得して Job Queue に push、Job Processor が Job Queue 内のアイテムに基づいてアカウントを更新するという流れとしました。 また、Job Queue については、債権更新イベントテーブルに、Job Queue に入っているかを表すフィールドを設けることで、DB を Job Queue として使用できる仕組みとしました。なぜイベントの管理を、外部サービスではなく DB で管理としたのかというと、外部サービスへの依存を避けられること、同様の処理を行うマイクロサービスにおいて DB で管理する構成で正常に機能しているためになります。 以下の画像は、非同期イベントをどのように処理しているのかについて表したものです。Workerは DB から処理されていないイベントレコードを取得し、server上のメモリ(以下の図の Queue) に保存します。その後、Job Processor が Queue 内のイベントをまとめて処理するという構成になります。 実装では、Worker、Queue、Job Processor のそれぞれについてカスタマイズしやすい struct を定義し、他の非同期処理において再利用できるようにしました。 実装 今回の実装では、社内で活用が推進されている ASDD(Agent Spec Driven Development) という方法を使用しました。ASDD とは、AI agent が仕様書を作成し、別agentがその仕様書に基づいて実装を進めるという手法です。詳しくは、 pj-double: メルカリの開発生産性向上に向けた挑戦 — AI-Native化が辿り着いたASDDとプロセス変革の全貌 の記事をご覧ください。 アカウントの非同期化は、システム全体に関わる非常に大きな機能改善であったため、厳密に設計をDocsとして記録すること、レビューのしやすさを考慮し、仕様書自体は僕が手作業で作成したため、時間を消費してしまいましたが、その後の実装はあっという間にAIによって完了し、とても驚きました。 「もし社内の全員が ASDD を使いこなす未来が来たらどうなるのか」 と想像するだけでワクワクする体験でした。 負荷試験 負荷試験については、まだ行っていないため、これから取り組む予定のことを説明します。今回の負荷試験では、想定される平均リクエスト数と最大リクエスト数をテスト環境に対して送信し、システムがどの程度安定して処理できるかを確認する予定です。 また、債権残高の更新イベントが生成されてから、非同期的に実際に更新されるまでの処理時間についても計測しようと思います。というのも、債権残高の更新される速度は、債権の処理を行う上流のサービスにとって非常に重要なものになるためです。 テスト計画を立てる中、驚いたことは、負荷試験のためのリポジトリが整備されていたことです。専用のリポジトリが存在することで、誰でも容易に負荷試験シナリオを作成でき、さらに他者が同じ条件で負荷を再現できるため、検証の透明性と再現性を保つことができます。 インターンを通して得た学び 今回のインターンでは、日常の開発ではなかなか扱うことのできない規模のリクエスト数を処理するシステムの開発を経験することができ、技術的な学びはもちろん、コーディングに対する姿勢やプロダクトへの向き合い方について学びました。 コーディングへの取り組み方 インターンを通じて特に印象的だったのは、コメントを書かずとも、関数名、コードから類推がつき、後から読んだ際に一目で何をする処理なのかを理解できるレベルを目指す姿勢です。保守・運用のことまで考えたコードを書くことは普段の開発においても、心掛けているのですが、普段の自分を見つめ直し、コーディングへの姿勢を改めるきっかけになりました。 また、レビューの際に、ファイル内のコメント一つに対しても、どのような意図を持って書いたのか、また、そもそもそのファイルは何のためにあるのかといったことを指摘していただき、開発においてメタ的に考えることと具体的に考えることの両方を行うことの重要性を実感しました。 プロダクトのことを第一に考える開発 また、プロダクトに対する心構えについても、非常に刺激を受けました。チームのメンバー一人一人が、プロダクトの未来を考えながら、意思決定をしており、「将来的にこう使われる可能性があるから、今の内にこの手法を採用しておく」、「お客さま体験を良くするためにこのデータ構造はこうあるべき」といった議論が開発中だけではなく食事中にも頻繁に行われており、プロダクトへの愛とメルカリの Values の一つである Be a Pro の精神を強く感じました。 その他の活動と経験 インターン期間中は、開発のタスクにのみ取り組むのではなく、Qに1回開催されている社内イベントのTech Talkに登壇してみたり、他のチームの方と1on1やランチに行ったり、技術書やテックブログの読み合わせ会に参加したりと、いろいろな活動をしました。 ランチではバックエンドエンジニアの方だけではなく、セキュリティエンジニアの方とも話す機会をいただき、なぜその職種を選んだのかというキャリアの話から、最近の攻撃手法、日々の開発で意識すべきセキュリティ観点まで、バックエンドに閉じない視点を得ることができました。 また、Tech Talk や読み合わせ会に参加し、メルカリは、自発的に技術を学びに行ったり、技術について情報発信する環境が本当に整っていることを強く実感し、エンジニアにとって最高の環境だと思いました。 さいごに インターンを通して、タスクに取り組む中で技術的な学びだけではなく、AIの活用方法、エンジニアとしての姿勢についても多くの学びを得ることができました。特に、エンジニアとしての姿勢は、これからの働き方に活かしていこうと思います。インターンとして参加できる残りの期間では、負荷試験までやり切り、可能であればリリースまで完了させたいと考えています。 今回の開発をリードしてくださった@yutaroさん、メンターの@kobaryoさん、そしてチームの皆さんを始め関わってくださった全ての方々、本当にありがとうございました! 明日の記事は@komatsuさんです。引き続きお楽しみください。
アバター
はじめに こんにちは。メルペイのPayment Core team/Backend Engineerの@tomoです。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の17日目の記事です。 都度払いから継続決済へ これまでメルペイの決済は、メルカリでの買い物や、お客さまがスマホを取り出してバーコードを提示したりボタンを押したりすることで完了する、いわゆる都度決済が中心でした。しかし、メルカリのエコシステムが拡大するにつれ、決済のあり方は大きく変化しています。 例えば、私たちが提供を開始したメルカリモバイルでは、毎月の利用料金を支払うためにお客さまが都度アプリを開くことはありません。システムがバックグラウンドで自律的に決済を実行します。 このように、決済はもはや単発のイベントではなくなりつつあります。お客さまの操作を伴わずに実行される オフセッション決済──サブスクリプション課金のように、継続的に行われる支払い形態が増えてきています。 そして、メルカリ特有の多様な支払い手段を組み合わせつつ、これらの継続決済を大規模に安全に実行するために、私たちは Mandate (マンデート) と呼ばれる新しい概念を導入しました。 Mandateとは 「Mandate」という言葉は日常では馴染みが薄いかもしれませんが、Fintech の領域では口座振替依頼や自動引き落としの同意を表す一般的な用語です。Stripe の SetupIntent や、インド UPI の AutoPay など、世界中の決済プラットフォームで同様の仕組みが提供されています。 身近な例として、動画配信サービスのサブスクリプションがあります。お客さまは初回登録時にクレジットカード情報を登録し、「毎月このカードから定額を引き落としてよい」という包括的な許可を与えます。この「将来の支払いに関する包括的な同意」こそが Mandate の本質です。これらは一般に「オフセッション決済」と呼ばれます。請求の瞬間にお客さまが操作を行わずに決済が実行される決済形態を指します。 メルカリにおける Mandate も同じ考え方で、お客さまがサービス(例:メルカリモバイルサービス)に対して「メルペイ残高やポイントなどを用いて、未来の支払いを行ってよい」と認可するデジタルな契約を示します。 一般的なMandateは、特定の「クレジットカード」や「銀行口座」に1対1で紐づきます。たとえば、あるサブスクAの支払いに対してクレジットカードBで契約するためのMandateを作成するという具合です。しかし、メルカリのお客さまは以下のような多様な決済手段を持っています。 売上金・残高 無償ポイント・有償ポイント メルペイのあと払い クレジットカード 「ポイントが余っていればポイントを優先し、足りなければ残高から、それでも足りなければあと払いで」――このような複合決済を毎回お客さまの操作なしに行うには、単一のカードへの紐付けでは不十分です。そのため、Payment Platformでは、複数の決済手段に対してMandateを作成できるようにしました。つまり Mandate は、「多様な支払い手段を組み合わせて継続的に課金する」というメルカリ特有の要件を、安全に実現するための基盤として設計されています。 メルペイにおける Mandate Mandate を構成する 3 つの基本要素 オフセッション決済では、誰が → 誰に → どう支払うか の三要素がそろって初めて正しい権限判定ができます。この三要素によって Mandate のスコープを定めます。 Customer(誰が支払うか):お客さま Partner(誰に支払うか):料金を受け取るサービス(例: メルカリモバイル) Payment Method(どう支払うか):ポイント、残高、あと払い、クレジットカードなどの組み合わせ Mandate をこの三軸の組み合わせで表すことで、余計な権限を持たせることなく、監査に耐える説明可能性を確保し、かつ決済実行時の判定を機械的に行えるようになります。 Mandateの管理はWallet Serviceによって行われます。Wallet Service は、あんしん支払い設定など、お客さま固有の設定や支払い権限を管理する基盤サービスです。 決済サービスによる必須の Mandate 検証 オフセッション決済はお客さまの操作を伴わないため、何よりも安全性が求められます。Mandate が存在しない、あるいは範囲外の決済が誤って実行されることは絶対に避けねばなりません。 私たちはその安全性を担保するため、決済作成 API( CreateCharge )に Mandate 検証ロジックを統合しました。 クライアントはオフセッションとして決済を実行する意図を示すために mode=off_session を指定して CreateCharge を呼び出し、Mandate の有無を事前に確認する必要はありません。 Payment Service は mode=off_session を受け取ると、Wallet Serviceの CheckMandateExistence APIを呼び出し同期的に検証を問い合わせます。Mandate が存在し、スコープ内で有効なものであれば決済を実行し、そうでなければ即座にエラーを返して処理を中断します。 こうしてプラットフォームが Gatekeeper として機能することで、サービス側の実装に依存しない堅牢な安全性を確保しています。 決済チェックアウトソリューションで Mandate-Free な開発者体験を実現する Off-session modeのCreateChargeでは、クライアントはMandateの存在を意識せず使用することができます。しかし、サービス契約時には Mandate関連のAPI 呼び出しを実装する必要があります。つまり、サービス側のエンジニアはmandateの作成・削除などライフサイクルに関する仕様を理解し、実装しなければいけません。 そこで Payment Platform 側では、 決済チェックアウトソリューション と組み合わせることで、クライアントが Mandate の API 仕様を意識せずに済む「Mandate-Free」な開発体験の実現を目指しました。 メルペイのチェックアウトソリューションは、決済向けの共通チェックアウト画面を提供する仕組みとして開発されました。決済 UI や 3DS 対応をプロダクトが個別に実装する必要がなくなり、基盤側で統一的に提供できるようになったものです。 さらに今回、このチェックアウトソリューションに setup mode を新設し、支払い手段の登録フローも一括で管理できるようにしました。setup mode のチェックアウトソリューションを通じてお客さまがサービス利用のための支払い手段を登録すると、内部でMandate関連APIを呼び出し、Wallet Serviceに Mandate を作成・更新します。 結果として、クライアントはお客さまに支払い方法を設定させるために チェックアウトソリューション を呼び出すだけでよく、以降の継続課金も mode=off_session の CreateCharge を呼ぶだけで完結します。Mandateの検証やスコープチェックは Payment Platform 側が強制するため、クライアントは決済実行時に必要となる細かな権限管理ロジックを扱う必要がなくなります。 メルカリモバイルにおける実践 Mandate と チェックアウトソリューションの統合は、現在メルカリモバイルのクレジットカード決済で本番運用されています。 お客さまはサービス契約時に一度だけ チェックアウトソリューション を通じてクレジットカードを支払い手段として登録します。登録後、クレジットカードは内部的に Mandate と紐づけられ、以降の毎月の料金請求はオフセッションで自動的に処理されます。お客さまが特別な操作をすることはありません。 メルカリモバイル開発者にとっても、複雑なカード登録フローや Mandate 管理といった重たい実装から解放され、「契約時に チェックアウトソリューション を使用する」「毎月 off_session で CreateCharge を呼ぶ」という最小限の実装だけで安全な継続課金が実現できています。 おわりに 本記事では、メルカリの多様な支払い手段と複雑なビジネス要件を背景に、将来の支払い権限を管理する基盤としての Mandate と、その Mandate をお客さまにも開発者にも意識させない形で統合した チェックアウトソリューション(setup mode) の実践を紹介しました。 明日の記事は@Minatoさんです。引き続きお楽しみください。
アバター
こんにちは。Mercari Ads teamのEngineering Managerの @ogataka50 です。 この記事は、 Mercari Advent Calendar 2025 の15日目の記事です。 1. はじめに Mercari Ads では、メインの DB として TiDB を採用しています。HTAP(Hybrid Transactional and Analytical Processing)により、広告設定などのオンライン処理(OLTP)と、impression・conversion の集計などのバッチ処理(OLAP)を単一クラスタで運用しています。しかし、ワークロードの多様化とトラフィック増加に伴い、リソース競合による性能劣化が次第に顕在化しました。具体的には次のような事象です。 バッチ処理や集計処理が TiDB に過度な負荷をかけると、広告管理ツール(Ads Manager)の操作のレスポンスが悪化し、サービス品質(UX)に悪化 逆に、オンライン処理が重くなったときにバックグラウンドのレポート集計やバッチ処理が大幅に遅延。これによりレポートの生成やデータ更新が遅れ、期待どおりの動作にならない このような異なるワークロード同士のリソース競合によって、システムの安定性やパフォーマンスが低下する課題に直面していました。 そこで、TiDB の Resource Group を使って、用途(オンライン/バッチ/レポートなど)ごとにリソースを論理分離し、干渉しないよう制御することにしました。 本記事では、Resource Group の概要と、どのように導入を進めたかを共有したいと思います。 2. Resource Control の概要 Resource Group は、TiDB におけるリソース制御機能のひとつで、論理的な「グループ 」に分け、各グループに対して CPU/I/O/ストレージへのアクセス量を制御できます。 この制御の単位となるのが Request Unit (RU)になります。RU は CPU 時間やディスク I/O、IOPS など複数リソースの消費量を統合して評価する抽象的な単位です。 TiDB の公式ドキュメントでは以下のように RU の消費定義 が示されています。 Resource Group を使い、複数のワークロードで必要なTiDBのリソースを論理的に分離して、リソース競合を防ぎつつ、必要に応じてリソースを割り当て直すことができます。具体的には以下のような処理です。 オンライン処理には高めの RU を割り当てる + 高優先度で処理させる バッチ/分析には必要最小限の RU を割り当て、低優先度で処理させる この仕組みによって、オンライン処理のレイテンシを維持しつつ、バッチや分析処理も同時に安定して実行できるようにすることを目指しました。 3. 実際の導入方法 3.1 サービスごとに SQL ユーザーと Resource Group を分離 Mercari Ads では、各マイクロサービス (広告管理 UI、レポート生成バッチ、分析サービスなど) ごとに SQL ユーザーを分け、それぞれに専用の Resource Group を割り当てるようにしました。 クエリ単位でヒントを使って Resource Group を設定することも可能ですが、多数のサービス/クエリが混在すると運用が煩雑になりやすいため、SQLユーザー単位での分離することから始めました。 3.2 Resource Group の定義例 まずは Resource Group を作り、それを SQLユーザーに紐付けるような流れになります。 次の SQL で Resource Group を作成します。 -- create Resource Group CREATE RESOURCE GROUP IF NOT EXISTS rg_online RU_PER_SEC = 2000 PRIORITY = HIGH BURSTABLE; CREATE RESOURCE GROUP IF NOT EXISTS rg_batch RU_PER_SEC = 500 PRIORITY = LOW; RU_PER_SEC: 1 秒あたりに補充される RU の量 (トークン・バケットの回復速度) を指定 PRIORITY: ストレージ層 (TiKV / TiFlash) 側でのタスク優先度 — 高優先度なら他より先に処理される BURSTABLE: 状況に応じて余剰リソースの利用を許可する設定。負荷が低いタイミングでは余裕を使える どの Resource Group をどの SQL ユーザーに割り当てるかを、以下の SQL で設定します。 -- bind Resource Group and SQL User ALTER USER 'ads_service_sql_user' RESOURCE GROUP rg_online; ALTER USER 'batch_job_sql_user' RESOURCE GROUP rg_batch; optimizer hintsを追加することでSQL単位でResource Group を指定することも可能です。 -- SQL 単位で Resource Group を指定する例 SELECT /*+ RESOURCE_GROUP(rg_name) */ * FROM table_name; 3.3 モニタリング → 設定の見直しサイクル 次のようなサイクルで適切な設定値の調整をしていきました。 まずは制限なしのRU_PER_SEC (default / unlimited 相当) での Resource Group を作成し、各サービスの「通常負荷時」のリソース消費を観測 CREATE RESOURCE GROUP IF NOT EXISTS rg_monitoring RU_PER_SEC = 2147483647; 1週間程度監視し、通常時のRU 使用量、I/O/CPU 負荷、クエリ数などを把握する 用途 (オンラインかバッチなど) に応じて RU_PER_SEC・PRIORITY・BURSTABLE を設定し直す オンライン処理: RU_PER_SEC 高め / HIGH 優先度、必要なら BURSTABLE を使うことを検討 バックグラウンド(バッチ/分析)処理: RU_PER_SEC 控えめ / LOW 優先度 このサイクルを継続し、各 Resource Group の RU_PER_SEC を徐々に適正化しました。 4. 平均値ベースだけではなく、瞬間的な RU の消費も考慮する Resource Group を SQL ユーザーごとに分け、RU_PER_SEC の設定を進めていく中で、意図通りにいかなかったケースがありました。あるサービスは、平常時はほとんど TiDB にアクセスしないのですが、ユーザが期間の長い広告レポートをリクエストした際にだけ、大量のデータを読み取る集計処理が発生し、瞬間的に多くの RU を必要とするケースがありました。このような場合平均値ベースの RU 消費は小さく見えます。しかし実際には、1 回のリクエストで数千〜数万 RU を消費するようなスパイクがあり、平均値を基準に RU_PER_SEC を設定していたため、このスパイク時に上限に達してしまい、必要な RU を確保できず著しくパフォーマンスが低下する状況が生まれてしまいました。 そのため、RU_PER_SEC の設定では平均値だけではなく、瞬間的なスパイクにも対応できるよう考慮する必要があります。こうしたユースケースでは、必要に応じて BURSTABLE を有効化し、一時的に余剰リソースを利用できるようにすることも効果的です。 5. Runaway Query の制御と管理 Resource Group によるリソース分離だけでなく、想定以上にリソースを消費するクエリを制御、管理する機能があります。 Resource Group 定義に、QUERY_LIMIT オプションを追加することで、あるクエリが長時間実行される、または過剰にリソースを消費するような クエリを検知し、強制終了 (KILL)、優先度変更といった制御が可能です。 TiDB では、このような予想以上にリソースを消費するクエリを Runaway Query と呼んでいます。 たとえば、以下のように定義することで、「30秒以上実行されるクエリは自動的にkillする」などの制御ができます。 -- configure QUERY_LIMIT on resource group CREATE RESOURCE GROUP rg_online_limited RU_PER_SEC = 10000 QUERY_LIMIT = (EXEC_ELAPSED = '30s', ACTION = KILL); こうした制御を入れることで、意図せぬ重たいクエリや無限ループ/誤った SQL による極端なリソース消費や、他ワークロードへの影響を防ぐ一助になります。 発生した Runaway Query は、次の SQL で確認できます。 -- select Runaway Query by Resource Group SELECT * FROM mysql.tidb_runaway_queries WHERE resource_group_name = 'rg_online_limited' ORDER BY start_time DESC LIMIT 100; 6. まとめ & 今後の展望 Resource Groupの導入によって、オンライン処理に必要な RU を安定して確保できるようになり、Ads Managerのレイテンシがバックグラウンド処理の影響を受けにくくなりました。また、バックグラウンド処理側も過剰にリソースを奪わない範囲で着実に実行されるようになり、ワークロード間の競合による性能劣化が減少しました。 実施した内容をまとめると、以下の通りです。 現状のワークロード把握 各SQL user(≒サービス)ごとにどのようなシステム要求があるかリストアップ (オンライン/バッチ/Background/分析用途など) 最初は制限なし (default / UNLIMITED 相当) で動かし、どれくらい RU を消費するか観測 モニタリング期間 (数日〜1週間) 通常時のRU 消費を計測 特にバッチや分析クエリのピーク時の消費量に注意する ワークロードごとに Resource Group の設定値を設定 オンライン処理: 応答性重視 → RU_PER_SEC を比較的高め、PRIORITY = HIGH、必要なら BURSTABLE を使うことを検討 バックグラウンド処理: RU_PER_SEC を控えめ、PRIORITY = LOWで必要以上のリソースを消費しないようにした 必要に応じて Runaway 制御 (QUERY_LIMIT) を設定 継続的な運用とレビューサイクル 定期 (週次/月次) で RU 消費状況、遅延・タイムアウト・失敗のログをチェック 発生したRunaway Queryの確認 必要に応じてResource Group 設定を調整 今後は引き続き下記のような改善、調整を行っていこうと考えています。 スパイクが発生するケースでは、一時的に割当を調整するなど、Resource Group と Runaway 制御を組み合わせた運用改善 定期レビューの自動化。どのサービスがどれくらい RU を使っているか/どの程度余裕があるかなどを可視化と調整 本記事が TiDB 運用の一助となれば幸いです。 明日の記事は @Snehaさんです。引き続きお楽しみください。 7. Refs Use Resource Control to Achieve Resource Group Limitation and Flow Control CREATE RESOURCE GROUP Manage Queries That Consume More Resources Than Expected (Runaway Queries) TiDB Resource Control: Stable Workload Consolidation of Transactional Apps Managing Resource Isolation: Optimizing Performance Stability in TiDB
アバター
はじめに こんにちは、Ads Servingチームでバックエンドエンジニアをしている@yanapです。 この記事は、 Mercari Advent Calendar 2025 の14日目の記事です。 メルカリは 2025年10月時点で 月間 2,305 万人 のお客さまに利用されており、検索や閲覧などの操作に合わせて広告が表示される「メルカリAds」にも、毎日非常に多くの広告リクエストが届きます。 広告候補は用途ごとに多数存在し、その中から最適な広告を選び出す必要があります。 しかし、どれだけ処理が複雑であっても、広告は 数百ミリ秒以内 に返さなければ検索体験を損ねてしまいます。 大規模なトラフィックの中で高速に広告を選定する仕組みを成立させるのは、簡単ではありません。 お客さまがメルカリアプリで「トマト」と検索したその瞬間、裏側では広告配信のための小さな通信が静かに動き始めています。 その通信を受け取り、複数の内部サービスと連携しながら最適な広告を短時間で選定して返す仕組みを、Ads Serving チームが担当しています。 本記事では、この広告配信フローの全体像と、低レイテンシを維持するための工夫について紹介します。 広告がどこに表示されるか まずは、メルカリAdsが実際にお客さまの目にどのように触れるのかを見てみましょう。この記事では、広告配信の仕組みそのものにスポットを当てていますが、こうした広告がメルカリアプリ内のどこに表示されるのかを具体的に知ることで、その仕組みをより身近に感じてもらえるかと思います。 メルカリAdsは、以下のような場所に表示される仕組みになっています。 検索結果画面 お客さまが検索したキーワードに関連する広告が、検索結果リストの上部や一定間隔ごとに表示されます。 検索体験を邪魔しないよう、通常の商品リストと自然に馴染むようにデザインされています。 商品詳細ページ 「この商品を見ている人におすすめ」ブロック内に、関連性の高い広告が表示されます。 閲覧中の商品や検索履歴などをもとに、興味を持ちそうな商品を提示しています。 メルカリアプリでは、このようにお客さまの操作や閲覧内容に合わせて、自然に広告が挿入されるように設計されています。 メルカリAdsの広告配信の仕組み ここからは、メルカリAdsで広告がどのように選ばれ、短時間で返却されているのかを紹介します。 まずは中核となる AdServer を軸に「広告が返ってくるまでの流れ」を見ていきます。 広告リクエストの開始 検索操作やページ遷移などをきっかけに、広告を表示するための通信が AdServer に送信されます。 広告枠の位置、検索キーワード、閲覧中の商品情報など、表示に必要な情報がここに含まれます。 AdServer の役割:最適な広告を選ぶ司令塔 AdServer は、広告配信フローにおける 中心的な役割を担うサーバー です。 操作に応じて送られた広告リクエストを受け取り、「このお客さまには今どの広告を出すべきか?」を判断します。 そのために、AdServer は裏側にある複数のサービスに問い合わせて「広告候補」を収集します。 収集された候補は、ターゲティング条件・配信設定・予算状況などにもとづいてフィルタリングされ、最終的にユーザーに適した少数の広告が選ばれて返却されます。 表示位置に合わせた広告の返却 検索結果画面では、広告の位置や頻度は画面や文脈に応じて細かく制御されています。 選ばれた広告は、その時点の仕様に基づき、適切な位置としてクライアントに返されます。 高速な広告配信を支える仕組み ここからは、メルカリAdsの広告配信が「なぜこれだけ複雑なのに高速なのか」を紹介します。 広告リクエストが AdServer に届くと、最適な広告を選ぶために複数の内部サービスと連携して処理が進みます。 このように重い処理ですが、実際には 多くの工夫によって数百ミリ秒で完了するように最適化されています。 数百ミリ秒、つまり0.数秒です。まばたき1回分の時間ですね。 この短い時間で、多数のサービスが連携し、広告が選ばれて返却されます。 多数の広告候補生成ロジックを"並列"で動かす AdServer の裏側では、用途ごとに分かれた「広告候補生成サービス」が 複数存在しています(この仕組みを社内では「Demand」と呼んでいます)。 なぜ複数のサービスに分かれているのでしょうか? それは、広告を探す「手がかり」が状況によって異なるからです。 たとえば、以下のようにそれぞれの広告製品ごとに専用の候補生成ロジックが動いています。 Product Ads(商品広告) : 広告主が商品データフィードを連携することで、多品目を効率的に広告配信できる製品 システム側では、メルカリの商品データベースと連携して広告候補を探索 Infeed Ads(インフィード広告) : 広告主が画像やテキストクリエイティブを入稿して配信する製品 ユーザーのデモグラフィック情報を用いたターゲティング配信が可能 システム側では、MLモデルを使って、ユーザーの興味に合った広告を推薦 Shops Ads(メルカリShops広告) : メルカリShopsの店舗向けに特化した広告製品 ショップ商品を効果的にプロモーション C2C Ads(メルカリC2C広告) : メルカリの個人間取引(フリマ出品)を対象とした広告 これらのサービスは、AdServer のリクエストを受けて すべて並列に処理を開始し、広告候補を生成します。 そして異なる広告抽出ロジックを持った各Demandを複数のmicroserviceに分割し、AdServerから並列で呼び出すことで、短時間で大量の広告候補を抽出することを実現しています。 配信設定や予算チェックの最適化 広告配信では広告を出稿している広告主が、配信の上限予算や期間を設定できます。AdServerで広告を返却する前に、これらが有効かどうか確認する必要があります。 ここで重要なのが、データの性質による使い分けです。 配信設定(ON/OFF) → 頻繁には変わらないデータ → キャッシュ(一度取得した情報を保存)を使って高速化 予算残高 → 刻一刻と変化するデータ → 毎回リアルタイムで確認(ただし、タイムアウト時は柔軟に対応) つまり、「変化の速度」に応じて最適な取得方法を選んでいるわけです。 重い判断処理であっても、データの性質に応じて最適な取得方法を使い分けることで、レイテンシを最小限に抑えています。 AIによる最終的な並び替え レスポンスを返す直前には、AIによるスコアリングによって広告を「どの順序で表示するか」を最適化します。 ここでも軽量なモデルやキャッシュが利用され、処理の高速化が図られています。 表示に必要な情報の組み立て 最終的なレスポンスを返すために、広告として表示するタイトル・画像などの詳細情報を取得し、クライアントがそのまま描画できる形に整えます。 ここでもキャッシュの活用によって、追加の遅延を抑えています。 まとめ 本記事では、メルカリAdsにおける広告配信の仕組みを紹介しました。 メルカリAdsが高速に動作しているのは、次のような設計思想のもと、複数のサービスが連携しているためです。 用途別に分かれた複数の広告候補生成ロジックを並列で呼び出せる構造 重い処理を複数のサービスに分散し、AdServer が統合して返すアーキテクチャ 配信設定・商品情報など、頻繁に参照されるデータはキャッシュ前提で高速化 予算情報はリアルタイム取得で正確性を保ちつつ、タイムアウト時は柔軟に対応 AIスコアリングも軽量化・キャッシュにより遅延を抑制 これらの工夫により、検索結果が表示されるころには最適な広告が数百ミリ秒以内に返却されているという体験が実現されています。 日々の開発を通してこの仕組みを理解していく中で、システムの設計思想や高速化の工夫に触れられたのは貴重な経験でした。 今後もメルカリAdsは進化を続けていくと思います。 この記事が、メルカリAdsの仕組みに興味を持つきっかけになればうれしいです。 最後までお読みいただき、ありがとうございました。 明日の記事は @ogataka50さんです。引き続きお楽しみください。
アバター
こんにちは。メルペイ Manager of Managers の @abcdefuji です。 この記事は、 Merpay & Mercoin Advent Calendar 2025 の14日目の記事です。 アドベントカレンダー内のn8nの連載企画の最終日です。 本記事では、メルカリにおける n8n Enterprise 導入の PoC(Proof of Concept)をどのように成功させたか を紹介します。 近年、生成 AI の爆発的な普及により、企業内には日々膨大な AI ツールが流れ込んでいます。コード生成、文章要約、データ連携、AI エージェント、自動化、その他 毎日どこかで新しいツールが誕生し利用されている状態 です。 この状況が生む課題はシンプルであり、深刻です。 PoC ツールが乱立する 情報アップデートに追いつけず、すべてを触り切る余裕がない PoC を始めても Adoption(定着)が進まない 評価するチームも、本業と並行では十分にリソースを割けない こうした課題は、多くの企業で共通しているはずです。 メルカリでもn8n の PoC は、このような“AIツールが溢れすぎる時代”の中で始まりました。 その中で、どのように導入まで至ったのか。 最初に結論を言うと n8n PoC の成功に必要だったのは、技術そのものではなく、“組織として AI をどう扱い、どう広げていくかを PoC で学んでいく姿勢” でした。 これは、ツールの良し悪しを評価する PoC ではなく、 “AIツールを組織に根づかせる方法を見つけるための PoC” だったのだと思います。 1. PoC を始める前に見えていた背景 メルカリでは、社内から100名を越えるメンバーが選出された横断組織「AI Task Force」 によって 約4,000の業務プロセスが可視化 されています。 その多くは AI や自動化によって効率化できる余地がありました。 AI Task Forceの詳細は下記の記事をご確認ください。 メルカリが本気で始めた「AI-Native」化。100名規模のタスクフォースが立ち上がるまで 「AI Task Force」で変化を加速する。CTO @kimurasが描くメルカリの成長戦略 しかし現場には次のような課題があり、どの組織でも PoC が途中で止まってしまう理由にもなっています。 部署によって使うツールがまったく違う 非エンジニアが参加しづらい セキュリティ観点の懸念が大きい PoC の担当者には本業があり、専念できない このままでは自動化が前に進みません。 そこで私たちは、組織全体の“共通基盤”となる自動化プラットフォームとして、n8n の PoC を開始しました。 2. PoC が始まってすぐに見えてきた“勢い” n8n を試した初期段階から、複数チームで自然にワークフローが作られはじめました。 気づくと次のような利用データが観測されていました metrics value 週あたりの実行数 約 13,000 回 月あたりの実行数 約 40,000 回 PoC の段階にも関わらず、すでに “実務の中に入り始めている” という手応えがありました。 ただし、数字だけで PoC がうまくいったわけではありません。 ここからは、 どのように PoC を設計し、実行したか の話になります。 3. PoC の最初の一歩は「とにかく触ること」 PoC の企画書を書くよりも先にやったことは、ただひたすら n8n を触る ことでした。 UI の特徴 JSON 構造がどう見えるか どこまで柔軟に作れるか LLM との相性 非エンジニアがつまずきそうなポイント これらは、仕様を読むだけでは分かりません。 自分で触ってみて初めて、ツールが“どう現場にハマるか”が見えてきます。 PoC 担当者が誰よりも詳しくなることで、現場と同じ目線で話せるようになります。 これが後の推進力につながりました。 4. n8n PoC は“やる気のある仲間探し”でもあった 実際に PoC を動かし始めて感じたのは、 PoC の成否はツールよりも人で決まる ということでした。 今回のコアメンバーは以下の通りです: abcdefuji(Backend Manager) :PoC 推進、ユースケース伴走 (当ブログ) hi120ki(AI Security) :脅威モデル、ガードレール設計 shuuk(AI Task Force) :全社プロセスとAdoptionの橋渡し ISSA(Director) :DevEx の視点での全体整理 理想の Workflow Platform という“聖杯”に、n8n でついに手が届くかもしれない | メルカリエンジニアリング mewuto(Backend Eng) :静的解析 CLI(DAG / AST) n8nの静的解析CLIツールをOSS化 – JSON解析とDAGで実現するセキュリティチェックの自動化 | メルカリエンジニアリング T(SRE) :Enterprise 構成、Enginerringの全て Making n8n Enterprise-Ready: 企業向けn8nの導入と運用の取り組み | メルカリエンジニアリング 全員、 本業がありながら隙間時間で参加していました 。 にもかかわらず PoC が成立したのは、全員に共通して 「これはメルカリ全体にとって価値がある」 という強い思いがあったからです。 PoC は仲間が多いほど強くなります。 そして熱量は伝播します。 n8n の PoC はまさにその象徴でした。 5. 小さな成功を一緒につくる:ユースケース伴走 PoC を成功に導くためには、 早い段階で小さな成功を複数つくること が重要です。 n8n の PoC では、Marketing・QA・SRE・監査・HR などのチームに伴走し、次のような改善が生まれました: 部署 ユースケース 効果 Marketing KPI チェックの自動化 月 500 分削減 QA リリース作業の自動化 90 分/週 → 0 分 Eng AI Agent 開発工数削減 2 週間 → 2〜3 日 Audit 情報集約の効率化 属人性を大幅に改善 ここで重要なのは、PoC チームが「代わりに作ってあげる」のではなく、 一緒にワークフローを作り、一緒に成功する という姿勢でした。利用者がわからない時にサポートを行う。これは Adoption を加速する最も強力な手法です。 6. セキュリティとガバナンス:PoC で課題が出るほど良い n8n は自由度が高い分、いくつかのリスクもあります。 PoC のなかで実際に以下のような問題が見つかりました: credential の誤設定 HTTP Node での不正なアクセス 権限混同によるリスク Code Node 内の危険な処理 しかし、これはむしろ好材料です。 PoC は問題を見つけるための場所 です。ここで検知できれば、本番導入では安全に運用できます。 PoC 中に次の仕組みを整備しました: External Hook による保存前チェック 静的解析 CLI(JSON / DAG / AST) SSO(Okta) Task Runner によるコード実行の隔離 ガイドライン・テンプレート こうして、導入時に必要な安全性が PoC のなかで自然と整っていきました。 詳細はこちら Making n8n Enterprise-Ready: 企業向けn8nの導入と運用の取り組み | メルカリエンジニアリング n8nの静的解析CLIツールをOSS化 – JSON解析とDAGで実現するセキュリティチェックの自動化 | メルカリエンジニアリング 理想の Workflow Platform という“聖杯”に、n8n でついに手が届くかもしれない | メルカリエンジニアリング 7. 「ROI は罠」 ── 短期回収で PoC を評価してはいけない PoC ではよく ROI が議論されますが、短期回収だけで判断すると誤った評価になりがちです。 AI や自動化は 「導入しない」 という選択肢のほうが損をする 世界に入っています。 参考: “BoldなAI活用”から1年。人間の限界を超えていく、メルカリの「AI-Native」な現在地 そのため私たちは、次のような前提で PoC を進めました: 導入するかどうか、ではなく、どう導入すれば成功するかだけを議論する。 数字の比較は必要ですが、まず見るべきは “成果ベースの数字” です。 再現性のある成功事例がどれだけあるか 非エンジニアでも価値を出せているか エラー削減、工数削減の実績 全社展開できる安全性があるか これらが確認できて初めて、年間コストや ROI 試算の意味が出てきます。 また、n8nにはEstimated time saved機能があります。 1 workflow毎にどの程度時間を削減できたかの見積もりを設定する機能です。 設定後、以下のようにDashboardから各Workflowで設定された削減時間を確認することができます。 中長期的にはこのようにn8nの効果測定をすることも可能です。 8. Adoption戦略:広げるには“雰囲気”も必要 PoC の後半では、次のような活動をして Adoption を広げていきました。 All Hands や社内勉強会で紹介 Slack チャンネルで成功事例を共有 非エンジニア向けテンプレートの提供 質問にはすぐ返す文化づくり 気づけば、周囲の人たちが 「ちょっと n8n 触ってみるね」 と自然に言うようになっていました。 ツールが広がるには“雰囲気づくり”もとても大事です。 9. PoC を成功に導く“再現可能な型” 最後に、今回の PoC から得られた成功パターンをまとめます。 まず自分が一番触る 効率より熱量のある仲間を見つける 小さな成功を早くつくる PoC 中に課題を見つけ、仕組みとして解決する ROI よりも成果ベースの数字を見る テンプレート・ガードレールで安全に広げる Adoption を広げる雰囲気をつくる PoC担当者の覚悟 これらは n8n に限らず、AI ツール全般の導入で応用できる考え方です。 PoC担当者には”覚悟”が必要です。達成するべきVisionを信じきる覚悟です。自身がなぜ必要・有効なのかのロジックを持ち、そしてそれを信じて突き進んでください。 おわりに n8n PoC を振り返ると、成功を分けたのは技術だけではありませんでした。 本業の合間に動きながら、皆でアイデアを出し合い、問題を潰し、成功を積み重ねていく。 その“姿勢”そのものが PoC の最大の価値であり、組織が AI を受け入れる力につながりました。 PoC はツールのテストではなく、 組織が AI をどう扱うかを学ぶフェーズ です。 これからも改善を続けながら、AI-Native な組織を目指して進んでいきます。 またどこかでメルカリがどのようなworkflowを構築し活用しているのか紹介できたらと思います。ここまで読んでいただきありがとうございました。 明日の記事は Timoさんです。引き続きお楽しみください。 n8n.io logo source: https://n8n.io/brandguidelines
アバター