Cross Border(XB) EngineeringでArchitect兼SREをしている yanolab です。 ブログシリーズ初日では、 グローバル展開にむけた基盤の再構築 としてメルカリにおける取り組みの遷移の紹介がありましたが、本記事ではグローバル展開を支える基盤の裏側と題して、バックエンドシステムのアーキテクチャーやフレームワーク、取り組みなどを少し掘り下げて紹介したいと思います。 Background メルカリにおいては長らくMicroserviceアーキテクチャを採用して運用し、そのエコシステムにも投資をしてきました。echoサービスと呼ばれるMicroserviceのテンプレートや、GoでMicroserviceの開発を行うためのSDK、基本的なインフラ関係の設定をまとめたスターターキットと呼ばれるTerraformのモジュール、Kubernetesの設定を抽象化し、少ない記述でDeploymentを管理できるSDKなどがあります。また、Microserviceのリリースに際してはProduction Readiness Check(PRC)と呼ばれるプロセスがあり、新しく開発されたプロダクトやMicroserviceはこのチェックリストに合格する必要があります。これらのエコシステムやプロセスは成熟してきたものの、複雑化したエコシステムは学習コストを高め、肥大化したPRCによって、1つのMicroserviceを立ち上げるのには最低でも3ヶ月かかるようになってしまっていました。また、新しくビジネスを立ち上げる際は構築初期の人数は少ないにもかかわらず、数十のMicroserviceを立ち上げなければならない場合が多く、そのような場合においてMicroservice数×3ヶ月という工数は現実的ではなく、直近のメルカリの新規ビジネスはMonolith的なアプローチを採用することが多くなってきています。(ref: メルカリ ハロの技術スタックとその選定理由 ) グローバル展開にむけた基盤の再構築においては将来的に現在のメルカリMarketplaceと同じような規模になることが想定されるため、単純なMonolithではなく、既存のエコシステムを最大限活用しつつ、Microservice的な運用ができるような特殊なModular Monolithを設計し、運用しています。 分割して運用が可能なModular Monolith メルカリのMicroservicesを想定したエコシステムは1レポジトリ、1サービスが基本となっており、大規模かつ複雑な構成のシステムは想定されていません。例えばCI/CDでは1バイナリ、1コンテナ、1Deploymentを想定しています。このような環境から逸脱する場合、システムの実装側で独自にワークフローを作成しメンテナンスを行う必要があります。Cross Borderチームでは独自でメンテナンスし続けるコストを回避するため、この方針に従いつつ、将来のビジネスの成長に伴う運用負荷の分散のため、Microservice的な運用ができるようにシステムを一つのバイナリにコンパイルするが、設定ファイルでモジュールの有効・無効を切り替えられるようにしています。また、モジュール間のインタフェースはProtocol Bufferで定義し、その通信はgRPCを利用するようにすることで、同じインスタンス内の通信にとらわれず、運用の自由度を高めています。これによって、1バイナリ、1コンテナとして既存のCIビルドシステムを利用しつつ、設定ファイルでモジュールをオン・オフしたり、モジュール間の通信相手を任意に設定したMicroservices的な運用を可能にしています。また、モジュール間のインターフェースをProtocol Bufferにしたことで、モジュールの独立性を高めつつモジュールのインタフェースの設計からチームで連携しながらモジュールの開発を行えるようになっています。(Fig. 1) Fig.1 Modular Monolith with Flexible Deployments 新基盤のデータベースにはAlloyDBを用いています。過去のメルカリのMonolithにおいては、システム全体で共有のデータベースを用いており、ドメインごとのテーブルの連結や権限に制限はありませんでした。そのため、サービスが成長するにつれてドメイン間の依存度は高まり、運用コストは増大していきました。それに対してMicroserviceへ移行した際には多くのサービスやチームで、SpannerやCloudSQLが採用されてきました。サービス毎に独自にデータベースを持ってチームで運用することは、ドメインやサービスの独立性が高く、オーナーシップやメンテナンスの面でとても優れている選択でした。しかし、それぞれのチームで独自にデータベースを持ち、少ないリクエストでも安定運用のためにHA構成としなければならないということはコストの面から見ると非効率で、リクエストの少ないサービスでは特にコスト的に無駄が多い状態となっていました。そこで、Cross Borderチームでは、コスト節約のためなるべく同じクラスタを利用するが、モジュールごとにサービスアカウントを分けアクセスできるデータベースを制限し、データベースもモジュール単位で分割することとしました。これによって、コストを抑えつつ将来の分割やスケールに備えています。(Fig. 2) Fig.2 DB Isolation 従来、メルカリではMicroserviceの設定を環境変数にて行ってきましたが、Monolithになった場合は設定が非常に多くなり、環境ごとの設定の管理なども煩雑になってしまうことが予想されました。そこで、設定ファイルには CUE lang を採用し、デフォルトの設定をシングルソースで管理できるようにし、開発環境や本番環境など、環境ごとに違う値のみを差分管理できるようにしています。これらの設定ファイルはコンテナのビルド時にコンテナに同梱され、環境に応じて、ローカル環境であればローカル用の設定、開発環境・本番環境であればそれに応じた設定が自動的に使われるようになっています。また、実行時にCUE/YAMLで標準の設定を上書きをできるようにすることで、Deploymentごとに違う設定を行うことも可能にしています。(Fig. 3) Fig. 3 Difference management of config 例えば開発環境と本番環境の標準の設定を標準のコンフィグとして下記(Fig. 4)のように定義します。この場合、ProductモジュールのProductInventoryアプリケーションはSearchモジュ ールのアドレスとしてlocalhostを利用します。 #GRPCClientConfigSpec: { address: string | *"localhost:\(#HTTPPort)" timeout: =~"^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" | int | *"3s" retry: int & >=0 | *3 } components: "layers/tire2/product/applications/productinventory": enabled: bool | *false search_module: #GRPCClientConfigSpec "layers/tire3/search/applications/productsearch": enabled: bool | *false ... Fig. 4 Common part of development and production 開発環境の共通の設定を下記(Fig. 5)のように定義したとします。この場合、開発環境の一部であるGKEの環境でも、ローカル環境でも全ての機能が有効となり、すべてのモジュールはローカルホストのモジュールを利用します。 components: "layers/tire2/product/application/productinventory": enable: true "layers/tire3/search/applications/productsearch": enabled: true ... Fig. 5 Development specific configuration(Enabled all of modules) 本番環境でGKEのDeploymentを分ける場合は、コンテナに同梱しているものとは別にConfigMapをYAMLとしてマウントし、これを読み込ませます。例えばDeploymentAのProductモジュールのInventoryアプリケーションの接続先をDeploymentBとし(Fig. 6)、DeploymentBではSearchモジュールのProductSearchアプリケーションのみを有効にする(Fig. 7)ことでSearchモジュールのみを独立して運用することが可能となっています。 components: "layers/tire2/product/applications/productinventory": enable: true search_module: address: deploymentB.xxxx.svc.local "layers/tire3/search/applications/productsearch": enable: false ... Fig. 6 The Search module used by the Product module can be switched to a different Deployment components: "layers/tire2/product/applications/productinventory": enable: false "layers/tire3/search/applications/productsearch": enable: true ... Fig. 7 Deployment with only the Search module enabled これらの柔軟なアーキテクチャはローカル開発、開発環境ではシングルバイナリで運用し、本番環境においては適切な単位でモジュールを切り分け運用を行うことを可能にしています。これは特にローカル開発において非常に強力で、Microserviceの開発時の課題である、依存するMicroserviceを含めた実行環境を用意する必要がなくなり、開発環境の構築とメンテナンス効率を劇的に向上することができます。ただし、今回の基盤再構築においては、すべてのMicroservicesを置き換えるわけではなく、現存するメルカリのMicroservicesへの依存も存在しています。これらの依存関係に対応するために mirrord というプロダクトを用いて、ローカル環境からリモートのKubernetes環境に繋いで開発を行っています。また、 air というプロダクトも利用しており、変更の動的リロードができるようになっており、Webアプリを開発するようなモダンな開発環境を実現しています。 モノレポによる変化への対応 メルカリのMicroserviceではサービス毎にレポジトリを作成し、Protocol Bufferの定義、Terraformを用いたインフラストラクチャの管理やKubernetesへのデプロイ環境のレポジトリのみ、それぞれ全員が共有するモノレポとして運用しています。このアプローチは有効ですが、メインで利用するレポジトリと異なっていることで、レポジトリ間を移動する必要があります。このコンテキストスイッチが頻繁に発生することは開発者にとって非常にストレスとなります。また、レポジトリをまたいだ自動化は、個別に動作するCIによって処理時間が長くなるだけでなく、問題が発生した場合にどこで何が起きているかを把握することが難しく、開発者の体験を悪くする要因となっています。今回基盤再構築にあたり、これら開発者の体験を見直すため、この構成も見直し、Backendプロジェクト、Frontendプロジェクト、Protobufの定義やTerraformを一箇所に集めて、極力モノレポで開発が完結するような試みを行っています。(Kubernetesへのデプロイのみエコシステムの都合上既存のモノレポを利用しています。) Modular Monolithで境界を明確にしつつ、モノレポでBackendプロジェクトのみならずFrontendプロジェクトも管理することで、アプリケーションやアーキテクチャやフレームワークを揃えつつ、言語や役割を超えた貢献をしやすくしています。また、メンテナンスの面においても、スクリプト、Workflow、CIなど一箇所をメンテナンスすれば良く、メンテナンス効率が高いと考えています。メルカリでは長らく組織やチームの生産性を可視化できておらず、開発者の生産性を正確に測定する方法が課題となっていました。2024年より、開発者の生産性を可視化し、改善することを目的に DX を導入しています。DXではサーベイを用いた定性的データとGitHubなどの生産性に関わるメトリクスなどの定量データを合わせて、効率、スピード、品質、新規性の4点を可視化しています。モノレポを用いたアプローチはこれらの値でメルカリ全体のスコアよりも良い結果が出ていることがわかりました。 今回構築したモノレポにおいて少しユニークな点としては、インフラストラクチャの管理にTerraformとCUE langを用いているところです(従来通りtfフォーマットも利用可能です)。CIにてCUEからjsonに変換して適用しています。インフラストラクチャの定義をCUEにすることで、上で紹介したModular Monolithの設定管理のように差分を意識した環境構築が可能になります。CUEはYAMLやJSONとマージして利用することが可能なので、自動化の面で非常に有効だと感じています。今後、モノレポのすべてのデータが同じレポジトリにあるというメリットを活かして、Modular Monolithの設定やフレームワークから自動的にインフラストラクチャの構成ファイルを生成するFramework defined Infrastructureに取り組みたいという野望もあります。(Fig. 8) Fig. 8 Framework Defined Infrastructure 複雑化するドメインや依存関係に対するアプローチ 現在、メルカリにはMarketplace事業に関係するMicroserviceのみでおよそ250ほどのGCP Projectが存在しており、Merpayも含めると400近い数になります。これらのサービスは必要以上に細かく分割されていたり、相互に依存し合っていたりしてメンテナンスを困難にするだけでなく、新規に機能を作成しようと思ったときに、どのMicroserviceに機能を追加するべきか、またどのMicroserviceの機能を利用できるのか、そもそも新規にMicroserviceを作成するべきなのかなどの判断を非常に困難にしています。そこで、Cross Borderでは新規にMarketplaceの基盤を再構築するに当たって、Tierという概念と依存関係マップを導入しつつ、Likeサービスのように特定の機能にフォーカスし、小さく分けすぎたサービスをSocialモジュールにまとめるなど、ある程度まとまった大きめのドメインに再集約するなど、ドメインや役割を整理しながら進めてきました。 このTierコンセプトでは、BFF(Backend for Frontend)/Gateway、Tier 1、Tier 2、…Tier 4の5つの層に役割を分割し、それぞれの層の役割と制限を追加しました。 BFF/Gateway層 BFFはよく知られていますが、この層ではMobileやWeb画面に最適化したAPIを定義しすべてのリクエストはBFFを通してから下位の層へ送られます。お客さまに応じた言語の変換や通貨の変換もこちらの層で担当します。Mobileエンジニア、Webエンジニア、バックエンドエンジニアで共同で所有しメンテナンスを行っています。 Tier 1 主にリクエストオーケストレーションやビジネスフローを担当します。Tier 1の責任は、Tier 2以下のモジュールを使用してビジネスプロセスを構築することです。イメージとしてはMarketplaceの様々な機能を利用してプロセスを構築するので、水平方向の処理を担当する領域です。 Tier 2 主にMarketplaceのコアの機能を実現するドメイン特化の層になります。ProductモジュールやOrderモジュールなどが該当します。イメージとしては該当のドメインに特化した垂直方向の処理を担当する領域です。 Tier 3 基本的にMarketplaceに依存しないより汎用的な機能を提供する層になります。SearchやNotificationなどが該当します。 Tier 4 この層は少し特殊で、特定の特殊な要件を満たさなければならないモジュールや、Tier 1 〜 Tier 3に属することが難しい機能を提供する層になります。他のモジュールとは適用されるセキュリティーや運用要件などが異なる個人情報を専門で取り扱うモジュールをこの層に配置しています。 リクエストは常に上から下へと流れ、同じTier同士の通信は禁止するという制約を設けています。ただし、上位Tierから下位Tierにアクセスする場合、中間Tierは飛ばして良いというルールを設けており、BFFからNotificationへのアクセスは許容しています。(Fig. 9)データベースもモジュール単位で分かれており、モジュールをまたいでトランザクションを張るということもできません。これらのルールにより、モジュールの独立性が非常に高まるとともに小さなモジュールが乱立するといったことを防いでいます。もし、同じTier同士のモジュールの通信が必要になった場合、そのモジュール同士のドメインが非常に近しいことを意味し、ドメインの境界の見直しの良いシグナルとして捉えています。 Fig. 9 Tier Concept 基盤の再構築はまだまだ始まったばかりですが、PaymentやIdPといったまとまったドメインかつ、環境が安定しているサービス群を活用しつつ、このデザイン手法を用いてMarketplaceのドメインを再整理し実装することで、2025年10月の現時点で18モジュールに留めることができています。 現在の課題 現状ではモジュール単位でのデプロイを可能にするために、モジュールごとにバージョンをファイルで管理し、リリース時にはそのバージョンをインクリメントすることで、モジュールごとのバージョンアップを検知しています。しかし、この方法はmainブランチをリリース用とするGitHub Flowとは相性が悪く、意図しない変更がリリースに含まれてしまうおそれがあります。現在この問題を解決するために試行錯誤をしています。 今後の展開 AIによる開発が主流になってきている昨今、競争力確保のためには新規にビジネスを素早く立ち上げる必要があります。今回紹介したCross BorderチームのMonorepo、Modular Monolithアプローチは初期の構築コストがそれなりに高いため、メルカリの今後の新規ビジネスに適用できるようにPlatformチームと連携して、もっと簡単に素早く構築できるように挑戦中です。今後何処かで機会があれば、これらの結果をまた記事にしたいと思います。 最後に 2025年11月13日に、メルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます。こちらにもぜひお越しください! 参加登録はこちら 👉 https://gears.mercari.com/ 明日の記事は @Garyさんです。引き続き「 連載企画:メルカリ初の世界共通アプリ『メルカリ グローバルアプリ』の開発舞台裏 」をお楽しみください。
こんにちは!メルカリ Engineering Office の @mikichin です。 来る11月13日、メルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます! 2018年に実施した「Mercari Tech Conf 2018」から7年の時を経て、久しぶりのオフラインでの開催となります。 テーマは「メルカリエンジニアリングの今」。 今年の全社的なテーマでもある「AI-Native」についてはもちろん、2018年以降メルカリグループのエンジニアリングがどのように変化してきたかを、技術・組織・カルチャーの観点からご紹介します。 オンライン配信はありませんので、ぜひ会場でご自身の目と耳で確かめてください!! 会場は、メルカリのエンジニアリング組織における信念や行動の基盤となる共通認識を明文化した「Mercari Engineering Principles」をモチーフにした「PASSION Stage」「GROW Stage」「MECHANISM Stage」の3つのステージがあります。 本記事では、「PASSION Stage」のセッションをご紹介!「PASSION Stage」は同時通訳の提供があります。 まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちらから お願いします。 12:15 – 12:45 Keynote 13:00 – 13:20 Techniques for Reliable Code Generation Using AI Agents 今年、コードの書き方は大きな変化が見られました。コード変更は主にAIエージェントが行うようになり、私たち人間の仕事は全体的な調整や成果物の修正が中心となってきています。しかし大規模かつレガシーなコードベースを扱う場合、AIエージェントがどこまで自律的に作業できるかには明確な限界があります。プロジェクト全体の文脈を十分に理解できていない、ガイドラインが守られていないという理由から、生成されたコードはマージ前に大幅な手直しが必要となることも少なくありません。 本セッションでは、AIエージェントが自律的にコード変更を行えるように設定する方法について、特にマイグレーションや定型処理の多いコードを扱う場面で有効なテクニックを紹介します。 13:30 – 13:50 AIの礎 ——プロダクトを支える、目に見えない力をつくる。 「見た目が似た商品」から始まった画像埋め込みの小さな実験は、やがて“Embeddings”革命へと発展し、メルカリのプロダクト、カルチャー、そしてビジネスに大きな変革をもたらしました。本講演では、その歩みを振り返りながら、画像検索からAI Listing、セマンティック検索に至るまで、埋め込み技術がいかにブレークスルーを実現してきたのかを紐解きます。また、プロトタイプから堅牢なインフラへと拡張していく過程で直面した課題や、そこから得られた学びについてもご紹介します。 14:15 – 14:55 Building Foundation for Mercari’s Global Expansion メルカリは創業当時よりグローバルなマーケットプレイスを実現することをビジョンとして掲げてきました。これまでの挑戦から得られた学びや反省を踏まえ、現在は“Global One Product”というよりグローバルへの展開を加速させるための新たな共通基盤の構築に取り組んでいます。本セッションではなぜこのアプローチに至ったのか、どのようなアーキテクチャや実装で支えているのか、組織的なチャレンジと技術の両面から詳しく紹介します。複数リージョン展開における開発・運用上のチャレンジや、組織横断での意思決定の工夫についても共有します。 15:15 – 15:35 メルカリにおけるフィッシング対策の軌跡と未来 フィッシング攻撃は進化を続け、サービスやユーザーを狙う手口は年々巧妙化しています。メルカリでも、その進化に対抗するために多様な防御策を講じてきました。そしてパスキー導入を契機に、戦いの焦点は大きく変わり、「いかにフィッシングを防ぐか」から、「いかに守れるユーザーや機能を広げるか」、「いかに強固でありながらUXを損なわない認証体験を実現するか」へとシフトしてきました。本セッションでは、攻撃手法の変遷と、それに呼応して発展してきたフィッシング対策や認証・リカバリー施策の歩みを振り返ります。 16:00 – 16:40 The Future of Platform in the Age of AI 本セッションでは、私たちが現在AIを社内でどのように活用しているか、社内のエンジニアリング組織のニーズがどのように進化すると考えられるか、そしてAIエージェントを正規のユーザーとしてサポートできるプラットフォーム構築とは何なのかについてお話しします。 AI時代におけるプラットフォームエンジニアリングの姿や、今後3年から5年の間に取るべき大胆な一手について一緒に探っていきましょう。 17:00 – 17:40 Backend Standardization with MCP 他のチームのサービスを理解するのに頭を抱えたことはありませんか?各チームがそれぞれ異なるコード構造を使っていたり、部門ごとに分断されていたりして、作業がなかなか進まない。そんな状況をAIとModel Context Protocol (MCP) でどう変えられるのかをご紹介します。本セッションではまずMCPとは何かを説明し、なぜこれが社内のバックエンド開発を標準化し、投資対効果(ROI)を高める「ゲームチェンジャー」になり得るのかをお話しします。その後、実際にMCPが動くデモをご覧いただき、現在直面している課題や今後の設計の可能性についても探っていきます。 「mercari GEARS 2025」のお申し込みは こちらから 。 イベント詳細 開催日時: 2025年11月13日(木) 11:00-18:00 概要: mercari GEARS 2025は、メルカリグループのエンジニアリング組織の技術への挑戦と、カルチャーを体感する技術イベントです。 本イベントは、単なる情報伝達の場ではなく、エンジニアたちが出会い、経験を共有し、交流を通じて新たな機会が生み出されることを目的としています。 参加費:無料 会場:TODA HALL & CONFERENCE TOKYO 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @MercariGears でお知らせしますので、気になる方はぜひフォローをお願いします。
自己紹介 こんにちは、@KiKiと申します。今年9月に1ヶ月間、メルカリのインターンに参加させていただきました。 大学では情報系を専攻していて、大学の授業ではハードウェアからアプリケーションに至るまで幅広い分野について学んでいます。 今回のメルカリのインターンは自分にとって初めて参加するインターンでしたが、多くのことを学びながら大きく成長することができたと感じています。本記事では実際にインターンで取り組んだ内容と学んだことをご紹介できればと思います。どうぞよろしくお願いいたします。 参加したインターンについて 私が今回参加したのは「Build@Mercari」というプログラムの一部であるインターンシップです。 なお、Build@Mercariのプログラム自体の詳しい内容については、他の記事でとても詳しく紹介されていますので、そちらをご覧ください。 https://careers.mercari.com/mercan/articles/40098/ どうしてBuildインターンに申し込んだのか 一般的なインターンに応募する際、技術要件や事前知識の高さにハードルを感じる方も多いのではないでしょうか。特に、情報系を専攻していない方はもちろん、専攻している方でも、インターンの応募時に求められる技術要件や知識に不安を感じることはあるかもしれません。 大学では、アルゴリズムやハードウェア、OSの基本原理など基礎的な内容が中心で、Webアプリケーション開発などの実践的なスキルを学ぶ機会は限られることもあります。 私自身、フロントエンドやバックエンドといったWeb関連技術は全くの未経験で、「どこから始めればいいのかわからない」と感じていました。そんな中、STEM分野・IT分野におけるマイノリティである女性や、LGBT+コミュニティの方を対象にトレーニングとインターンシップの機会を提供する「Build@Mercari」というオンラインプログラムを知りました。 このプログラムは「Web関連技術の知識は全くないけれど、この業界に興味がある!」という気持ちひとつで応募できる懐の深さが魅力でした。「これなら私にも挑戦できるかもしれない」と思い、思い切って応募することにしました。 配属されたチームについて 私が配属されたのは「Contact Center」という、メルカリでのお問い合わせ対応をサポートする社内システムを開発しているチームです。 現在、メルカリのお問い合わせ対応は、お客さまがフォームからお問い合わせし、お客さまからいただいたお問い合わせ内容などの情報を元にCS(カスタマーサービス)オペレーターが対応する、という流れになっています。ただし、このCSオペレーションではお問い合わせの解決までに時間がかかりすぎる、という課題がありました。 このチームではそういったCSオペレーションを抜本的に再構築するプロジェクトを進めていました。具体的には、お客さまのお問い合わせにリアルタイムでBotが対応し、Botで解決が難しい場合は、有人チャットを通じてCSオペレーターが対応にあたる、という方式への移行を目指しています。インターン期間中は、この新しいチャット体験への移行を進めているフェーズだったので、メルカリの未来のCS体験を支える重要な仕組みに関われるのは、とても魅力的なポイントでした。 実際に取り組んだ内容 プロダクトに関わる業務は大きく分けて、バックエンドとフロントエンドに分かれます。 バックエンドはサーバー側やデータベースの処理を担い、フロントエンドはユーザーに直接触れる画面や操作部分を担当します。今回私は、バックエンドとフロントエンドのタスクを1つずつ担当させていただきました。 バックエンド開発 使用した言語・ツール 言語: Go, SQL ツール: GCP, Spanner, Kubernetes, BigQuery, Spinnaker, yo 背景 お問い合わせ対応システムの開発を進める中で、会話履歴や関連データに紐づく識別情報をスムーズに取得することが、調査や分析作業を円滑に進める上での課題となっていました。 このチャットのシステムは、GCPのサービスを使った実装になっています。個々のチャットを特定するためのIDは連携・保存していましたが、ConversationIDと呼ばれる、Botが会話したIDはそれとは異なるIDとなっており、これはシステム上では保存していませんでした。 そのため、これまでの運用では、対象となる会話データから、ConversationIDを取得するまでに、複数の手順を踏む必要がありました。例えば、会話の記録から情報を一つひとつ検索したうえで、目的のデータを特定するといったプロセスが発生します。このような手間は、迅速な問題解決が求められる場面では特に大きな障壁となっていました。 実装したこと こうした課題を解決するため、ConversationIDを自動的に収集・格納する仕組みを検討しました。具体的には、会話終了時に必要なデータを自動的に取得し、これまでテーブルに保存していなかったConversationIDも、会話終了時にテーブルへそのまま保存するように変更しました。この仕組みを活用することで、調査プロセスを大幅に簡略化し、より効率的な対応を目指しました。 結果 その結果、インターンの期間を通して、メンターさんをはじめとしたチームの方の助力もいただき、この仕組みを実際のシステムに反映させることができました。現場では「調査の高速化に役立っている」といった声もいただいており、自分が関わった仕組みが実際に使われていると実感でき、とても嬉しく感じています。この経験を通じて、開発したものが誰かの作業を少しでも助けられることのやりがいを改めて感じました。 フロントエンド開発 使用した言語・ツール 言語: TypeScript, GraphQL ツール: Ant Design 背景 お問い合わせに関する情報にお客さまのメールアドレスが登録されていない場合、そのお問い合わせにはダミーのメールアドレスが登録されます。ただしそのような場合でも、CSオペレーターが操作する画面上には、「お客様のメールアドレス宛にメッセージを送信するボタン」が表示されていました。 しかし、有効なメールアドレスではないため、このボタンを押してもメールの送信は実行されません。それにもかかわらず、CSオペレーターの画面上にはその旨が表示されないため、メール送信が完了したという誤認識を招く可能性があるUIとなっていました。 実装したこと この問題を解決するため、ダミーのメールアドレスが設定されている場合に送信ボタンが押されたら、エラーメッセージをモーダルで表示する処理を追加しました。 この実装を行うために、送信先メールアドレスの情報を取得できるように、データ取得クエリの一部を変更しました。この変更により、画面初期読み込み時に必要な情報が整う仕様に改めました。 結果 画面上にエラーメッセージが正しく表示されることを確認できました。これにより、CSオペレーターが誤認識をするリスクが減少し、日々の業務をより正確に進めることに役立つ改善が実現しました。 チーム開発ならではの学び プライベートの個人開発では、自分の思いつくままに自由に実装することが多いかと思います。しかし、個人では達成が難しい大きな目標も、チームであれば実現できることがあります。一人では膨大な時間と労力がかかる作業も、チームで取り組むことで、それぞれの得意分野を活かし、知識やスキルを共有しながら効率よく進めることができます。 さらに、チーム開発では単なる作業の分担にとどまらず、互いにフィードバックを与え合うことでプロダクトの可能性を広げていきます。 今回のインターンは、私にとって初めて「お仕事でのチーム開発」や「大規模な開発」に触れる機会となりました。私がここで得た学びを、次にご紹介します。 プロダクトへの携わり方は業種によってさまざま 今回、Contact Centerチームに配属させていただき、チームの方々にサポートしていただいたり、働く様子を間近で見る中で、チームメンバーそれぞれの役割や業務内容について理解を深めることができました。 私が今回のインターンにおいては、以下のようなポジションの方と関わりがありました。 Product Manager プロダクトを使うお客さま(私達の場合Customer Serviceのメンバー)からのニーズを取りまとめて、最適な形で実装できるように仕様を決定する役割です。今回のインターンでは、フロントエンドの実装を行う際、エラーメッセージの内容やデザインについて相談させていただきました。 Engineering Manager エンジニアの意見をチームやプロジェクトに反映させるため、多くの会議に出席し関係者と調整を行ったり、他のエンジニアが意思決定に迷った際に相談に乗るのが主な役割です。また、チームのエンジニア一人ひとりと毎週1on1を行い、困りごとや課題に耳を傾けるなど、コードを書くこと以外にもチームメンバーとのコミュニケーションを重視している印象を受けました。 私もインターン期間中に何度か1on1を設定していただき、直接お話をする機会がありました。 Frontend Engineer フロントエンドエンジニアはユーザーが直接目に見える部分を実装するエンジニアです。チームでの会議の際に、実装が出来上がった部分を紹介する時間があるのですが、フロントエンドのデモンストレーションは華があって見応えがあるので、いつも私も楽しみにしていました。 Backend Engineer フロントエンドエンジニアとは逆に、表からは見えない部分を担当するエンジニアです。プロダクトの機能のに関わる裏側の処理を行うことができるという点が魅力です。適切なデータ構造やAPIの決定、システムのパフォーマンスに関わる仕事もできるのが個人的に面白いと考えています。縁の下の力持ちという印象です。 開発の流れ チーム開発では、メンバーと協力して働くからこそ、個人開発にはないステップが必要になります。 ここでは、そのリリースまでの流れを簡単にご紹介します。 Planning (何をするか決める) 解決すべき課題と作るものを明確にする段階です。Product Managerの方を中心に議論し、作業の方向性を定めます。 Spec作成 / チケット起票 Planningで決まった内容をもとに、仕様を具体化し、タスク管理ツールに登録します。この時点でレビューを一度受けることもあります。 Technical Spec / 詳細設計 技術的な詳細設計を行い、データの流れやAPI選定など、具体的な実装内容を詰めていきます。今回のインターンでは、チームの方がすでにチケット起票までを終えてくださっていたため、詳細設計の作成から作業を引き継ぎました。 開発 設計に基づいてコードを実装します。 Pull Request(PR)作成 GitHub上でコードを共有し、実装の意図やテスト内容を説明します。扱ったリポジトリでは同時に、PR作成時には自動的にCIツールが実行され、コードに対してlintや単体テスト(unit tests)が走る仕組みになっていました。 レビュー チームメンバーがコードの品質や設計の意図を確認します。レビューの結果次第では4の開発に戻ってコードを書き直し、再度レビューを受け、承認が得られるまで繰り返すことになります…。 リリース準備 環境設定や実行権限の取得を行い、開発用の環境でテストを経たうえで本番リリースに備えます。 リリース 完成したコードを本番環境にリリースし、ユーザーが利用できる状態にします。 大規模開発に向けた設計思想「Clean Architecture」について 今回、バックエンド開発で触ることになったリポジトリは、「Clean Architecture」に基づいて設計されていました。 コードの設計思想とは、特に大規模な開発において重要となる概念です。これは、「コードをどのように整理し、配置するか」を決める際に参考にするポリシーのことで、チーム全体での効率的な作業を支えます。たとえば、「このコードはここに置かれているに違いない」とチーム全員が共通認識を持てることで、開発効率が大きく向上します。 Clean Architectureでは、プログラムの役割や責任に応じてコードがレイヤーに分かれています。それぞれのレイヤーは、独立して役割を果たせるように設計されており、異なるレイヤー間の依存関係を最小限に抑えることが特徴です。この設計により、変更や拡張がしやすくなるという利点があります。 大規模開発に触れたことがなかった私にとって、コードの設計思想という概念に触れること自体、非常に大きな学びとなりました。 生成AIを用いた開発について メルカリでは積極的に業務に生成AIを導入しています。 今回のインターンを通じて、ソフトウェア開発の現場では「言語の文法を覚えてスラスラと書くだけがスキルではないんだ」と実感しました。生成AIの進化によって、コードを書く作業がかなり効率化されており、大規模なプロジェクトのコードを理解する際にも非常に有用だということを学びました。 一方で、それ以上に重要だと感じたのは、大規模な開発に適した設計思想や、将来的に仕様変更がしやすい設計、自分以外の人にも分かりやすいコードを書くことの大切さです。また、モジュール化やメンテナンス性を意識した開発の考え方が、現場では重視されていることを強く感じました。 これらの経験から、「知らない言語を使うプロジェクトだから…」と機会を逃すのは、少しもったいないと気付かされました。言語自体の知識は必要に応じて身につけていけばよく、現場で学べる設計や開発の考え方こそが、より長く自分の糧になり、生成AIに取って代わられることのない人材へと成長することにつながるのではないかと思います。 終わりに この記事では、私が初めてのインターンを通して学んださまざまなことについて、紹介させていただきました。 1ヶ月という期間はとても短く感じましたが、フルタイムで社員の方々に混ざって働き、たくさんお話をさせていただく中で、この記事には書ききれないほどの大きな学びを得ました。なにより、本当に楽しかったです。メンターをしてくださった Peranikov さんをはじめ、Contact Centerチームの皆様方、ありがとうございました。
Cross Border (XB) Engineeringの @deeeeeeeeeet です. 先日の事業戦略発表会において共有しましたが,今後更にメルカリの海外展開を加速させるためにグローバル版のメルカリアプリを先日リリースしました. このアプリは現在提供してる日本版・アメリカ版のメルカリとは異なる新しいアプリであり,またアプリだけではなくその裏側のバックエンド基盤も新たに再構築しています.本記事では,エンジニアリングの観点からメルカリ グローバルアプリ(以下、グローバルアプリ)とその基盤の戦略やアーキテクチャーをこれまでのメルカリの挑戦から得られた学びを振り返りつつ紹介します. メルカリにおける越境取引 「メルカリ」に出品したことがあるみなさんの中には,自分の商品が一般のお客さまではなく事業者によって「代理購入」された経験がある方もいらっしゃるかもしれません.これは,海外のお客さまが日本の「メルカリ」に出品されている商品を購入できる越境 (Cross-Border, XB) 取引という仕組みによるものです. メルカリにおける越境取引は代理購入パートナーとの連携によって実現されています.海外のお客さまは,まず提携パートナーのWebサイト上で「メルカリ」の商品を注文します.すると,パートナーが購入代行者として「メルカリ」上で商品を購入し,支払い手続きを行います.国内の出品者は,この代理購入者であるパートナーの指定する日本の倉庫へ,通常の国内取引と同じように商品を発送します.商品が倉庫に到着後,パートナーが検品や海外向けの梱包を行い,海外のお客さまの元へ国際発送するという流れで実現されています. この仕組みは,海外と国内のお客さまの双方にメリットがあります.海外のお客さまにとっては,言語の壁や通貨の違いを気にすることなく,日本のユニークな商品を手軽に購入できます.一方で,国内のお客さまにとっては,海外のお客さまとの直接的なコミュニケーションや国際発送といった複雑な手続きは一切不要で,国内取引と同じように販売の機会を世界中に広げることができます. 越境取引事業は2019年に始まり,近年さらに成長しており, GMVとしては過去3年で15倍に成長しています.特に,アニメ,コミック,ゲーム,エンタメ関連グッズのカテゴリーが取引全体の多くを占めており海外のお客さまからの強い需要があります. このような強い需要と成長を顧みて,代理購入パートナーのサイトを通じた仕組みに加え, 日本のメルカリのWebサービス を通じて代理購入を可能にする取り組みも開始しました.この仕組みにより,海外のお客さまは直接「メルカリ」上でアカウントを作成し,「メルカリ」が提供する体験を通じて商品の検索と購入を行うことが可能になりました (引き続きパートナー企業を間に挟む形式は継続しています).この取り組みは2024年にリリースし, 現在台湾と香港から利用可能で利用者数を伸ばしています. こうして越境取引事業は順調に成長してきましたが,同時にいくつかの重要な課題も見えてきました.以下で説明するように既存の日本のシステムは日本市場に特化して作られており,単一通貨・単一言語を前提とした設計になっています.越境取引機能はこの上に追加的に実装したため,複数国への展開や各国固有の商習慣への対応を実現していくには限界がありました.特にアジア市場ではEC利用の多くがモバイル経由という状況において,Web版のみの提供では競争力に欠けるという問題もありました. このような課題を抱えながらも,海外市場からの需要は確実に存在しており,特にアニメ・ゲーム関連商品への関心は非常に高いことがわかっています.現在は台湾と香港の2か所のみですが,東南アジアや欧米にも同様の潜在的な需要があることは明らかでした.この機会を最大限に活かすためにはより早く展開国を拡大していく新たなアプローチが必要でした. そこで私たちは,単に既存システムを拡張するのではなく,グローバル展開を前提とした新たなアプリケーションとその基盤を構築するという決断に至りました.これは越境取引から始めて,将来的には各国でのローカルマーケットプレイスの立ち上げ,そして最終的には国境を越えたグローバルなマーケットプレイスの実現を見据えた戦略的な判断でした. 海外展開のアプローチ グローバルなマーケットプレイスの実現は,メルカリ創業当時からのビジョンであり,海外展開への挑戦は今回が初めてではありません.これまでにもアメリカでの事業展開に挑戦し,現在もその成長に注力しています.過去にはイギリスへの展開を試みた経験もあります. これまでの海外展開では,それぞれの国において,日本と同様のローカルなC2Cマーケットプレイスをゼロから立ち上げるというアプローチを取ってきました.しかし,今回のグローバル展開は越境取引の成功と課題から学んだ新たなアプローチを取っています.日本から海外へ商品を届ける「越境取引」を事業の軸に据え,そこで構築した顧客基盤を活かしながら段階的にサービスを拡大していく戦略です.また展開エリアも3年以内に50カ国と地域を目指しており,スピード感も従来とは大きく異なります.これは日本のお客さまや事業者に出品していただいたユニークで豊富な商品を世界中に届けることを起点とし,そこから更なる可能性を模索していく戦略への転換を意味しています. この事業戦略の転換によりエンジニアリング戦略も大きく変えました. これまでの日本とアメリカ,そしてイギリスへの展開はそれぞれ独立した異なるシステムにより実現してきました.もちろん当初は共通のコードベースを各国にデプロイする方式 (ただしデータは分離) を取っていました.しかし,日本向けに作られたシステムを各国の事情に対応させていくことによるコードベースの複雑化 (e.g., 国のスイッチのためのif文が多くの場所で書かれることになった) や,国間での方針のアラインが必要であるために各国の意思決定のスピードの低下といった課題にぶつかりました. 最終的にはフォークを決定し,それぞれ独立したシステムとなり,開発運用の体制も分離していくことになりました.アメリカはその後アプリ自体も現地のUI/UXに合わせて刷新を行い,独自の機能をその上に実装していくことになり,日本とアメリカのシステムは今日でも分離されています. この方法は,迅速に事業を立ち上げ,各国の市場に深く最適化できる点では有効なアプローチでした.各国の事業をそれぞれで伸ばしていくために独立した組織作りとシステムを開発していくのも重要だったと思います.一方でより長期的な視点に立ったときに以下のような課題があり,次の展開へと繋げることが困難になっていました. 展開のコストとスピード : 展開国を増やすという観点での共通の基盤の整備はできておらず,次の国を考えたときに新たなアプリケーションとバックエンド基盤を構築し直すこと,もしくは既存のシステムの大規模な改修を考える必要がある. 開発リソースの非効率性 : 同じような機能がそれぞれの国で個別に実装され,各基盤に専任のチームが必要となるため,開発リソースの重複や運用の非効率性が発生する. 現状の「越境取引」自体は既存の日本のシステム上に構築できています.しかし,以下でより詳しく述べるように既存のシステムは複雑化しており,今後のより高速に展開国を増やしていく,グローバルに向けたより良いUI/UXの提供を行っていくのは限界がきていました.そして「越境取引」の次,例えば新たな国でローカルのマーケットプレイスを展開するといったことに繋げることは非常に困難です. このような課題を根本的に解決し,そして「越境取引」を中心とした新たな海外展開を効率的に加速させるためには新たな戦略が必要でした.そこで「国や地域ごとに個別のシステムを構築するのではなく,単一のグローバルな基盤で全ての国や地域をサポートする」という新たなビジョンを打ち立てその基盤の開発を始めました. グローバル基盤の開発戦略 この単一のグローバル基盤の開発の戦略にはいくつかのアプローチが考えられますが「拡張と再構築のハイブリッドなアプローチ」を選択しています.このアプローチに至った背景をこれまでのメルカリのバックエンドシステムの変遷から説明します. メルカリのバックエンドシステムの変遷 メルカリのバックエンドシステムはMonolithアーキテクチャ (単一コードベースに全ての機能を実装する方式) として始まっています.アメリカ事業やイギリス事業を開始するときにフォークという選択肢をとることができたのはこのためです (それぞれの国のスケールを支えるために裏側のインフラやツールとして多くの仕組みがありそれらを複製するのは容易ではなかったはずですが). 2017年あたりから特に日本の組織の規模は急激に拡大を始めます.組織の拡大により単一の巨大なコードベースに多くの人が同時に開発を行うことが困難になり,また一部の機能のバグでサービス全体に障害が波及する事も多く発生しました.加えてほとんどのシステムがオンプレ上に構築されており,その運用や拡張がボトルネックになっていました.このような問題を解決するためにMicroservicesアーキテクチャ移行とクラウド移行 (それに伴うDevOps化への移行) を開始します.私自身が入社したのはこの直前で,移行プロジェクトの推進とMicroservices開発の基盤やツールを整える Platform Engineeringチームの立ち上げと拡大 を担ってきました. Microservicesアーキテクチャ移行のアプローチとしては Stranglerパターン を採用しました.これは既存のシステムの前段にGatewayを置き,そのGatewayを軸にトラフィックを徐々に新しいシステムに移行していくという方針です.より具体的には,(1) 既存システムに実装されている機能群をMicroservicesとして切り出し (2) Gatewayからその機能の利用トラフィックを徐々にMicroservices側に流す,を繰り返すことで段階的に新システムに移行していくアプローチです.移行開始から数年が経過しましたが,多くの機能をMonolithから切り出し,またその上で新しい機能を開発してきました.またほぼ全てのサービスのクラウド移行も完了しています (サービス数でいうと100を超えています). Microservices化以降では日本ではメインとなるC2Cマーケットプレイス事業に加えて複数の新規事業の立ち上げが始まることになります.フィンテック事業のメルペイ,暗号資産のメルコイン,B2C事業のメルカリShops,そしてスキマバイトサービス事業のメルカリハロです.メルペイはメルカリの決済システムを切り出しており,MicroservicesアーキテクチャとしてC2Cと同じインフラ基盤上に構築しています.メルコインはセキュリティのためにインフラは大きく分離していますが,基本的には同様のアーキテクチャパターンで開発しています.ShopsはMicroservicesアーキテクチャですがC2Cとは切り離した独立したシステムになっています (モバイルアプリとしては一つですが,裏側のバックエンドは分離しています). この数年に渡るMicroservices移行と複数事業の立ち上げに合わせて推進してきたのは共通基盤の整備です.自分がリードしてきたPlatform Engineeringのレイヤーとしての開発基盤やツールだけではなく, ID基盤 や 決済基盤 ,マーケティング基盤のような複数事業にまたがって利用できる基盤も開発してきました.これらが創業以来メルカリのバックエンドシステムの変遷です. 既存システムの課題 2025年の現在,既存のシステムを俯瞰したときにいくつかの構造的な課題を抱えています. 最も大きな問題は,C2Cマーケットプレイスとして重要な機能がMonolith基盤に残っているという点です.Stranglerパターンとしていくつかの機能をMicroserviceとして抜き出すことはできてはいますが,この方式はProxy的に上物の機能を抜き出すに止まりデータ移行まで進まなかった部分も多くあります.特に「トランザクション管理」「配送」といった機能をMonolithとそのDBから抜き出すことができていません.これらはロジックとして密結合が強くうまく分離を進められなかったというのも大きな理由です.そのためMonolithへの強い依存が未だに残っています.この部分は今でも多くの開発と変更が必要な一方で複雑なコードベース上に残ってるために,日本事業の継続的な改善においても早急な対処が必要です.Microservices移行の初期から関わってきた人間としては,この重要部に初期から挑まなかったのは大きな反省です. グローバル展開を見据えてもこれは大きな課題になります.Monolithに残るトランザクション管理と配送システムは日本市場に特化した設計になっています.トランザクション管理は日本円のみを前提としており,複数通貨での取引,為替処理,各国異なる税制への対応を追加することは非常にコストは高いです.配送システムも日本国内の配送業者のシステムと密結合しており,各国のローカル配送業者,異なる配送オプションへの対応は根本的な作り直しなしには実現は難しくなっていました. また,C2CマーケットプレイスとB2C Shopsのシステム乖離問題があります.現状は別々のトランザクション,配送システムをそれぞれが持っているだけでなく,プロダクトの管理も分かれており,結果として日本のお客さまに対しても統一的な体験を提供できていません.これは,もともとのビジョンとして独立したサービスが考慮されていたこと,方向性が変わり統合しようと思っても上のMonolith問題により実行が難しかったことが原因として挙げられます. Microservicesアーキテクチャ自体にも課題があります.各サービスのオーナーシップと自由度を重視し,サービス間で十分な抽象化を行えていなかったこと,適切なドメイン分離を行えておらず分割の単位も非常に小さくしてしまったことが原因で,多くの小さな,作り方が微妙に異なるMicroservicesが数多く構築されてしまいました.このためMicroservicesの運用のコストが非常に高くなってしまっています.メルカリはスピード感を持って物事を進めるため組織変更も頻繁に行いますが,そのたびにMicroservicesのオーナーシップの移管が必要になり,実装の差異によりオンボードのコストも高くなっています. これらの制約により,既存システムの延長線上でグローバル展開を進めることは,技術的にもビジネス的にも限界があることが明確になりました. グローバル基盤の方向性 このような変遷と現状の課題をベースにグローバル基盤の開発方針としていくつかのアプローチを考慮しました.まず,過去のアメリカ展開のようにフォークという選択肢を取ることは非常に難しくなっています.Microservices化された多くのシステムを複製していくのは現実的ではありません.全てをゼロから再構築することも考えましたが,これもコストと効率の観点から選択肢から外しました.結論として「既存のシステムの拡張と再構築のハイブリッドなアプローチ」を選択しています. このアプローチでは,どこまでを拡張とし,どこまでを再構築するか? のラインを決めるのが重要でした.既存のシステムの多くは日本の市場に特化したものになっており,また多くのサービスがMicroservices化されています.それら全てを拡張していくのは現実的ではありませんし,日本事業は引き続き重要であるため,グローバル展開はそこから独立して進められることも重要でした.また未だ残るMonolithにグローバルから依存することも避けたいという強い気持ちもありました. 「拡張」としては複数事業の立ち上げとともに発展した共通基盤を主に活用することにしました.特に強い専門性が求められる,そして拡張性を考慮して設計されてるサービスを選定しています.以下で詳しく述べますがMicroservicesからの脱却も同時に考えており,小さな細かなサービスには依存するのではなく,十分な大きさかつ独立した「ドメイン」(SaaSとして置き換えられるレベル) に依存することも決めました.この基準により,例えば,ID基盤はグローバルで共通に,また決済基盤はメルペイ基盤を通じてStripeに接続しグローバルの通貨やローカルの決済手段に対応していく,といったことを進めています.他にも検索基盤,マーケティング基盤なども既存のシステムを拡張することで活用しています. それ以外の部分は「再構築」の選択肢をとっています.特に上述したC2Cサービスとしての「トランザクション管理」「配送」「アイテム・プロダクト管理」は作り直すしかありませんでした.日本と同じ問題を避けるために,(1) それぞれを疎に長期的な拡張性を容易にする (2) CとBの商品を同等に扱い,統一したUI/UXを提供することができることを考慮し,また複数カ国展開や別の国において新たなローカルマーケットプレイスを実現できるようにするために (3) 各国の通貨,言語,税制・関税,法規制に柔軟に対応できる (複数であることを前提にする.以下のTenetsを参照) (4) 日本以外の国の商品や配送手段を扱うことになっても対応できるようにする,を前提として構築しています. また単に作り直すだけではまた新たな別基盤が誕生するだけです.初期はグローバルでの成功をメインとしつつも,最終的には日本のC2CとB2Cの基盤も置き換えていく,という想定で動き始めています (実際にリリースまで達成したのでこの基盤を日本でも活用していくためのプロジェクトを始動しています). モバイルアプリとWebに関してもグローバルでは異なるUI/UXは必須なので作り直しの選択になっています.加えてバックエンドを刷新することでAPI自体も切り替えることもでき,実装自体もより良くできます. MicroservicesからModular Monolithへ 上述したMicroservicesアーキテクチャの抱える課題に取り組むため「再構築」したバックエンド基盤はModular monolithアーキテクチャとして開発しています. Microservicesの課題 メルカリにおいてMicroservicesアーキテクチャの運用コストが高くなってしまった大きな理由は,各サービスの開発の自由度を高めてしまったところにあります.サーバー実装はGoで,データベースとしてSpanner/CloudSQL (MySQL),インフラとしてKubernetesを利用する,という最低限の技術スタックの統一は進めてきました.一方で,レポジトリ戦略はPolyrepo (1サービス = 1 GitHub レポジトリ)として,基準となるテンプレートや最低限の共通ライブラリはあれど,レポジトリの構成や実装方針は各チームに委ねる形になっていました.そのため,マクロで見ると同じGoのMicroservicesですが,ミクロでみるとかなり異なるサービスが量産されました.一つ一つのサービスの運用のコストは小さくても,異なるサービスを複数面倒見る必要があるとその差異により共通化ができず,コストが高くなるということが起こっています. これに加えてメルカリはとにかくスピード感を持って物事を進め方向性を転換していくため組織変更も頻繁に行います.そのためMicroservicesのオーナーシップの移管も頻繁に行う必要があります.移管のたびにオンボードが必要ですが実装の差異によりそのコストも高くなります.また共通化を進めるのも難しいです. また特にMonolithから移行を進めたC2C側はドメインの適切な分離ができていないところも多く,サービスの凝集度が低いところが多くあります.これにより機能追加のために複数のサービス,チームに跨った変更が必要になり,コミュニケーションコストの増大にも繋がっています.サービスごとのオーナーシップを強化するという方向性は逆に外からの変更を受け入れにくくするということにも繋がっています. このような課題に対して上手くMicroservicesアーキテクチャによる実装を進めたのが メルカリShopsによるMonorepoを使ったアプローチ です.この方式ではShopsに関わる全てのMicroservicesを1つのRepoにまとめ,サービス間の実装を抽象化・統一化するということを実現しており,複数サービスによる運用のコストを削減しています.開発体験としてはMonolith的に,裏ではサービスが分離されてデプロイされる(これにより耐障害性のメリットを得られる),という両方の良い部分を取り入れることができています. 一方でこのアプローチであっても課題はあります.こうしたMonorepoのためのインフラや自動化の仕組みを管理維持していくのは非常にコストが高いです (既存のPlatformと大きく分けて構築されたため共通基盤チームとの連携が難しくなっていたことも原因として挙げられます).そもそもMicroservicesのテスト,デプロイ,開発環境の構築は複雑にならざるを得ません.例えばテスト環境は全部のサービスをPRごとに複製するという富豪的なアプローチをとっています.またサービスごとにDBを分けるなどを厳密に行なっており,インフラのコストも高くなってしまっています. Modular Monolith このような背景もあり,新しい基盤の構築にはModular monolithアーキテクチャーを選択しています.単なるModular monolithではなく特定のModuleを必要とあらば独立してデプロイ可能な形にしています (Service Weaverのコンセプトに近い). 初期のメルカリのMonolithでは適切なドメイン分離・モジュール分離ができなかったためにコードの密結合とそれによる複雑化が発生したと思っています.サービスの境界,依存関係をモジュールごとに明確に整理することで同様の問題に当たらないようにしています.Microservicesのように細かく分離しすぎることで複雑になるのを避け,十分に機能が凝縮されたモジュールを作るようにしています.また必要なときに独立したデプロイを可能にすることでMicroservices的な耐障害性の利点も可能にしています. 初期の開発フェーズでは人数も多くないので基本は特定のモジュールにオーナーシップを限定することはしていません (もちろん特定の領域に強い人はいる).皆がコードベース全体にオーナーシップを持ってもらうようにしています.これにより,プロダクト開発の優先度によってモジュールのアサインが動的に決まり,Microservicesで発生した無駄なコミュニケーション調整コストをなくしています.一方で,今後組織が拡大したとしても,モジュール単位でのアサインは可能であり,かつてのMonolithでハマった問題も解決できる余地もあります. Monolithであることで,ワンバイナリによるローカル開発環境の構築は容易になり,またテストやデプロイもシンプルになり,Microservicesによって生じていた開発負荷もなくすことでより良い開発体験を作れています.インフラやCI/CD基盤もPlatform Engineeringチームが提供するものをそのまま使うことができ,ShopsのMonorepoアプローチで陥った基盤運用コストを抑えることができています (より詳細は次のポストで @yanolabより紹介します). 一方でこの方針は組織全体の中では新しく,既存のMicroservicesアプローチとどう共存していくかという課題があります.現実的に一度分離したMicroservicesを全てMonolithへと戻していくことは簡単ではありません.そのためMicroservices自体は今後も残ることになると思います.Microservices開発と運用のコストを減らしていくために,サービスの分割単位をより適切なレベルに合わせていくことや,さらに言えばShopsで実現したようなMonorepoアプローチによる統一化を高めていくことが重要だと思っています.そして将来的な新規事業でこれからMicroservicesアーキテクチャーを初手で選択することは,特別な理由がない限りは,しない方がいいと思っています.このグローバル基盤のModular monolith構築パターンを横に展開し,実装パターンを共通化していくことも考えています. 技術スタック 以下はこの基盤の構築に利用している技術スタックの一覧になります.基本的にはメルカリがこれまで培ってきたスタックを前提に大きく変えないでそれらをうまく活用するようにしています. インフラ: 引き続きメインのクラウドにはGoogle Cloudを採用しています.メインのリージョンは東京を使っていますが,将来的には(特にパフォーマンスの観点から) 別のリージョンを利用する可能性も考慮しています.アプリケーションの実行基盤にはPlatform Engineeringチームが管理するKubernetes (GKE) を利用しています. データベース: データベースにはAlloyDBを選択しました.これまではメルペイを中心にSpannerを選定してきましたが, (1) 長期的な展開を考慮した時にGoogle Cloud 全てで担えない可能性も考慮し,なるべくロックインを避けること (2) PostgreSQLによるより良い開発体験エコシステムを利用すること,を考慮してAlloyDBを選定しました.他にもCockroachDBも考えており,今後の展開によっては乗り換えも考慮する可能性があります 言語・フレームワーク: サーバーはGo,iOSはSwift,AndroidはKotlin,WebはNext.js (TypeScript)としています.ここは大きく変えていません Monorepo: より詳細は別のブログがこのあと書かれますが,iOS, Android,Webはそれぞれ日本のサービスのレポジトリをMonorepoとして拡張することで開発されています.日本とグローバルで共有可能なモジュールを切り出し,CI/CDを共通化することで,開発と運用の効率化をしています. Tenets この新たな基盤とアプリの開発には日本のみではなくインド拠点のメンバーを含めて多くが参加しています.さまざまな背景のメンバーが参加しても,これまで上で紹介してきたような方向性を実現するには,皆が同等の指針にしたがって意思決定を行えることが重要です. これを実現するために「Global Engineering Tenets」を策定しました.TenetsはAmazonの Tenets: supercharging decision-making を参考にしています. 主なTenetsをいくつか紹介します: Design for two : ソフトウェア開発においてある機能のサポートを1から2に増やすよりも,2から3に増やす方が容易であることは実感としてわかると思います.例えば,アプリケーションが既に2つの言語をサポートしている場合,3つ目の言語を追加するのは簡単です.一方、アプリケーションが1つの言語しかサポートしていない場合、2つ目の言語を追加するにはi18nの仕組みなど多くの準備が必要になります.これはグローバル展開においても同様のことが言えます.既に複数国・地域に対応している基盤に新規の地域や国を追加するのは、単一地域/国向けのアプリケーションを拡張するよりもはるかに容易です.機能やシステム設計においては常に2カ国・地域以上を想定するようにしています. Global by default but enable localization : グローバル利用に向けたシステム開発を進める一方で,単に複数国へ事業を拡大するだけでなく,主要市場ではローカライゼーション施策を実施します.そのため,システムは複数の国々へ迅速かつ容易に拡張できつつ,かつ特定の国の要件をサポートする柔軟性も考慮する必要があります.長期的にはローカライゼーションのため現地にエンジニアリングチームを設置する可能性もあり,彼らが独立してローカライズ機能を開発できるようにする必要があります. Learn and unlearn from the past experience: 今回新規で「再構築」する部分が多くあります.ただし,これは完全に新規であるべきではなく,上で紹介したような過去の学びを重要な資産として活用するべきです.自分は概要を説明しましたが,それぞれの領域,モバイル開発,Web開発,プロダクト開発などさまざまな領域で見直すべき課題があります.新しく採用したメンバーに関してもこれらの活用は強くお願いしました. Keep each country’s business isolated : 既存の基盤やプラットフォームを活用する場合でも、相互に影響を与えないようにすべきです.例えば,グローバルで発生したバグやインシデントが日本の事業に影響を与えたり,その逆が生じることを避ける必要があります. これらはデザインドキュメントを書く時など多くの場面で指針として利用されています (特にDesign for Twoは各所で言われた).もちろん,多くの人が参加してる,長期的なプロジェクト、である以上は細かな部分ではズレは発生していますが,大きな方向性としては皆が同じ方向を向けたのではないかと思っています. 今後の展望 今回のリリースでは基本となる機能の実装が完了した状態です.今後はこの上に越境取引にとって重要になる機能,例えば事業者商品の予約販売機能や鑑定機能,などを実装しつつ,展開国をどんどん増やしていくことを目標としています.横展開だけではなく,特定の国へのローカライズとグロースを行っていく必要もあり,さらに基盤を活用していくフェーズになります.また上で紹介したように基盤自体は日本でも使えることを想定しており,その置き換えのプロジェクトも始めています.これによりこれまで抱えていた技術的な負債も同時に返済していくことを考えています. mercari Gears 2025 2025年11月13日に、実に7年ぶりとなるメルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます.@yanolob とともに「Building Foundation for Mercari’s Global Expansion」と題して登壇いたします. グローバルアプリを開発するにあたり、なぜこのアプローチに至ったのか,どのようなアーキテクチャや実装で支えているのか,組織的なチャレンジと技術の両面から詳しく紹介します.複数リージョン展開における開発・運用上のチャレンジや,組織横断での意思決定の工夫についても共有します. ぜひ,セッションを聞きに来てください! 参加登録はこちら 👉 https://gears.mercari.com/ 明日の記事は @yanolobさんです。引き続き 連載企画:メルカリ初の世界共通アプリ『メルカリ グローバルアプリ』の開発舞台裏 をお楽しみください。
こんにちは。Cross Border (XB) Engineeringの @deeeeet です。 先日、2025年9月30日に越境取引事業の新戦略を発表し、メルカリ初の世界共通アプリ「メルカリ グローバルアプリ」(以下、グローバルアプリ)の提供を開始しました。 そこで今回は、グローバルアプリの開発プロジェクトの開発舞台裏をご紹介する連載企画をスタートいたします。 トピックはバックエンド開発のみではなく、モバイル開発、Web開発、SRE & Enablingなどなど多岐にわたるのでお楽しみに。 「メルカリ グローバルアプリ」の概要 メルカリ初となる世界共通アプリで、 海外の購入者は「グローバルアプリ」を通じて日本の「メルカリ」と「メルカリShops」の商品を閲覧・購入することができます。言語や決済、複雑な手続きなどの課題が解消され、海外の購入者は日本の「メルカリ」と同様、かんたんかつ安心・安全にお買い物を楽しめます。2025年9月30日より台湾・香港で提供を開始し、今後、展開する国や地域を順次拡大する予定です。 公開予定表 こちらは、後日、各記事へのリンク集になります。 Title Author Rebuilding Foundation for Global Expansion @deeeet Behind the Infrastructure Powering Global Expansion @yanolab TBD: Multi-domain strategy with Next.js @gary Order management in GOP @takady TBD: Global search strategy @shinpei The journey of item translation @aymeric Platform から SRE に転生!現場の声を聞きながら改善していく! @hatappi Something about global IdP @gia TBD: GOP Android strategy and execution and all in between @Karthi Mirrord + E2E testing @ryotarai TBD: How we overcome Project management challenges (How to plan a product launch in 6 months) @g-bansal TBD: B items integrations strategies in GOP @ahsun Guest post from FT payment platform — Engineering for Multi-Currency and Multi-Provider Payments @ryuyama TBD @manas TBD @vb TBD: GOP App Release Strategy @manoj readability; backend common packages etc @osari.k Scaling iOS Development: Building and Operating Multiple Apps in a Large-Scale Monorepo @shingt TBD: distributed transactions on checkout flow, specially error handling, retry @ahsun TBD: Framework for handling i18n resources in web modular monorepo @gary TBD: Order (Double Master Data Migration); ItemxTransaction (decoupling using sagas/external locking) @andrei Something about global payment and checkout @huhu TBD: Ops development with AI @waiting.lau Taming Agents in the Mercari Web Monorepo @maxi Sync Saga @Shishir TBD: High output teams @Atif TBD: Ordering Features @Shreyasi TBD @Chong (チョン) TBD @chris ひとつでも気になる記事がある方は、この記事をブックマークしておくか、 エンジニア向け公式X をフォロー&チェックしてくださいね!
はじめに 2025年度のBuild@Mercariに参加し、メルカリ ハロのMLチームでインターンをしている@Ariaと@Ririkoです。私たちはメルカリ ハロの求人のリスク予測に取り組みました。この記事では、インターンで取り組んだこと・感想などについて書いていきたいと思います! 自己紹介 @Aria こんにちは!大学1年の@Ariaです。私は高校生の時Build@Mercariに参加し、夏休みでBuildインターンをしています!機械学習・AIについて学んでみたいと思い、メルカリハロのMLに応募しました。 @Ririko 大学の学部3年の@Ririkoです!大学では電子情報工学を専攻しています。春休みにBuild@Mercariに参加しました。機械学習やAIに以前から興味があり、今回のBuildインターンに応募しました。本格的にインターンに参加するのはこれが初めてです。 背景 メルカリ ハロでは「求人の内容が適切か」「不適切な表現が含まれていないか」などといったリスクのある求人がないかを全件チェックしています。 今回、私たちは、様々な機械学習手法で求人のリスク予測モデルを作成し、それぞれのコスト・精度・管理のしやすさなどの検証を行いました。 やったこと 以下のモデルを試し、コスト・精度・管理のしやすさなどの比較を行いました。 統計モデル ロジスティック回帰 LightGBM NNモデル BERT LLM 各モデルの構築について 概要 求人のリスク予測においては、全体数に対してリスクのある求人数が少ないです。モデル作成の際に最も重要なことはリスクのある求人を取りこぼさずに検知することです。モデルが誤ってリスクありと判断した求人の数(False Positive数)がある程度増えてしまってでも、モデルが誤ってリスクなしと判断した求人の数(False Negative数)をゼロにすることが重要になります。 また、統計モデルやニューラルネットワークモデルを扱う際、訓練時に愚直に学習させると、データに不均衡があるためにすべての求人をリスクなしと判断するようになってしまいます。そのため、正例(リスクがある求人データ)の数を拡張したり、損失関数に重みづけをしたりするなどして学習を工夫する必要があります。 統計モデル ロジスティック回帰とLightGBM、どちらのモデルを用いる場合でも、コンピューターが文章を理解できるよう前処理が必要です。まず、文章のテキストデータを形態素解析によって単語に分解します。例えば、「猫はコタツで丸くなる」という文は、「猫」「は」「コタツ」「で」「丸く」「なる」といった単語に分けられます。 次に、TF-IDF(Term Frequency Inverse Document Frequency)という手法を用います。TFは文書内での単語の頻出度を表し、IDFは単語の希少度を表します。TFとIDFを掛け合わせることで、単語を数値化し、文書全体をベクトルとして表すことが可能になります。このベクトル化の際には、正例に特徴的な単語をFeature(ベクトルの基底)として抽出しました。TF-IDFを用いることで、「は」や「で」のように頻繁に出現するため重要度が低い単語ではなく、特定の文章にのみ現れる重要度の高い特徴的な単語を際立たせることができます。 このようにして作られたベクトルを入力として、各モデルは、求人にリスクがある場合は1、ない場合は0のラベルを出力するよう学習させました。 ロジスティック回帰 ロジスティック回帰は、機械学習において最も基本的な分類モデルで、結果が0か1かといった二値である事象を予測するための統計的手法です。特定の事象が起こる確率を、説明変数を使って計算します。このモデルは、確率を0から1の間に収めるためのシグモイド関数という特殊な関数を用いるのが特徴です。 訓練データを愚直に学習させると、データに不均衡があるために、うまく学習できずすべてリスクなしと判断するモデルになってしまいます。そのため、今回のロジスティック回帰では損失関数の計算時に、数少ない正例のペナルティが大きくなるように重み付けをしながら計算して学習を回しました。また、ハイパーパラメータのグリッドサーチなどによりモデルの性能向上を目指しました。 LightGBM LightGBMは決定木をベースとする機械学習アルゴリズムです。特に、大規模なデータセットを扱う際に、その高速性と高い予測性能から、データサイエンスの分野で広く利用されています。 LightGBMには、ハイパーパラメータと呼ばれる設定項目がたくさんあります。これらのパラメータを適切に設定することで、モデルの性能は大きく変わります。そのため、グリッドサーチという手法を使って、最適なパラメータの組み合わせを自動的に探索し、モデルの改善に取り組みました。 BERT BERTは、2018年にGoogleにより開発されたTransformerのエンコーダー部分を基盤とする事前学習済み言語モデルです。大量のテキストデータから単語の文脈を双方向で学習するため、文全体の意味を深く理解できます。これにより、質問応答や文章要約など、さまざまなNLPタスクで高い性能を発揮します。 BERTは正例と負例の数の不均衡なデータセットの学習が苦手です。そのため、LLMを用いて合成データを作成し、正例の数を増やしました。データ拡張の際にLLMに渡したプロンプトには元の正例の中からランダムに選んだデータをfew-shotとして組み込み、生成されたデータの文体に多様性が生まれるように工夫しました。さらに、BERTの学習において重要なパラメータ(トークン化の際の最大文字数、バッチサイズ、エポック数、学習率など)をグリッドサーチにより探索し、モデルの性能向上に取り組みました。 LLM LLMに学習は必要ないので、データの前処理なしでプロンプトを工夫して、精度改善をしました。単に「リスクがあるか、ないか」のラベルだけでなく、なぜそのように判断したのかという理由も出力させました。LLMの出力から、誤った判断を下した理由や、不足している情報がないかを分析し、足りない指示をプロンプトに追加し改善しました。また、求人審査にはルールがあるため、そのルールをしっかり理解し、テキストデータを見直すことも精度改善につながりました。 実用上の観点から考えた各モデルの長所・短所 長所 短所 ロジスティック回帰/ Light GBM 2値のクラスに分類するための境界線である閾値の調整によってどこまで検知するか決められる 処理が非常に早い 求人件数が増えても運用コストがあまり変わらない 説明性が低い ルールが改定されたときに新たな学習データの用意、学習に手間がかかる BERT 2値のクラスに分類するための境界線である閾値の調整によってどこまで検知するか決められる 文脈の理解が得意 説明性が低い ルールが改定されたときに新たな学習データの用意、学習に手間がかかる 推論にGPU、または多くのCPUを使うので統計モデルに比べて運用コストが高い LLM 管理がプロンプトの更新のみで簡単 ルールが改定された時も更新が容易 過去にデータがないものへの対応が可能 なぜそのように判断したかの理由が自然言語で説明できる 件数が増えると、処理時間・運用コストが線形的に増える 比較結果 統計モデルは複雑な文脈の問題に関しての求人のリスク検知は苦手であるものの、今回取り組んだタスクにおいては、学習方法を工夫することにより、LLMと同等の精度を出すことができました。 BERTについても、学習に使うデータを拡張して正例・負例の数を同程度にすることにより、LLMと同等の精度を出すことができましたが、運用コストが統計モデルに対して高いので、今回の求人のリスク予測に関してはBERTを選択するメリットがないという結果になりました。 運用コスト面で比較すると、統計モデルは小さなインスタンスで動くので、冗長性を考慮しても運用コストが低く、また求人件数が増えてもコストが変化しにくいです。BERTは統計モデルに比べてCPUがたくさん必要なので、元々のコストが高くなります。一方、LLMはトークンごとの課金のため、求人件数が増えるごとにコストも線形的に高くなります。 これらの結果から、求人件数が少ない段階ではLLMが柔軟に活用できる一方、求人数が増えるとLLMではないモデルへの切り替えがコスト削減になることが分かります。 インターンでの学び・気づいたこと 今回のインターンを通して、テキストデータを前処理して統計モデルに適応する手法や今まで学ぶ機会がなかったBERTなどのモデルについて理解を深めることができました。モデルの性能を向上させるためにやるべき手法についても実際に手を動かしながら学ぶことができました。また、モデルに変更を加えて性能向上を目指すだけでなく、与えられたデータを自分の目でよく確認してデータの特徴を掴むことも非常に重要であることも学びました。 実際の業務においては、自分が考えていることや試してみようと思っていることを他の人が確認できる形で言語化しておくことで、コミュニケーションがスムーズになるということを認識しました。 左から@Aria, @Ririko 終わりに 本記事では、インターンで取り組んだタスク、感想についてお話しさせていただきました。今回のインターンを通して、開発に必要な知識、またキャリア面での知識など様々な学びを得ることができました。一ヶ月という時間はあっという間でしたが、とても濃い時間を過ごせました。 メンターの@ku-muさん、アドバイスをくださった@arr0wさん、ML teamの皆さん、本当にありがとうございました!
はじめに はじめまして!8月の1ヶ月間、Buildインターンに参加したkyoroです。 文系の私にとって、Build@Mercariは「エンジニアへの第一歩」となった大変貴重な成長機会でした。私がBuild@Mercariで学んだことや経験したことを共有することで、同じように「エンジニアになりたいけど、非STEM領域出身で自信がない」や、「成長の機会に恵まれていない」と感じている方々に、Build@Mercariという選択肢があることを知ってほしいと思いました。 私に似たバックグラウンドをお持ちの方や、これから参加を検討されている方々の参考になれば幸いです。 なぜBuild@Mercariに参加したか 私は大学1年生で受講したデータサイエンスの授業をきっかけにプログラミングに興味を持ちました。しかし、私の学部は完全に文系でCS関連の授業もなかったため、それ以降は独学で学習を進めていました。 独学で学習を進めていたものの、実践の機会が少なく、あまり成長を実感できていない部分がありました。インターンシップを通して実践的に成長できたら、と思っていましたが、応募時点で一定の開発経験や制作物を求められることが多く、なかなか受け入れてもらえない状況が続いていました。そんな時、テックコミュニティ経由でBuild@Mercariの存在を知りました。現時点での経験が浅くても参加できるエンジニア育成プログラムと聞いてすぐに応募を決めました。 Build@Mercariってどんなプログラム? 性自認が女性である方を対象に、ソフトウェアエンジニアリングのスキルトレーニングとインターンシップの機会を提供するプログラムです。 現在STEM領域では女性がマイノリティとなっています。業界全体のD&Iを推進するべく、メルカリではこうした学習機会を私たちに提供してくれています。 Buildトレーニングについて 2週間で、メルカリを想定した簡易出品アプリを個人で構築します。 この課題を通じて、Gitの使い方からAPI開発、フロントエンドの実装、Dockerによるコンテナ化まで、Webアプリケーション開発の基本を一通り学ぶことができました。アプリ構築以外にも「アルゴリズムとデータ構造」や「データ分析」を学ぶステップも用意されており、非常に内容が充実しています。 選考の話 選考では、志望動機とコーディングテストを提出します。コーディングテストは、コンピュータサイエンスに関する基礎知識を確認するためにオンラインで実施されます。Buildトレーニングプログラムは、通常のインターンシップ選考とは異なり、多くの方にチャレンジしていただきたいという想いから、コーディングテストの難易度は低めに設定されています。そのため、現時点でのスキルに自信がない方も応募をためらう必要はありません。 このトレーニングの良かった点 1つ目は「数人のチームに分かれて、各自課題に取り組む」ことです。平日は毎日、グループ内で進捗共有の時間があり、メンターさんに質問したり、他のメンバーの進み具合を知ることができました。ここで自分の遅れを認識し、良い意味で焦れたことが、トレーニングを完遂できた大きな要因でした。初学者が一人で学習していると、わからないところで立ち止まってしまい、そのまま学習を中断してしまうことも多いです。そういった意味でも、このように仲間やサポートがある環境は、とても心強かったです。 2つ目は、「参加者は1年間無料でUdemyの講義を受講できる」ことです。 参加時点では周辺知識がほとんどなかったため、とにかくトレーニング中はコードを動かすことで精一杯でした。しかし、トレーニング終了後にUdemyを大いに活用し、点と点だった理解を少しずつつなげて腹落ちさせ、「なぜそのコードが必要なのか」「どんな仕組みで動いているのか」を理解することができました。 トレーニングの成果 参加前の私は git と github の違いすらわからないレベルでした。しかし、トレーニング終了の2ヶ月後に1人で参加したハッカソンで企業賞をもらえるレベルに成長していました。Buildトレーニングは独学で伸び悩んでいた私に大きな成長を与えてくれました。 Build インターンについて 選考の話 構築した出品APIが動作確認のテストに通ったトレーニング参加者は、1ヶ月間のBuildインターンに進むことができます。 基本的には、トレーニング終了後に提出するアンケートに回答した希望ポジションと部署を前提に選考が進みます。 また、就業型インターンに応募して不合格となった場合でも、再度Buildインターンへ応募することも可能だそうです。 Buildインターンの選考では30分程度の面接が1回設けられます。この面接は開発経験などの深掘りというよりも、配属先のエンジニアマネージャーさんとインターンへの参加意欲の確認を行いました。 配属先 私はメルカリのお客さまのお問い合わせ管理システムを構築しているContact Centerチームにバックエンドエンジニアとして配属されました。 取り組んだこと 現状のシステムでは、お問い合わせに対する自動返信や通知メールの文言がハードコードされており、文言の変更コストがかかることが課題でした。私は、その文言をデータベースから取得できるようにするタスクに取り組みました。 将来的にこの機能を拡張させ、管理画面から文言に変更を加えられるようにすることで、実際にお問い合わせに対応する非エンジニアの方でも文言の変更が可能となり、運用コスト削減や、変更スピードの向上が期待できます。 大きく分けて3つのフェーズでタスクに取り組みました。 1. DB設計 どの文言をデータベースに移行するかを、文言が使われる場面や、その変更可能性も考慮しながら検討しました。 最初は深く考えずに、既存の他のDB設計を参考に設計していました。チームの方に設計をレビューしていただいた際、なぜそこでこの制約を入れたのかという質問に対してすぐに答えられなかった経験から、自分の設計根拠の甘さに気づくことができました。 DB設計のみならず、設計や方針に唯一の正解はなく、エンジニア間で議論する中で自分一人では気付けなかった点に気づくことで、最適な解が導き出されることを学びました。議論を円滑に進めるためにも、常になぜ自分がその方針が良いと思ったのか、他に考えられる方針はないのか比較検討した上で、設計の意図や根拠を明確にもつ重要性を学びました。 2. DBへの文言挿入 実際にデータベースへ文言を挿入する段階では、移行する大量の文言を既存の文言と一言一句のずれも起きないよう、正確なクエリを作成する作業が発生しました。 また、Spanner CLIの仕様上、文言に含まれる空行をSQL文の終了と認識してしまうため、全ての空行を改行文字に変更する必要があり、非常にミスが発生しやすい作業でした。作成したSQL文の最終確認は大変骨の折れる作業でした。最終確認をしていただいたチームの方々、日常の忙しい業務の最中、時間を割いていただいてありがとうございました。 3. 文言取得の実装 詳細設計の話 実装時の大幅な手戻りを回避するため、詳細設計を詰めてから実装に入りました。詳細設計を立てるには、5年分のコンテキストがある既存コードの流れを短期間で把握する必要があり、最も時間がかかりました。また、プロジェクト初期ほど見積もりの誤差が大きくなるという、「 不確実性コーン 」のお話が興味深かったです。 最初に私が立てた詳細設計は見積もりが甘く、もう少し内容を詰めるようレビューをいただきました。その結果、後の実装工程では迷わず手を動かすことができました。開発プロセスの中で設計を疎かにするとその分の見積もりの誤差が実装に引き継がれてしまうということを身をもって学ぶことができました。 チームでは「Architecture Decision Record」と呼ばれる意思決定記録に設計方針を残していました。「なぜ、そういう設計になったのか」や「他の案はあったのか?」などの議論や決定事項を記録しておくことで、今後新しい機能を実装しようとした時に、過去の設計をそのまま使用できたり、参考にして拡張することができる利点があると教えていただきました。ハッカソンのチーム開発経験とは比べものにならない「現場のチーム開発」を学ぶことができました。 テストコードの話 テストコードを組み立てるのは今回が初めてでした。今までは正常に動作していることを確認するだけで満足していましたが、コードの品質や保守性を高める重要な手段であることを学びました。Go特有の「テーブル駆動テスト」や「テスト駆動開発」、正常に値が返されるかだけではなく、渡す値などを変えた時、エラーがきちんと返されるかなど、「幅広いテストケースの想定」が必要であることを学び、テストコードの奥深さを知りました。 Goの話 Contact Centerチームではバックエンド開発言語にGoが採用されていました。Goに触れるのは今回のインターンが初めてだったため、開発を進めながら多くのGo独自の構文や考え方を学べました。 全体を通して学んだこと エンジニアの仕事 インターンを通して実務に入ったことで、エンジニアに求められることはコードを書く力だけではないことを強く実感しました。特に印象的だった学びが、以下の3つです。 1つ目は、「プログラミングは、コードを”書く”時間よりもコードを”読む”時間の方が多い」だということです。機能を新しく追加するにしても、まずは既存のコードを読み解いて、どこをどう変更すべきかを理解する必要があります。 2つ目は、開発には期限があり、その中でいかに優先順位をつけてタスクを進めていくかも仕事では求められるということです。チームに進捗を伝える際も、「まだ終わってません」と伝えるのではなく、「現状で〜%進んでいます。ここまでに〜日かかったので、残りも同じくらいのペースで進めば、あと〜日程度かかりそうです」というように、進捗と予測をセットで伝える報告の仕方がチームとしての動きやすさにもつながるというお話もお聞きし、勉強になりました。 3つ目は、仕事をチームで進める上で技術力と同じくらい、「伝える力」が大切ということです。PRを作成する際もレビューする側の目線に立って、意図や背景を丁寧に書くことであったり、1on1での質問においても、ただ「ここがわかりません」と言うのではなく、「〜について調べたり、〜を試したけれど、この時点で詰まっています」というふうに、自分の思考プロセスを整理して伝えることで、より的確なアドバイスをもらえると感じました。 アーキテクチャ アーキテクチャに関する話の中で、メルカリがモノリシックな構成からマイクロサービス化へと移行していった背景や、その過程で起きた技術的・組織的な変化について伺いました。 特に印象的だったのは、マイクロサービス化によって各モジュールが自律的に機能するようになったことで、開発チームもそれぞれが独立して動けるようになり、組織構造そのものにも変化があったという点です。 また、既存コードの流れを把握する際に、「ドメイン駆動設計」や「クリーンアーキテクチャ」といった考え方も教えていただきました。 こうした設計思想は、単に「きれいなコードを書く」ためではなく、長期的に安定したシステムを作るための考え方であることを学びました。 メルカリ文化 社内勉強会 社内勉強会も活発で、私はOpenAI社の講師によるトレーニングプログラムに参加しました。会話をするAIを、「指示、知識、アクション」の観点から細かく設定できるカスタムGPTの活用事例を実演形式で学びました。 普段からノンカスタムGPTは回答の情報量が多く、何が質問に対する回答の本質なのか見失いがちだったため、「なるべく不必要な部分を削ぎ落とし、シンプルで初学者にとってわかりやすい説明を心がけること」、「より人間らしく、後輩から慕われるようなエンジニアとして振る舞うこと」を指示したカスタムGPTを作成しました。インターン期間中このGPTへの質問でよりスピーディーに疑問を解消しながら開発できたこともあり、実際に社内勉強会での学びの恩恵を受けました。こうした様々な勉強会に参加できる環境が非常に魅力的であると感じました。 開発手法 チームでは「スクラム」という開発手法が取り入れられていました。スプリントと呼ばれる数週間の単位で開発期間を短く区切り、毎回「今回のスプリントではこれをやる」という目標をチームできめてから開発に入る形でした。 スプリント期間中は毎朝のDaily Scrum(朝会)でチーム内で進捗や課題を共有しあい、タスクの進行を常に可視化しながらチーム全体の開発を前に進めていたことが印象的でした。 その他 インターン期間中、Contact Centerチームの方々やトレーニングで担当していただいたメンターさんと何度かランチに行かせていただきました。「キャリアの話」、「日本人チームと外国人チームの違い」、「メルカリの昔と今」、「エンジニアの成長ステップ」といったテーマについて、実際に働くエンジニアの方々から直接お話を伺うことができました。普段なかなか聞くことができないような、リアルな現場の話や考えに触れることができたことで、自分自身のキャリアや働き方を考えるきっかけにもなり、大変貴重な学びとなりました。 終わりに メルカリと配属先チームの皆さんへ Build@Mercariという成長機会を提供してくれたメルカリ、そしてインターンで受け入れてくださったContact Centerチームのメンターさんをはじめとするメンバーの皆さんに心から感謝の気持ちを述べたいと思います。短い期間でしたがここには書ききれないほどたくさんのことが学べました。本当にありがとうございました。 これから参加しようと考えている方へ ほぼゼロだった私がここまで多くのことを学び成長することができたのはBuild@Mercariのおかげです。もし今の自分のスキルに自信がなくても、エンジニアとして成長したいと考えているなら、ぜひBuild@Mercariへ参加して欲しいです。また、Buildインターンや就業型インターンで実際にメルカリのサービスに触れることで得られる学びは非常に大きいです。ぜひBuildトレーニングで終わらずに、有給インターンシップまで進んで欲しいです。 ※この体験記は2025年度(今年度)のプログラム内容です。来年度以降のプログラムにおいては内容が変更になる可能性がありますので、ご了承ください。
メルカリハロで QA Engineering manageをしている @____rina____ です。 本記事では、プロジェクトチームで実施したオフサイトについて、スクラムマスターとしてワークショップデザインを担当した経験を共有します。 リモートワークも継続する中で、対面でのオフサイトをどのように設計し、初回参加者への配慮をどのように実践したかについて詳しく解説します。 この記事から読者が学べること: 長期プロジェクトの効果的なふりかえり手法(タイムラインふりかえり) AIを活用したワークショップデザインの実践例 初回参加者への配慮と心理的安全性の確保方法 5グラウンドルールを活用した質の高い議論の実現方法 対面でのチームビルディングの重要性と効果 リモートワーク環境でのコミュニケーション技術的課題と解決策 アナログ手法による対面ワークショップの効果と重要性 執筆者自身の学び: スクラムマスターとしてワークショップデザインを担当した経験を通じて、参加者の心理的安全性を確保することの重要性を改めて実感しました。特に、初回参加者への丁寧な説明や視覚的な資料の活用、段階的な進行が、ワークショップの成功に直結することを学びました。また、AIを活用した効率的なワークショップ設計の可能性も実感でき、人間ならではの創造性や配慮と組み合わせることで、より効果的なワークショップを設計できることを確認しました。 開催概要 今回実施したのは、メルカリハロで事業者向けサービスを開始するにあたり、事業者から手数料を徴収する仕組みを構築するプロジェクトチーム向けのオフサイトです。このチームのメンバーが、福岡市内の会場に集まり、5時間にわたってオフサイトを開催しました。普段はリモートで業務を進めているメンバーですが、この日は全国からメンバーが一堂に会し、対面ならではの熱量と一体感を感じながら、プロジェクトのこれまでとこれからについてじっくりと語り合う貴重な時間となりました。 参加者はPM、エンジニア、EM、デザイナー、QAから10名を超えるメンバーが参加し、初回参加者も含めて多様なバックグラウンドを持つメンバーが集まりました。 背景・目的 今回のオフサイトを企画した背景には、長期にわたる手数料プロジェクトをふりかえり、今後の改善やチームの連携強化を図りたいという思いがありました。リモートワークも続く中、日々のコミュニケーションはどうしてもテキストやオンライン会議に偏りがちです。だからこそ、対面で集まり、普段は話せないような深い議論や、カジュアルな交流を通じて、チームとしての結束力を高めることが不可欠だと考えました。 手数料プロジェクトでは私がスクラムマスターを務めており、今回のオフサイトはワークショップデザインから全体の進行まで、一貫して設計・運営を担当しました。特に意識したのは、初回参加者が安心して参加できる環境を整えることでした。 ワークショップデザインの工夫 AIを活用したアジェンダ作成とアイスブレイク設計 今回のオフサイトの準備段階では、AIを積極的に活用しました。まず、ワークショップ全体のアジェンダ作成において、AIに手数料プロジェクトの特性や参加者の構成、目的などを入力し、最適な進行スケジュールの提案を受けました。AIが提案した時間配分やセッション構成をベースに、実際の参加者数や会場の制約を考慮して調整を加えることで、効率的で効果的なアジェンダを作成できました。 特に印象的だったのは、アイスブレイク用のクイズ作成です。AIに福岡の文化や目にする予定の建築物に関する問題を生成してもらい、参加者の滞在をもっと楽しくする内容にしました。 初回参加者への配慮:丁寧なチェックインと説明 ワークショップデザインにおいて最も重要視したのは、初めてワークショップに参加するメンバーへの配慮でした。参加者の中には、付箋を使ったワークショップや、グループディスカッションに不慣れな方もいました。そのため、各セッションの開始時には必ず丁寧な説明を行い、参加者が迷わないよう配慮しました。 各セッションでの具体的な配慮 タイムラインふりかえりでは、具体的な手順を視覚的な資料とともに説明しました。グルーピング作業では、抽象的な指示ではなく具体的な例を示すことで、参加者が迷わずに作業を進められるよう工夫しました。 各セッションの開始時には必ず目的、手順、期待する成果物を明確に伝え、質問しやすい雰囲気を作ることで、参加者全員が安心してワークショップに参加できる環境を整えました。 当日の流れ オフサイトは、参加者全員が最大限に集中し、活発な議論ができるよう、綿密にデザインされたプログラムで進行しました。 アイスブレイクの意味と目的の説明 ワークショップの冒頭では、まず「アイスブレイクとは何か」「なぜアイスブレイクが必要なのか」について、参加者全員に丁寧に説明しました。この配慮を特に重視したのは、私自身が過去にワークショップに参加した際、突然ゲームが始まって「これをする意味がよくわからない」と混乱した経験があったからです。 アイスブレイクが単なる場を和ませるための時間ではなく、その後の議論の質を左右する重要な要素であることを理解してもらうため、以下の4つの目的を明確に伝えました: 参加者同士の緊張をほぐす : 初対面や久しぶりの対面で生じるぎこちなさを解消し、心理的安全性を高める 場の雰囲気を明るくする : ポジティブな空気を作り出し、その後の議論が活発になる土台を築く 親近感を高める : 共通の体験を通じて、お互いへの理解を深め、チームとしての繋がりを強化する 集中力を高める : 軽いアクティビティを通じて、参加者の意識をオフサイトのテーマへと自然に引き込む この説明により、参加者はアイスブレイクの重要性を理解し、積極的に参加することができました。この事前の配慮が、次のアイスブレイクセッションでの自然な参加につながりました。 アイスブレイク:緊張をほぐし、一体感を育む時間 アイスブレイクとして、事前にAIを活用して作成した福岡にちなんだクイズからスタートしました。アイスブレイクの目的は、参加者同士の緊張をほぐし、場の雰囲気を明るくし、親近感を高めることです。お互いの意外な一面を知るような質問を投げかけることで、笑い声が絶えない和やかな雰囲気を作り出すことができました。 特に、ワークショップ形式に不慣れなメンバーからも自然な笑い声が聞こえ、緊張していた表情が和らいでいく様子が印象的でした。このアイスブレイクを通じて、参加者全員が同じ土俵に立ち、次のセッションに向かう準備が整いました。 5グラウンドルールの共有 アイスブレイクの後、ワークショップを円滑に進めるための「 5グラウンドルール 」を参加者全員で共有しました。このルールは、今年私が参加した社外イベントで講師の方が使用していたもので、運営者として参加した私がその効果を実感し、今回のオフサイトで採用することにしました。 ほめる 聴く 受けとめる 待つ 愉しむ 実際に体験者として参加したことで、これらのルールが参加者の心理的安全性を高め、質の高い議論を生み出す効果を実感できました。今回のオフサイトでも、参加者全員が同じ価値観でワークショップに臨むことができました。 タイムラインによるプロジェクトのふりかえり アイスブレイクで場が温まり、「5グラウンドルール」で参加者全員の認識がそろったところで、メインコンテンツである「タイムラインを使ったプロジェクトのふりかえり」へと移りました。手数料プロジェクトは長期にわたるため、過去の出来事を時系列で整理し、共通認識を持つことが非常に重要だと考えました。 ステップ1:できごとと感じたことを書く まず、ロール上の模造紙にプロジェクトのタイムラインを引き、各メンバーが印象に残っているできごとや感じたことを付箋に書き出し、該当する時期に貼り付けていきました。このプロセスでは、まず事実としての「できごと」を書き出し、それに対して「感じたこと」を複数書き出すという明確な手順を示しました。 事前準備として、これまでの議事録をNotebookLMに読み込み、音声出力サマリーを作成しました。このサマリーを参加者全員で聞くことで、プロジェクトの全体像を共通認識として持つことができ、より具体的で深い議論につながりました。 付箋には色分けを採用し、できごとは黄色、感じたことはその他の色で分類することで、視覚的に情報を整理しやすくしました。アナログな手法だからこそ、参加者が直接手を動かして情報を整理でき、デジタルでは得られない物理的な体験を通じて、より深い議論が生まれました。 ステップ2:付箋を貼る タイムライン上に、重要なマイルストーンを設定し、各参加者が該当する時期の付箋を貼り付けていきました。 このステップでは、できごとについて簡単に説明する時間も設けました。これにより、他のメンバーが知らなかった出来事や、異なる視点での捉え方を共有することができ、プロジェクトの多面的な理解が深まりました。 特に印象的だったのは、書いた人が読み上げることで、「これもあった」「これもあった」と次々と思い出が湧き上がり、付箋がどんどん増えていったことです。この段階で参加者全員の熱量が一気に上がり、ワークショップの雰囲気が大きく変わりました。 ステップ3:グルーピングする タイムラインに沿って書き出された付箋を、関連性のあるもの同士でまとめる作業を行いました。同じような課題や、同じ時期の出来事、同じチームに関連するものをグループ化することで、プロジェクト全体の課題がより明確になりました。 ステップ4:話を深掘りしたい付箋にシールを貼る グルーピングされた付箋の中から、さらに詳しく議論したいトピックや課題にシールを貼ることで、優先順位付けや深掘りの対象を明確にしました。このプロセスを通じて、プロジェクトの成功体験や課題、転換点などが視覚的に明確になり、参加者全員が同じ視点でプロジェクトの全体像を把握できるようになりました。 グループディスカッション タイムラインのふりかえり後、抽出されたトピックを基にグループに分かれ、グループディスカッションを実施しました。各グループには45分間の時間を設け、特定の課題やテーマについて深掘りし、具体的な課題の抽出や次のネクストアクションを導き出すことに注力しました。 ネクストアクションの抽出と優先度決め グループディスカッションで出された多くのアイデアや課題の中から、最も重要で実行可能な「ネクストアクション」を特定し、その優先順位を決定しました。この段階では、各アクションの実現可能性や影響度を考慮し、チーム全体で合意できる優先順位を設定することができました。 オフサイト自体のふりかえり 今回のオフサイトがどれだけ効果的だったかを評価するため、「ふりかえりのふりかえり」も実施しました。早めに全員がパソコンを閉じて、オフサイトに集中できる環境を作ったことや、福岡という場所を選んだことで普段参加が難しいメンバーも参加できたことが、特に良かった点として挙げられました。長時間の開催にも関わらず、議論が途切れることなく活発に進行できたのは、リモートワークでは実現困難な対面ならではの集中力と一体感の賜物でした。 まとめ 今回のオフサイトは、手数料プロジェクトの現状や課題を整理し、今後のアクションにつなげるだけでなく、チームとしての結束力を高める貴重な機会となりました。スクラムマスターとしてワークショップデザインを担当した経験は、今後のプロジェクト運営にも大きな学びとなりました。 おもな成果: 長期プロジェクトの効果的なふりかえり手法(タイムラインふりかえり)の実践 AIを活用したワークショップデザインの効果検証 初回参加者への配慮と心理的安全性の確保による質の高い議論の実現 5グラウンドルールを活用したチーム全体の価値観統一 対面でのチームビルディングによる信頼関係の強化
メルカリハロで QA Engineering manageをしている @____rina____ です。 昨年2024年11月に開催された Agile Testing Days とそこで参加したワークショップについて紹介します。 Agile Testing Daysとは何か Agile Testing Days とは、ドイツのポツダムで毎年開催されているカンファレンスです。参加者層はテスター、アジャイルテスター、QAエンジニア、テストリード、テストオートメーションエンジニアといったQAやテストに関するエンジニアに加え、ディベロッパー、ソフトウェアエンジニア、アジャイルコーチ、スクラムマスター、プロダクトオーナーやチームリードなど様々な方が対象のカンファレンスです。今回参加した日本語話者の参加者は数名だったこと、ヨーロッパの参加者が多かったようで、コミュニケーションは英語でおこないました。 Agile Testing Daysでは、1日のワークショップと3日間のカンファレンスで構成されています。カンファレンスでは、キーノートをはじめ、セッション、パネルディスカッション、ワークショップなどが開催されます。また、セッションの合間にはコーヒーブレイクやランチなどもが提供され、朝のジョギングから夜の音楽イベントまで、丸一日イベントを楽しむための仕掛けがたくさん用意されていました。 カンファレンス会場はアジャイルテストの第一人者とも言える Lisa Crispin に会うことができたり、たくさんの有識者に会えたり、同じ悩みを持ったエンジニアと交流できたりし、とても刺激的なイベントでした。 スピーカーはシニアエンジニアに限らす、はじめて登壇される方のセッションなど、幅広い登壇者のたくさんの発表を聞くことができました。 Getting a grip on exploratory testing with test charters Ewald WassinkSconewile氏とRob van Sttenbergen氏による、探索的テストのワークショップです。探索的テストのワークショップは国内でも時々見かけるようになりました。 このワークショップはいくつかのテーブルに分かれてグループワークをしました。私のグループは4名で、2名はドイツからの参加で、英語でコミュニケーションをしました。 次にワークショップの流れを紹介します。 ワークショップの流れ 以下のような流れでワークショップをデザインしていました。 講師の自己紹介とワークショップの説明 フリースタイルで探索的テストをする 2で見つけた不具合の紹介 テストチャーターを利用した探索的テスト グループディスカッションと発表 登壇者の考案したフレームワークを利用した探索的テスト グループディスカッションと発表 1. 講師の自己紹介とワークショップの説明 講師2人の自己紹介がありました。海外のキーノートなどは国内でも見る機会がありましたが、自己紹介をしない印象があったので、少し意外でした。彼らのバックボーンなどを知ることができました。 2. フリースタイルでテストを実行する 以下のURLにアクセスして、個人でフリースタイルでテストをしました。 https://www.eviltester.com/page/tools/thepulper/ 題材はWebサイトで、個々に不具合を出していきます。テスト設計はせずに、経験ベースでテストを実行します。 HTMLエンコードが行われていないため、入力された値がそのままHTMLとして表示される不具合 HTMLエンコードをしていないために、入力値とinput formの表示が変わってしまう不具合 日付を入力する欄に大きな数字をいれたためにNumber Format Exceptionが発生してしまった。これを不具合とするかどうかは仕様次第 3. 発見された不具合の共有 参加者全員で、探索的テスト中に発見した不具合について発表しました。私は自身が報告しようとしていた不具合が、既に他の参加者によって報告済みであるか確信が持てませんでした。そこで、念のため隣席の方に不具合の画面を見せながら、「このバグについて報告しようと思っているのですが、既に発表された方はいますか?」と確認しました。すると、その方は私の発表をフォローしてくださり、安心して発表に臨むことができました。 4. 探索的テストとテストチャーターの解説 ここでは、探索的テストとは何か、そしてテストチャーターとは何かについて解説がありました。講師からは、著名なソフトウェアテスト研究者である Cem Kaner 氏の言葉を引用しつつ、「テストチャーターは、テストのゴールを明確にするための計画である」という説明がありました。 以下はテストチャーターの例です。 define your goal; charter template target where are you exploring? resources what resources do you need ? information what kind of information do you want to discover 5. テストチャーターを用いた探索的テスト 隣の席の方とペアになり、先ほどのテスト対象のWebアプリケーションに対して、付箋を使ってテストチャーターを作成しました。ペアワーク後、グループ全体でそれぞれのペアがどのような考えでテスト項目を選び、テストチャーターを作成したかを共有し、議論しました。 6. BRIEFフレームワークの提案 講師から、Elizabath Hendricson氏が提唱するテストチャーターについての説明がありました。私はテストチャーターについて、彼女の著書で知ってはいたものの、改めて説明を受けることで、自身の抱いていた違和感が明確になりました。それは、受け入れ条件(Acceptance Criteria)を書く際、つまりテスト設計時に、情報やテスト観点から記述している点でした。 そして、講師らが提唱する新しいフレームワーク「BRIEF」の説明がありました。 BRIEFは、Behavior(行動)、Result(結果)、Impediments(障害)、Expectation(期待)、Feeling(感情) の頭文字を取ったものです。このフレームワークを用いることで、振る舞いを軸としたテストチャーターを作成することができます。最後に、このBRIEFフレームワークを使ってペアワークを行い、その後、他のグループと入れ替わってディスカッションを行いました。 ペアワークで使った付箋 このワークショップで特に素晴らしいと感じたのは、講師自身が考案したフレームワーク「BRIEF」を活用していた点です。探索的テストのワークショップでは、手を動かす演習や参加者同士の意見交換、テストチャーターの作成などはよく行われます。しかし、今回のように新しいチャーターのフレームワークを実際に試す機会は初めてで、非常に有意義でした。個人的にも、BRIEFのフレームワークは普段私がテストを考える際の思考回路に近く、とてもしっくりきました。 Journey From Manual to Automation Pythonic Tester 続いて、Mateusz Adamczak氏とMichal Pilarski氏による、テスト自動化の初学者を対象としたワークショップについてご紹介します。このワークショップはハンズオン形式で行われ、参加者は自身のPCを使って実際に自動テストを作成しました。 ワークショップの流れ ワークショップでは以下のような流れでワークショップをデザインしていました。 必要なツールとリポジトリのダウンロード Scrachを使ってアニメの作成 Pythonのコードにコンバートする テストコードの作成 グループディスカッションと発表 登壇者の考案したフレームワークを利用した探索的テスト グループディスカッションと発表 こちらもひとつずつ紹介します。 1. 必要なツールとリポジトリのダウンロード GitLabのリポジトリ、Python、JetBrainsをダウンロードします。 GitLab – GitLab.com – Files · ATD_workshop_manual2auto · Michal Pilarski / python_kids · GitLab Python.org – Python.org JetBrains – PyCharm – https://www.jetbrains.com/pycharm/download/download-thanks.html?platform=macM1&code=PCC 2.Scratchを使ったアニメーション動画作成 Scratchを使ってアニメーション動画を作成しました。最初に講師が画面共有しながら作り方を説明し、参加者はそれに倣って作業を進めました。Scratchは、子供向けのプログラミング学習ツールとして日本でも人気があり、直感的な操作でアニメーションを作成できます。そのため、プログラミング初学者でも問題なく取り組むことができました。講師の指示に従い、キャラクターを前後に動かしたり、音を鳴らしたりといった簡単な動作を作成しました。 3. Pythonコードへの変換 Scratchで作成したアニメーションが完成したので、次はそれをPythonのコードに変換します 変換に必要なコードは事前に用意されていました。 まずターミナルで python -V を実行してPythonのバージョンを確認し、次に pip install -r requirements.txt を実行して必要なライブラリをインストールします。その後、Scratchで作成した kitty.sb3 ファイルを変換することで、Pythonのコードが生成されました。 講師から基本的なPythonコードの説明があり、その後は参加者自身でコードの実装を行いました。私の作成したアニメーションには背景がなかったため、生成されたコードの6行目をコメントアウトする必要がありました。 4. テストコードの作成 いよいよテストコードの作成です。先ほどコンバートしたコードに対してテストコードを実装します。 講師が簡単なテストのサンプルコードを紹介してくれました。このサンプルコードは、Scratchで作成したアニメーションの動きをテストするもので、pytestライブラリを使用していました。例えば、キャラクターが指定された位置に移動することを検証するテストや、特定の音が鳴ることを検証するテストなどがありました。講師がコードを画面共有しながら説明してくれたので、私たちも自身のPCで同じようにコードを書き写しました。エラーが発生した箇所は、エラーメッセージを読みながら修正したり、講師に質問したりして解決しました。その後、ターミナルでpytestコマンドを実行してテストを実行し、テストが成功することを確認しました。詳細なテストコードについては、ぜひGitLabのリポジトリ([GitLabのリポジトリURL])にアクセスして確認してください。ワークショップで使用したすべてのテストコードや関連資料が公開されていますので、テストコードの全体像を把握したり、実際にテストを実行したりすることができます。 このワークショップの特筆すべき点は、まず初学者の参加者が実際に動くプログラムを作成できたことです。Scratchを活用することで、参加者が動くプログラムを自ら作れるようにするというアイデアは非常に素晴らしいと感じました。通常の自動テストに関するハンズオンでは、多くの場合、事前に用意されたプログラムに対してテストコードを書くことが一般的です。しかし、今回のワークショップでは、動くものをゼロから自分で作り、そのテストコードまで書くという一連の流れを、数時間という短い時間で体験できる点が素晴らしいと思いました。ワークショップの時間内ですべてのテストコードを実装することはできませんでしたが、参加者全員が何らかの形でテストコードを実装することができました。初学者向けにScratchでアプリ作成を体験させ、それをPythonコードに変換し、自身が作成したプロダクトコードに対してテストコードを実装するというワークショップのデザインは、本当に素晴らしいと感じました。 おわりに 今回の記事では参加した2つのワークショップについてご紹介しました。どちらのワークショップも、短時間で成果を実感できるような工夫が凝らされており、その内容とともに大変勉強になりました。ワークショップのオーナーの方々には、直接お会いして感謝の気持ちをお伝えし、ぜひこの素晴らしいセッションを日本にいるみんなにも広めたいので、サイトのURLなどを公開しても良いか確認させていただきました。 私自身、長年英語に苦手意識があり、ワークショップへの参加は、他の参加者や講師の方々にご迷惑をかけてしまうのではないかという不安がありました。しかし、同じ志を持つ仲間たちと、互いの伝えたい内容を理解しようとする姿勢に触れ、そのうちの一人とは数週間後に私の住む街へ偶然旅行に来るとのことで、食事の約束までできました。また、参加者の中には第二外国語として英語を学んでいる方もいたようで、みんなが真剣に耳を傾けてくれる姿勢が印象的でした。 結果として、私自身も非常に楽しく学習できる時間を過ごすことができました。同じグループになった参加者の方々も、とても親切で助けられました。私は英語が得意ではありませんが、Agile Testing Daysではキーノートをはじめ、数多くのセッションやワークショップ、パネルディスカッションが開催され、登壇者の経験に基づいた発表が多く、共感できる内容が数多くありました。 セッション以外の時間にも食事が提供され、参加者同士が楽しく交流できる場が設けられており、3日間を通して多くの方々と話すことができました。 今年の Agile Testing Daysの参加受付 も始まりました。このブログをきっかけに、読者のみなさまがワークショップを試してみたり、海外のカンファレンスへの参加に挑戦してみようと思っていただけたら、とてもうれしいです。
はじめに こんにちは。2025年度のBuild@Mercariに参加して、現在はメルカリのCS Tool Teamでインターンをしている@Aokaと申します。この記事では、私がBuild@Mercariに参加した感想や成長したことについて書いていきたいと思います。 Build@Mercariって何? Build@Mercariとは、これまでさまざまな事情で機会が巡ってこなかった方、特にSTEM分野・IT分野におけるマイノリティである性自認が女性の方々を中心として、スキルトレーニングとインターンシップの機会を提供するプログラムです。 トレーニングの話 選考 Build@Mercariの選考は書類とコーディングテストの結果で進みます。他の多くのインターンシップとは異なり、面接がないのが特徴的でした。 書類審査では、これまでの自分の経験やBuild@Mercariに参加したい理由などを記入しました。コーディングテストについては、プログラミング言語の基礎文法を理解していれば解ける問題が中心で、競技プログラミングのような高度な問題ではありませんでした。 選考は志望理由とコーディングテストの結果を総合的に判断しますが、志望理由が重要視されているそうです。 初日のオリエンテーション 初日のみオフラインでの開催で、メンターや同じチームの参加者とオフラインで交流する機会がありました。また、GitHubを使った課題をみんなで進めて、使い方に慣れることができました。オフラインで交流できたことが二週間のトレーニング期間を通じて心の支えとなり、モチベーションを維持することができました。 トレーニングでやったこと トレーニングではソフトウェアエンジニアリングに必要な基礎知識を一通り学びました。 トレーニング期間中は、5〜6人のチームにそれぞれメンターの方がついてくださる形で、各自が課題に取り組みました。課題の内容は以下の通りで、各STEPを進めながら、最終的にはメルカリのような商品を登録できるWebアプリを作りました。 STEP1 Git STEP2 Setup environment STEP3 Algorithms and Data Structures STEP4 Develop API STEP5 Database STEP6 Writing Tests STEP7 Docker STEP8 Continuous Integration(CI) STEP9 (Stretch) Frontend STEP10 (Stretch) Run multi service EXTRA1 (Stretch) Data Analysis トレーニング内容は公開されており、以下のレポジトリから確認できます。 https://github.com/mercari-build/mercari-build-training/tree/main つまづいた時にメンターの方々にSlackで質問したり、課題の各STEPごとにレクチャーをしてくださったりと、手厚いサポートのおかげで、最後まで楽しく開発を続けることができました。 学んだこと プログラム期間中はたくさんのことを学びましたが、特に以下の知識がついたと思います。 Git, Githubを使ったチーム開発の基礎 Backend開発の流れ DockerやCIなどインフラの知識 このトレーニングを通じての一番の大きな成長は、開発することに対する心理的なハードルが下がったことだと感じています。参加する前は、フロントエンドの開発しかしたことがなかったのですが、フロントエンドからインフラまでの基礎知識を身につけたことにより、新しい技術について学習する際や、開発でつまづいた時にどの領域の知識を深めていけばいいのか判断できるようになりました。 また、プログラムの参加者はUdemy Businessを1年間無料で使うことができます。はじめて学ぶ知識が多いなか、基礎から体系的に学習することができるので、非常に役にたちました。 難しかったこと 実装を始める前に、新しい概念を理解する必要があり、なぜこの技術が必要なのかというところから理解しなければならなかったことが大変でした。理解が浅いまま進めてしまうと、後でつまずくことが多かったため、基礎知識を身につけるためにUdemyの動画を視聴したり、AIとの壁打ちを通じて概念を整理したりして理解しながら進めました。 特に、STEP4のAPI開発では、Python言語を使用してRESTful APIを実装したのですが、デバッグ作業に苦労しました。エラーが発生した際に、どの部分でなぜエラーが起きているのかを特定するのが難しく感じました。しかし、この経験を通じてデバッグスキルの重要性を痛感するとともに、バグに対する耐性もついたと思います。 また、STEP7のDockerの部分が大変でした。初めてコンテナ技術に触れたため、仮想化の概念から始まり、イメージとコンテナの概念、Dockerfileの書き方まで、すべてが新しい知識でした。特に、依存関係の管理は理解するのに時間がかかり、何度もエラーと向き合いながら少しずつ実装を進めました。また、公式ドキュメントを読む大切さも学びました。はじめはとても読みづらく感じましたが、理解するのに大変役に立つことを実感しました。 自身の変化 プログラムを通して、技術力の向上はもちろんのこと、様々な方との関わりを通じて自分自身に大きな変化があったと感じています。 参加者の方々のバックグラウンドは多様で、情報系学部の人に限らず、文系学部や美術系学部の人、また高校生から社会人まで幅広い年齢層の方がいらっしゃいました。私のようにWeb開発が初心者の方も多かったです。 私がこのプログラムを修了できた最も大きな要因は、一緒に切磋琢磨し合える仲間がいたからだと感じています。お互いに教え合いながら頑張る雰囲気がとても心地よく、他の参加者の方々の進捗は良い刺激になりました。 また、プログラムの初日には社員の方々のキャリアに関するプレゼンテーションがあり、直接質問できる機会もいただきました。出産や子育てと仕事の両立、転職に関するお話など、貴重なお話を聞くことができ、自分自身のキャリアについて深く考える時間となりました。 Buildインターンの話 選考 トレーニング期間終了後、一定の基準を満たした参加者は、インターンシップへの応募資格を得ることができます。 選考プロセスでは面接が実施され、主にトレーニングを通じて得た学びや気づき、これまでの技術的な経験、そしてメルカリのバリューに対する理解や共感について質問されました。 選考通過後には、実際のインターンシップ開始前に事前面談の機会が設けられています。この面談では、配属予定のチームについての説明や、不安な点の相談などができるため、安心してインターンシップをスタートすることができました。 やったこと タスクは、カスタマーサポート業務で使用される社内ツールであるCS ToolのPHPで記述されている既存エンドポイントをGo言語とマイクロサービスアーキテクチャで再構築するというものでした。 開発の背景として、CS Toolの多くの機能は古いモノリスなアプリケーションとして運用されています。古いBackendはPHPで書かれており、現在これを保守性の観点などから、新しいマイクロサービスアーキテクチャに移行する取り組みが進められています。 現在CS Toolでは、開発方針として既存機能の移行作業を進めながら、新機能については新しいサービスで開発するというルールがあり、今回私は前者を担当しました。 学んだこと 新しい技術(Go, Kubernetes, gRPC) アーキテクチャの概念が実際のサービス運用でどのように活用されているかを理解することができました。 Test QA Releaseの工程 実際の開発現場での品質管理プロセスを経験できました。単体テストの書き方から、QAのケースの作成と実施、リリースまで一連の流れを学ぶことができました。 コードの可読性を考える 自分だけが理解できるコードではなく、チームメンバー全員が理解できるコードを書くことの重要性を学びました。変数名や関数名の命名、レポジトリ内でコードの一貫性を保つことなど実務で重要なポイントを学ぶことができました。 コードの拡張性を意識する 将来的な機能追加や仕様変更に対応しやすいコード設計について学びました。将来的に、同じエンドポイントに新しいフィルターを追加するなどする時に、コードが書きやすいか考えました。 また、自身が書く部分が既存のエンドポイントの実装と関わっていたり、使う関数が似ていたりするときに、コードを分割したり、まとめたりすることの重要性を学びました。 AIの活用 メルカリでは、AIの活用も積極的に進められており、開発にはCursorなどのAIコーディングツールを使うことができました。ただし、やみくもにAIに頼るのではなく、知識をもった上で、生成されるであろう答えを予想してから入力することで、より効果的にツールを活用することが大切だと学びました。 インターンを通じて、今まで触れる機会のなかった大規模開発ならではの知識や技術を多く学ぶことができました。特に、前述のコードの可読性の点では、コードのみならず、PRやQAシートを作成する際にも、チームの人が理解しやすく、レビューをしやすいかどうかを意識して書くことの重要性を学びました。 またコードレビューを通じて、開発に必要なコードの書き方を具体的に学ぶことができました。自分の実装がベストプラクティスかどうか、様々な視点から評価していただけました。 特に印象的だったのは、単にこの書き方の方が良いと教えていただくだけでなく、なぜその書き方が推奨されるのかという理由まで丁寧に説明していただいたことです。例えば、エラーハンドリングの実装では、ただ起こりうるエラーを処理するだけでなく、適切なログ出力やユーザーが分かりやすいエラーメッセージを考慮する必要があることを学びました。 交流を通じた学び チームでは定期的に勉強会が開催されており、チームに役に立ちそうな技術や知見を積極的に共有する文化がありました。難しい内容も多かったですが、CursorのMCP serverについての回は特に興味深かったです。 チームには地方に住んでいるメンバーも多くいましたが、普段はSlackで通話を繋いでコミュニケーションを取り、定期的に出社日を設けてオフラインでの交流機会を作ったり、チームビルディングイベントを開催したりと、チームのコミュニケーションを積極的に取ろうとされていることが印象的でした。 困った時はいつでも相談に乗っていただき、ペアプログラミングも積極的にしてくださいました。特に、課題がある時に手取り足取り教えるのではなく、私にとってよい学習機会になるようにサポートしてくださったのがとても印象的でした。 また、メンターランチや1on1での社員の方々との交流を通じ、自身のキャリアについて考えるとてもよい機会になりました。新卒入社の方のお話から、他の会社も経験された方のお話まで色々なバックグラウンドをお持ちの方との会話を通じて視野が広がりました。また、これからの大学生活に関して具体的なアドバイスをいただき、残り2年半の大学生活をどのように過ごすのか考える機会になりました。参加してくださった社員の方々に改めて感謝申し上げます。 終わりに 今回のBuild@Mercariとインターンでの経験を通じ、開発に必要な幅広い知識を身につけることができました。また、技術的な面以外でも多くの学びがありました。この半年間で得た学びを糧に、一流のエンジニアを目指して、さらに力をつけていきたいです。 このプログラム期間中、多くの方々にサポートしていただいたおかげで、ここまで成長することができました。Build@Mercariのメンターの皆さんや、インターン期間中にメンターをしてくださった @a-uki さんをはじめとするCS Toolチームの皆さんに本当に感謝の気持ちでいっぱいです。ありがとうございました。 ※この体験記は2025年度(今年度)のプログラム内容です。来年度以降のプログラムにおいては内容が変更になる可能性がありますので、ご了承ください。
はじめに 5月上旬、NATO Cooperative Cyber Defence Centre of Excellence(CCDCOE)が主催する世界最大級のサイバー防衛演習 Locked Shields 2025 が開催されました。今年は 約40 か国・約 4,000 名が参加し、17 の多国籍ブルーチームが国家レベルのICTインフラを防御するシナリオに挑みました。 昨年に引き続き、メルカリは今年もLocked Shieldsに参加しました。今回はセキュリティチームから3人のメンバーが参加しました。本記事では国際共同演習の最前線で得られた知見を共有します。 チーム構成と参加概要 今回次の3名が参加しました。 Yuto Iso:主に日本の防衛対象の全情報システムの保全および重要システムの侵害防止を担当しました。 Hiroki Akamatsu: プラットフォームおよびWebアプリケーションの脆弱性ハンティング・修正を担当しました。 Sana Okumura: 侵害兆候の分析、証跡の確認・報告を担当しました。 メルカリのメンバーは攻撃の兆候の検知・証跡確認、そして脆弱性の特定・修正を行いました。 取り組み内容 Locked Shieldsでは防衛対象の多数の情報システムが高度なサイバー攻撃を受けます。保護対象の全ての情報システムを自動的に調査する仕組みをIsoが開発し、各システムの保護・復旧にかかる労力を大きく軽減させました。これにより、脆弱性の事前特定・攻撃を受けたシステムの迅速な回復に貢献しました。 また、Locked ShieldsではAI機能を含む様々なサービス・認証基盤・ネットワーク、そしてそれらを運用するためのプラットフォームが存在していました。AIやWebアプリケーションおよびコンテナ技術に対応できる人材としてAkamatsuが複数のWebアプリケーションの堅牢化・コンテナの安全なデプロイ構築などを支援しました。 そして、攻撃者は様々な攻撃パターンで情報システムへの侵害を試みます。Okumuraは複数の証跡を確認することで正確に攻撃の影響範囲を特定・報告し、攻撃の検出から封じ込めに貢献しました。 得られた学びと成果 演習内ではそれぞれが自身の専門領域を活かしながら取り組みましたが、Locked ShieldsではOT(Operational Technology)系のシステムなど経験のない領域の攻撃に直面することもあり、学びつつ多数の攻撃からシステムを防衛しました。 また技術面以外でも、様々な専門分野の演習参加者とともに、それぞれの知識や経験を活かしながら、サイバーセキュリティ防衛における円滑なコミュニケーションと協力関係を築く方法を実践的に学ぶことができました。 さいごに Locked Shieldsは他に類を見ないほどの大規模な演習であり、今回の参加もメルカリのメンバーにとって非常に貴重な経験となりました。各メンバーがそれぞれの専門性を最大限に発揮し、各システムへの技術的な支援を横断的に行いました。自動化によるシステム調査・保全、そして複雑な環境下での迅速な脆弱性対応や影響範囲特定といった実践的なスキルを磨くとともに、新たな攻撃手法や防御戦略についても多くの学びを得ました。 特に、国境を越えた多様な専門家との連携を通じて、サイバー防衛におけるコミュニケーションと協力体制の重要性を再認識しました。刻一刻と変化する状況の中で、迅速かつ正確に情報を共有し、共通の目標に向かって協力することの難しさと、それを乗り越えた際の達成感を肌で感じることができました。 本演習で得た知見や経験は、メルカリのサービス全体のセキュリティ強化、インシデント対応能力の向上、そして将来のサイバー脅威への備えに大きく貢献するものと確信しています。メルカリは今後も、このような国際的な取り組みへ積極的に参加し、サイバーセキュリティ技術の向上と、安全・安心なサービス提供に努めてまいります。 出典: https://x.com/ModJapan_jp/status/1920770496632627647
こんにちは。SREチームの @foostan です。 弊社は2025年7月11~12日に開催された SRE NEXT 2025 に、PLATINUMスポンサーとして協賛し、ブース出展およびセッション発表を行いました。本記事では当日の様子とアンケートの収集結果をご紹介します。 ブース出展 弊社としては久しぶりのブース出展であり、私個人としては初めての経験となりました。2日に渡り200人以上の来訪者にお越しいただき、SREに関するお話をたくさんさせていただきました。ありがとうございました。このように共通の話題で盛り上がれる機会は非常に貴重であり良い経験となりました。なお我々のブースでは自由記述形式で以下の2種類のアンケートを行いました。 SREをやっていて良かった瞬間は? SREに関する業務でAIに任せたいことは何ですか? 詳細は後述しますが、昨今のAI利活用の盛り上がりはSREの領域でも大きな影響を受けており、当日はAIに関する話題が尽きることはありませんでした。 来訪者やアンケートに答えていただいた方向けにノベルティの配布も行っていました。特にロゴ入りのキーキャップは今回のイベント向けに用意したものでしたが高評をいただけて何よりでした。今後のイベントでも機会があれば配布しようと思いますのでその際は受け取っていただけると幸いです。 セッション発表 弊社の yakenji より、「複雑なシステムにおけるUser Journey SLOの導入」を発表させていただきました。我々がどのような経緯でUser Journey SLOを導入し、これをどのように運用しているのか、また今後の展望について共有しております。 なお本発表の内容は2024年末のブログ https://engineering.mercari.com/blog/entry/20241204-keeping-user-journey-slos-up-to-date-with-e2e-testing-in-a-microservices-architecture/ にも記載がありますので、よろしければこちらもご覧になっていただけると幸いです。 アンカンファレンスへの参加 当日のコンテンツはどれも興味深くさまざまな方の発表を聞いたり、各ブースを巡ってお話を伺うことでSREチームとして今後どうしていくか考えたり、またどのような技術の進歩があるのか考えたりと非常に楽しかったです。特に1日目の最後に行われたアンカンファレンスでは、具体的なテーマごとにグループに分かれてディスカッションを行うことで、各社のこれまでの経験や思いを知る良い機会となりました。 私は「SREとその組織類型」のグループに参加させていただきました。普段はエンジニアリングマネージャーとしてチームや組織編成について考える機会もあるため、SREが組織にどう組み込まれるべきか、過去の事例や現在抱えている問題など、自分の視点からでは見れなかった意見を知ることができました。組織の規模やフェーズ、置かれている状況に応じてSREの組織もそれぞれにあるべき姿が存在することを改めて認識しました。 アンケート結果 我々のブースで行ったアンケート結果をまとめましたのでご参照いただければ幸いです。各結果を同じような内容のグループに分類しそれぞれの割合を出しています。なお記載している内容は公開用に文章を変更しておりますのでご了承ください。 SREをやっていて良かった瞬間は? 合計で53件の意見をいただきました。 トラブルシューティング: 24.6% 大規模アクセスとなるイベントを無事乗り切った時や障害を迅速に解消できた時の達成感が最も多く挙げられました。難しい障害やボトルネックの特定・解消、原因不明のバグ修正などの技術的な課題を解決した時の喜びも大きいようです。また、インシデント対応フローの改善や開発チームの意識向上など、組織全体の成長を実感できる瞬間も良かった点として挙げられています。 自動化/トイル削減: 21.1% インフラや運用の自動化によって手動作業が不要になったり、高速にデプロイできるようになったことに達成感を感じたという声が多く見られました。コードによるインフラ管理やオートスケーリングの導入、リリースフローの改善などを通じて、生産性向上や自律的なシステム構築を実現できた点が良かったこととして挙げられています。 開発体験向上: 14.0% 開発者から「楽になった」といった声があった時や、生産性の向上を実感できた時にやりがいを感じたという意見が多く寄せられました。開発チーム全体のキャパシティを高める取り組みや、継続的に楽しく働ける環境づくりができていることも、良かった点として挙げられています。 ビジネス貢献: 12.3% コスト削減やリソースの最適化によって、事業への具体的な貢献を実感できたという声が挙げられました。また、ビジネスへの関心・意識の高まりなど、技術面だけでなく事業視点での行動や成果を評価する動きが広がっていることも印象的です。 データ活用: 10.5% トレースやメトリクスの導入により、システムの状態を可視化・定量化できるようになったことが大きな成果として挙げられました。オブザーバビリティの強化やSLI/SLOの導入などを通じて、計測や統計的な判断を行う文化が広がり、データに基づいた改善や意思決定が可能となってきているようです。 SREに関する業務でAIに任せたいことは何ですか? 合計で100件の意見をいただきました。 インシデントレスポンス: 22.2% インシデントの一次対応やエラー調査の自動化をAIに任せたいという声が多く見られました。またログの収集・要約や過去のポストモーテムとの類似ケースの検索、初動対応の判断支援、インシデントレポートの下書き作成といった業務など、人手による作業の負荷の軽減に期待が寄せられています。 分析/予測: 16.0% 障害やエラーの原因調査、影響範囲の把握、再発防止策の提案といった分析・改善フェーズにおいてAIの支援が期待されているようです。また、アップデートや構成変更に伴う影響調査、さらには事業計画やBillingデータからの将来予測といった業務にもAIを活用したいというニーズが見られました。 アップデート: 11.1% システムやコードの保守や改善に関してAIの活用を望む声が多く挙げられました。特にEOL対応や、アップデート作業の自動化・効率化に対する期待が高まっています。 ドキュメンテーション: 10.5% ポストモーテムや障害レポートなど、定型的かつ情報整理を要するタスクに対してAIの支援を求める声が挙げられました。また、社内向けの説明資料やダッシュボードの自動生成、ドキュメントの検索や要約といった情報の可視化・再利用性の向上に関してもAIへの期待が寄せられています。 モニタリング/アラート: 9.9% アラートのトリアージや原因調査、優先度の判断、リリース後の自動モニタリングや外部サービスの障害速報の把握など、AIによるリアルタイム性と網羅性が期待されています。判断や対応をより迅速かつ確実にし、システムの安定性を高めるための基盤が整えられることが望まれているようです。 おわりに 改めて来場してくださった皆様、また弊社のブースに立ち寄っていただいた皆様に感謝を申し上げます。また本イベントを開催し、運営していただいた皆様も本当にありがとうございました。弊社としても今後の発展に貢献していきますのでまた来年もよろしくお願いいたします。 おまけ: ノベルティーキーキャップの発注方法 今回作成したノベルティーキーキャップについてはクオリティの高いものを製作していただきました。需要は不明ですが、ノベルティーキーキャップの発注については直近ではあまり情報がないようでしたのでこちらにまとめておきます。 今回発注したのはYUZU Keycapsさん( https://yuzukeycaps.com/ )です。こちらでは昇華印刷と呼ばれる方法を利用しており、熱と圧力によって浸透させて色をつけるため耐久性が高く剥がれることもありません。この方法は境界が滲んてしまうことがあるのですがとてもきれいな仕上がりでした。 発注は以下の画面から行えます。 まずはレイアウトを選びます。ノベルティーキーキャップ用のレイアウトは用意されていないので、適当なものを選びカスタマイズしていきます。1Uサイズのものが一般的なのでOrtholinearのものを選ぶとあとの作業が多少楽になります。 「Options」 からレイアウトをカスタマイズできます。今回はすべて同じキーにしたいので 「Add/remove keys」 を選択して詳細の編集画面に移ります。 ここではすべてのキーを自由に選択することができます。各行 R1 ~ R4 も自由に選べます。ノベルティーキーキャップはEscとしてつけることを想定するためかR1であることが多いです。なお今回配布したメルカリのノベルティーキーキャップはMにつけることを想定してR4にしました。 説明用に作成したR1 10×5のものをこちらに置いておきます。 https://yuzukeycaps.com/keyboards/121dfa73-a55e-492c-870a-2b94e490d040 次にキーキャップのテンプレートを作成していきます。ひとつひとつ設定することもできますが、テンプレートを作成しておくと後の作業が楽になります。 後でロゴを配置できるように ICON タイプでテンプレートを作成します。なお、デフォルトのアイコンとしてアップロードした画像を選択することはできないようです。なのでここでは適当なものを選択しておきます。 次にキーを選択して、詳細の編集画面を開きます。「Select icon」を選択するとアイコンを選択する画面になるのでセレクトフォームの右側のアップデートボタンから利用するロゴファイルを選択します。画像の作成方法については下記に説明があります。基本的には2色のみしか使えないので注意が必要です(選べるカラーは豊富にありますが自分で自由に色を作ることもできません)。 https://fkcaps.notion.site/Custom-image-upload-e5e214dc80c047ada20d97d3418eb2de なおこの画面からロゴの位置やサイズの微調整はできますが、同じ作業をすべてのキーに対してすることになるので、ここでは何もせずに済むようにテンプレートを調整することをおすすめします。 あとはひたすらこの繰り返しです。アップロードしたデータはMy Iconsから選択できるようになっているので2回目以降は多少は楽です。なお私が発注したときはjsonファイルで入出力することができたので、jsonファイルを編集してこの繰り返し作業をもっと楽にすることはできましたが、この記事の執筆段階ではそれができなくなっていました。 データが完成したら「ADD TO CART」に進み発注して完了です。データチェック後に製造され、手元に届くのには2~3週間ほどかかりますので余裕を持って発注することをおすすめします。 以上です。ノベルティーキーキャップ作成の参考になれば幸いです。
こんにちは。メルペイQAチームの@uni0110です。 私は6月にスコットランドのエディンバラで開催された EuroSTARカンファレンス に参加しました。EuroSTARは世界的に有名なQAカンファレンスの一つで、今年は4日間にわたり60以上のチュートリアル、セッション、キーノートが行われました。約350社から1000人以上が参加した大規模なカンファレンスです。 テーマはAI on Trial 今年のカンファレンスで最も注目されたテーマはAIでした。参加者との会話でも、「あなたの会社ではAIをどのように活用していますか?」という質問が最も多く、議論が盛り上がりました。 当時、メルペイQAチームは自動化にAIを活用して、それ以外の工程ではさまざまなツールを試している段階でした。そのため、私自身もAIに関するトピックに最も期待していました。 全セッションの半分以上がAI関連のトピックで、内容はそれぞれ異なりましたが、どのセッションも共通して強調していたのは「AIがもたらす効率性や利便性よりも、AIの誤用や不確実性に対する注意」でした。初日のチュートリアルでこれを実際に体験できたので、簡単に共有したいと思います。 Test by Human vs. by AI 初日のチュートリアルでは、人間とAIがそれぞれ同じ内容のテストを実施しました。その結果、人間によるテストではシステムに潜在するバグが発見されましたが、AIが作成・実行したテストケースではバグを見つけることができませんでした。 この違いは、人間だからできる批判的な思考です。人がテストケースを作成する際には、まず仕様を把握し、「どのような改修が行われたか」、「特定のケースではどうなるか」といった疑問があったらチューターに質問し、解決しました。このプロセスを通じて、不要なケースを削除し、必要なケースを追加することで、テストケースを完成させました。 しかし、AIの場合は、どのAIツールを使用しても入力された指示に従ってテストケースを作成するだけで、バグを発見するケースは作成できませんでした。 このことから、優れたQAエンジニアになるためには、クリティカルシンキングに基づいた積極的なコミュニケーション能力が必要であると痛感しました。 QAが見るAI このチュートリアル以外にもAIが持っている以下の弱点のため、AIを使う時は十分気をつけないと行けないという内容のセッションが多かったです。 プライバシー&セキュリティ バイアス ハルシネーション 不慣れな人による誤用 過度な自動化 ここまでの内容だと、カンファレンス全体がAIに対して批判的な見方をしているように思われるかもしれませんが、どのセッションもAIが作業に役立つツールであることを前提としていたため、Anti-AI的な雰囲気ではありませんでした。 ただ、警戒心を何度も与えた理由は、私達のロールがQAだからです。QAは他のエンジニアロールとは異なり、問題やリスクを発見する役割を担っています。そのため、AIに対しても厳しく警戒心を持たなければ、品質が損なわれる可能性があるからです。 終わりに AIに関するベストプラクティスを期待して参加したカンファレンスでしたが、最後には自分は良いQAエンジニアなのか、もっとできることはないか、といった課題ばかり持ち帰ることになりました。また、QAエンジニアとしてAIに負けない私だけの価値について考え続けています。 しかし、さまざまな場所から参加した多様なQAエンジニアと話す中で、皆が同じ悩みを抱えていることが分かり、良い刺激を受けました。 特にAIについては、単なる便利なツールであり、silver bulletではないことを念頭に置いて活用していきたいと改めて感じました。
Search Infra Teamのmrkm4ntrです。 画像検索にElasticsearchのベクトル検索(kNN検索)を活用しています。しかし、従来のキーワード検索と比較して、同等のリソースで処理できるQPS(Queries Per Second)が大幅に低いという課題がありました。そこで、Elasticsearch 8を基に、kNN検索のパフォーマンスをどこまで改善できるのかを調査しました。 kNN検索の構成と課題 今回の検証で使用したkNN検索のクエリ構成は以下の通りです。 { "size": 100, "query": { "knn": { "image_embedding": { "vector": [ 0.1, 0.2, ... (128次元のベクトル) ], "k": 100, "num_candidates": 100, "filter": { "term": { "status": "on_sale" } } } } } } このクエリは、「status」フィールドが「on_sale」に一致するドキュメントの中から、与えられたベクトル(image_embedding)に類似した上位100件のドキュメントを検索するものです。ベクトルの次元数は128です。 検証当初はElasticsearch 8.12.1を使用しており、async-profilerを用いてCPUプロファイルを取得した結果、以下の箇所がボトルネックとなっていることが判明しました。 特に目立つのは、赤枠で囲まれた jint_disjoint_arraycopy と jlong_disjoint_arraycopy です。これらのメソッドは、 OffHeapQuantizedByteVectorValues.vectorValue から呼び出されており、JVMのヒープ外(つまりファイルシステムキャッシュ上)に格納されているベクトルデータをJVMのヒープ内にコピーする処理を行っています。 Luceneでは高速なkNN検索を実現するためにPanama Vector APIを活用しています。このAPIはベクトル計算でプロセッサのSIMD命令(AVX命令)を使用し、演算効率を向上させるものです。しかし、ベクターデータを一度JVMヒープ内にコピーしてからPanama Vector APIに渡す無駄が発生しているため、パフォーマンスが大きく制約されています。 このボトルネックを軽減する可能性がある修正がLuceneに施されていることが分かりました。具体的にはhttps://github.com/apache/lucene/pull/13339 の変更で、JVMヒープ外メモリから直接Panama Vector APIに渡す実装に改善されています。 Elasticsearch 8.17.1へのアップデートとパフォーマンスの変化 上記の改善が既に含まれるElasticsearch 8.17.1にアップデートし、パフォーマンスを検証しました。 検証環境 Elasticsearch Version: 8.17.1 k: 100 num_candidates: 100 ベクトルの次元数: 128 リアルタイムなドキュメントの追加/更新/削除 フィルタリングの有無と度合いがパフォーマンスに与える影響を評価するため、以下の3つのケースで同一のスペックで捌けるQPSをパフォーマンスとして計測しました。 フィルタなし: フィルタリングなし 緩いフィルタ(loose filter): 約50%のドキュメントがフィルタ条件に一致 絞り込みフィルタ(selective filter): 約10%のドキュメントがフィルタ条件に一致 フィルタなしのケースにおいて、async-profilerでCPUプロファイルを再取得したところ、flame graphからPanama Vector APIの痕跡が消え、代わりに赤枠で囲んだ dot7u というメソッドが表示されるようになりました。 これは、Elasticsearch 8.15から、LuceneのPanama Vector APIではなく、より効率的なElasticsearch独自のベクトル化モジュールが使用されるようになったためです ( https://www.elastic.co/search-labs/blog/vector-similarity-computations-ludicrous-speed ) 。この独自実装では、不要なデータコピーはそもそも発生しません。 8.12.1と8.17.1のパフォーマンスの比較は以下です。 8.12.1 8.17.1 フィルタなし 350 450 緩いフィルタ(loose filter) 50 70 絞り込みフィルタ(selective filter) 30 40 Elasticsearch 8.17.1にアップデート後、全体的にパフォーマンスが改善しましたが、フィルタありのケースでは依然としてフィルタ無しのケースと比べるとパフォーマンスが低い状態です。 絞り込みフィルタリング時のHNSWグラフ探索の最適化 絞り込みフィルタ(selective filter)を適用した場合のCPUプロファイルを確認したところ、赤枠で囲まれた部分の HNSWGraphSearcher.search の処理時間が大幅に増加していることがわかりました。 これは近傍のノードをチェックする際に、類似度の計算を行わず、諦めて次をチェックする回数が増加していることを意味します。 つまり、HNSWグラフの構造上、フィルタ条件に合致するドキュメントが少ない場合、グラフのリンクを効率的に辿ることができないために発生する問題です。類似度が高い方向にグラフを探索しても、フィルタ条件に合致するドキュメントが見つからない場合、大きく迂回したり、戻ったりする必要が生じ、探索効率が低下します。 この問題を解決するために、ACORNと呼ばれるアルゴリズム( https://arxiv.org/pdf/2403.04871 ) が提案されており、様々なベクトル検索エンジンが採用しています。Luceneのupstreamでも、ACORN風のアルゴリズムが実装されているため、このPR ( https://github.com/apache/lucene/pull/14160 ) をcherry-pickして試したところ、特に絞り込みフィルタの場合に大きなパフォーマンス改善が見られました。 8.17.1 8.17.1 + ACORN フィルタなし 450 450 緩いフィルタ(loose filter) 70 80 絞り込みフィルタ(selective filter) 40 120 とはいえ、緩いフィルタ(loose filter)の場合はあまり改善されていません。 緩いフィルタリング時のBitSet合成の最適化 緩いフィルタ(loose filter)を適用した場合のCPUプロファイルを確認したところ、赤枠で囲んだ部分である AbstractKnnVectorQuery.createBitSet の処理時間が大部分を占めていることがわかりました。 フィルタが固定で、kNN検索に指定するベクトル値のみを変更している場合、フィルタの結果のBitSetはクエリキャッシュに保存されるため、フィルタ自体のコストはほぼ無視できるはずです。 コードを解析した結果、createBitSetメソッド内で、フィルタのBitSetとliveDocsのBitSetを合成した新しいBitSetを作成していることが判明しました。LuceneのSegmentはimmutableであるため、削除されたドキュメントを管理するために別のデータ構造(liveDocs)が必要になります。liveDocsもBitSetで表現されており、フィルタのBitSetとliveDocsのBitSetを合成する際に、BitSetの中身をiterateしていました。緩いフィルタの場合、フィルタ条件に合致するドキュメントが多いため、この処理に大きなコストがかかっていました。 しかし、グラフを辿る際に、見つけたドキュメントがフィルタに合致するかをチェックするだけであれば、BitSetを合成する必要はありません。また、カーディナリティ(BitSet内で1が立っているビット数)を計算する場合も、iterateして合成する必要はなく、FixedBitSetのintersectionCountメソッドを使用することで高速に計算できます。 これらの点を修正した結果、特に緩いフィルタを使用した場合のパフォーマンスが大幅に改善しました。 8.17.1 + ACORN 8.17.1 + ACORN + BitSet合成最適化 フィルタなし 450 450 緩いフィルタ(loose filter) 80 200 絞り込みフィルタ(selective filter) 120 170 この修正はLuceneのupstreamにPRとして送りました( https://github.com/apache/lucene/pull/14771 ) 。しかし、その少し前に追加されていた修正 ( https://github.com/apache/lucene/pull/14674 ) にて改善されていたためこのPRは不要でした。正確には、このPRそのものはcherry pickして試していましたが、 applyMask の非default実装は別PRで対応されていたため、それを見落としていました。 FieldExistQueryによるパフォーマンス低下の解消 改善後のCPUプロファイルを確認したところ、依然としてcreateBitSet内の Lucene99ScalarQuantizedVectorsReader$QuantizedVectorValues.advance の処理時間が残っていました。 これは、フィルタにLucene内部で追加されるFieldExistQueryによるものであることがわかりました。インデックス内のすべてのドキュメントにkNNの対象となるベクトルフィールドが存在するわけではない場合、その存在をチェックする追加の処理が必要になります。今回のケースでは、埋め込み処理でエラーが発生した場合にベクトルが存在しないドキュメントが存在していました。 これらのドキュメントをインデックスに含めないように修正したところ、パフォーマンスがさらに改善しました。 8.17.1 + ACORN + BitSet合成最適化 8.17.1 + ACORN + BitSet合成最適化 + FieldExistQueryの除外 フィルタなし 450 450 緩いフィルタ(loose filter) 200 250 絞り込みフィルタ(selective filter) 170 200 一般にFieldExistQueryは対象のドキュメントのfieldを全てチェックする必要があるため高コストです。FieldExistQueryと今回のフィルタはQuery Cacheの対象のため全てのドキュメントをチェックしているわけではないはずですが、Query Cacheの対象とならないようなサイズのセグメントのみが対象だったとしても、緩いフィルタの場合は高コストであったと考えられます。 さいごに Elasticsearch 8のkNN検索において、フィルタリング時のパフォーマンスを改善するために、以下の施策を実施しました。 Elasticsearch 8.17.1へのアップデート: Elasticsearch独自のベクトル化モジュールを使用することで、フィルタなしのケースにおけるパフォーマンスを向上させました。 ACORN風アルゴリズムの導入: 絞り込みフィルタ適用時のHNSWグラフ探索を最適化しました。 BitSet合成の最適化: 緩いフィルタ適用時のBitSet合成処理を効率化しました。 ベクトルフィールドの存在チェックの排除: ベクトルフィールドが存在しないドキュメントをインデックスから排除することで、不要な存在チェックを削減しました。 これらの改善により、フィルタリングの有無に関わらず、kNN検索のパフォーマンスを大幅に向上させることができました。以下が最終的な結果です。 改善前 改善後 フィルタなし 350 450 緩いフィルタ(loose filter) 50 250 絞り込みフィルタ(selective filter) 30 200 ベクトルフィールドの存在チェック以外の改善は将来のElasticsearchのリリース(9.0.4以降?)に含まれる予定です。 これらの改善は、ElasticsearchのkNN検索をHybrid Searchなどに活用し、より高度な検索サービスの提供に繋がるものと考えています。
こんにちは。メルペイ Payment Core Teamで2ヶ月間インターンシップをした@taichiです。 この記事は、 Merpay & Mercoin Tech Openness Month 2025 の22日目の記事です。 はじめに 私は4月の中旬から6月の中旬の間、 バックエンドエンジニアとしてメルペイのインターンシップに参加しました。今回はインターン期間中に取り組んだタスクを振り返り、 そこで得た学びをまとめたいと思います。 この記事が、 メルペイのインターンに挑戦してみたいと考えている未来のHackerの参考になれば幸いです。 取り組んだタスク 私が担当したタスクは大きく分けると3つあります。 外部パートナーへの接続に関するCredentialの管理方法の変更 Re-arch中のソースコードへのPub/Sub基盤統合 個人情報難読化ポリシーの実装 以下で1つずつ話していきます。 外部パートナーへの接続に関するCredential管理方法の変更 背景 私が所属するPayment Coreチームでは、決済基盤マイクロサービスである『Payment Service』の開発を担当しています。このサービスは、メルカリ、メルペイ、メルコインが展開する多数のマイクロサービス群から参照されており、グループ全体の決済ドメインにおけるコアな責務を担っています。 メルペイでは決済機能の一部で外部パートナーさまのAPIを活用しているため、そのCredentialを適切に管理する必要があります。 私がタスクに取り組むまでの運用では、 新しく追加したCredentialを暗号化しSpannerにSQL raw queryを叩くことで保存していました。 従来の運用方法は以下に示す危険性と面倒さを有しています。 加盟店追加のたびにSQLクエリを叩く必要がある 加盟店追加後にSQLクエリを発行し忘れる可能性がある やったこと 上記の課題を解決するために、 以下のような設計と実装を行いました。 外部パートナーの加盟店さまのパスワードの格納先をGoogle Secret Managerに変更 Spannerに直接パスワードを保存せず, SecretのKeyとVersionだけを格納する Secretの情報を入力として渡すだけで, SQLが走ってSecretのKeyとVersionをSpannerに保存するK8sのJobテンプレートを作成 SecretManagerを通して加盟店さまのパスワードを取得できるようにClientCodeを修正 最初はCLIを作ってチームに提供することも考えましたが、 メンテナンスの負荷が新たに発生すること、 K8sのJob基盤がすでにチームに存在することを理由にCLIは避けました。 K8sのJobテンプレートはこちらが参考になると思います。 インターンに参加して1週間くらいで設計を行いドキュメントを作成したのですが, 設計書のレビューが手厚くチームメンバーと技術的な議論を繰り返すことでタスクやPayment Serviceの全体像を掴むことができました。 Re-arch中のソースコードへのPub/Sub基盤統合 背景 私が所属していたPayment Coreチームが開発しているPayment Serviceは、そのソースコードが非常に複雑なため、大規模な再構築プロジェクト、通称「Re-arch(リアーキテクチャ)」が進められていました。 このRe-archプロジェクトの目的は、既存のPayment ServiceのソースコードをClean Architectureのような設計思想に基づいて書き直すことです。 現状のPayment Serviceでは、非同期処理のためにGoogle Cloud Pub/Subが利用されています。しかし、Re-arch後の新しいソースコードには、Pub/Subを利用するための基盤がまだ整備されていない状況でした。 やったこと 私はRe-arch後のソースコードのコンテキストにマッチするようにPub/Subの基盤を統合しました。 Pub/Sub基盤の設計は、 Payment ServiceがPub/SubからSubscribeしか行わないことを前提にメンターと進めました。 Subscriberに渡すHandlerのInterface設計や、 Usecaseに渡す依存関係を一括で管理するContainerとの親和性を考慮して設計する経験は非常に勉強になりました。 Re-archのPRは変更が大きいものもあるので、 Conflictの解消やContextを理解し直すのに苦労したこともありましたが、 あれほど大規模なソースコードを読むこともないのでとても良い経験になりました。 開発体験としても、 Payment ServiceではMockの生成は moq.go を使っているので、 interfaceだけ設計すればMockを簡単に生成できるので、 素早くTestableなコードを書くことができました。 個人情報難読化ポリシーの実装 背景 個人情報保護法の改正を受け、メルペイ全社で「PII Deletion(個人情報難読化)プロジェクト」が進行中です。これに伴い、Payment Serviceもこの対応を行う必要がありました。 個人情報の難読化はメルペイ全体で取り組むべき課題であるため、すでにそのためのマイクロサービス「PII Deletion Service」が構築されていました。 しかし、Payment ServiceからPII Deletion Serviceを叩きに行くことができない状態でした。 やったこと PII Deletion Serviceのアーキテクチャは下図のようになっています。 上図を解釈すると, 処理の流れとしては以下になります。(Payment Serviceは上図における右端に位置すること, 各マイクロサービスはgRPCで通信を行うことを念頭においてください) PII Deletion Managerから難読化すべき個人情報の情報がPub/SubにPushされる Payment ServiceがPub/SubからPullして難読化する対象を見つける 難読化する 難読化が成功したかのステータスをPII Deletion Managerに返す 1はすでに仕組みとして存在するので、 私は2-4を実装すれば良いことに気づきます。 以下ではステップ2についてどのように対応したかを述べます。(3、 4はそこまで難しいことがないのでスキップします。) Pub/SubからPullして難読化対象を見つける PII DeletionのHandlerはRe-arch後のソースコードに実装するので、 私が統合したPub/Sub基盤を使用すればすぐに実現できるので簡単に思えます。 しかし、 Pub/SubのSubscriberが行う処理をそのまま記述しようとすると2点好ましくない点があります。 普段慣れ親しんでいるgRPCエンドポイントと異なる体験で開発しないといけない Subscriberのロジックが他のAPIのロジックから独立しがち これらの課題を避けるために、 メルペイはPub/Sub gRPC Pusherという内製化サービスを持っています。Pub/Sub gRPC Pusherの仕組みは簡単で、 以下のようなアーキテクチャになります。 gRPC Pusherはマイクロサービスの代わりにPub/SubからPullし, gRPCリクエストに変換してマイクロサービス側のエンドポイントを叩いてくれます。 gRPC Pusherを使うことでメルペイのエンジニアは、Pub/SubのSubscriberロジックを慣れ親しんだgRPCエンドポイントとして実装でき、Pub/Subという特定のInfrastructureを意識しなくて良くなります。 今回はこちらのgRPC Pusherを利用するためのInfrastructureリソースをTerraformで作成し、 個人情報難読化を行うロジックはgRPCエンドポイントとして実装を行いました。 ただ、gRPC Pusherを使うならいろいろと考えるべきことがあります。 Pub/SubのPull型Subscriptionの大きな利点は、Pullする側のスケールやワークロードの都合に合わせて処理を実行できる点にあります。gRPC Pusherはその都合をPullするマイクロサービスの代わりに受け持っていると考えることもできます。 Kubernetesをはじめとしたスケーリング技術は、必要になった時にすぐにスケールするわけではないので、ワークロード量によってはgRPC Pusherの使用は適切でない場合もあります。しかし、PII Deletionのリクエストはスケールが追いつかないほど大量のリクエストが飛んでくることは想定し難いため、gRPC Pusherの使用を決断しました。 全ての個人情報を難読化するところまでは完了できませんでしたが、 基本的なロジックは全て実装し終えました。 学んだことと感想 ハード面 使用した技術としては以下です。 Kubernetes Terraform Google Cloud (Pub/Sub, Secret Manger, Spanner) gRPC Go どの技術も触ったことはあったものの深く触ったことはなかったので勉強になりました。 特にTerraformには興味があるので、 大学院の研究が落ちつく7月は何かしらのProviderを自前で実装するつもりです。Kubernetesに関しても基本的な概念やリソースの役割のみならず、 カスタムコントローラの実装等、 面白い部分はたくさんあるのでこれからさらに深く勉強していこうと思います。 また、 Payment Serviceのソースコードは大規模かつ複雑だったので読み解くのに苦労しましたが、 パフォーマンスと冪等性を意識した設計になっているのでとても勉強になりました。 ソフト面 インターンを通して自身の英語スキルが向上したと感じました。 Payment Coreチームでは、 チームのStandupも月曜日から木曜日は全て英語で行われます。 また、私が参加していたPII Deletion ProjectのMeetingやGitHub上のやり取りも基本全て英語ですし、最終成果発表も全て英語で行いました。普段の業務から英語と身近に触れられたことは自身の成長に大きく繋がったと感じています。 それから, チームメンバーはもちろん、他のチームの方々ともコミュニケーションを積極的にとることも心がけました。チームメンバーはもちろんのこと、他チームの方々も私に親切にしてくださり最終成果発表にも参加してくださいました。 インターンシップを通じてメルカリのカルチャーを存分に味わえて本当に楽しかったです。 メルカリグループは全社的にAI活用を推進しており、私も積極的にAIを活用しました。私は以前からAIを使ってソースコードを生成することに違和感を覚えていました。 Junior EngineerはIntermediate、 Seniorとタイトルを上げていく必要があります。タイトルはエンジニアの各ソースコードのレベルだけで決まるわけではないですが、当然相関はあります。Juniorである私がAIを使ってソースコードを書いてしまったら、成長する機会がなくなりいつまで経っても自らのスキルが伸びないのではないか?と考えていました。 ですが、Payment Serviceの莫大なドメインと複雑なソースコードを理解するには到底2ヶ月では足りないため、効率の良いキャッチアップが必要です。チームメンバーに相談してみると、彼らは皆AI(Cursor)を使って効率よくドメイン知識を吸収したり、UnitTestを書いたりしていました。彼らの助言を受けて私もインターン中にCursorを徹底的に活用し、AIと協調して、今までよりもより本質的な作業に時間を使えるようになりました。 AIを使用しても出力されるコードや価値は本人の能力にキャップされるため、依然として強くなるために勉強は必要です。 私が最初に抱いていた違和感は今でも間違っていないと思います。 しかし、成長する機会は自分でいくらでも作り出せるので、仕事と成長をイコールで結ばず両方全力で取り組めば、より早く、より大きな価値を届けられるエンジニアになれると考えを改めました。 インターンを通して最も大きく変わった部分はここだと思います。 最後に チームメンバーをはじめ、たくさんの方々にお世話になりました。 メルカリのカルチャーを存分に体感しながら技術的に難しい課題に取り組まさせていただき、本当に感謝しています。 2ヶ月間ありがとうございました。
こんにちは。メルカリモバイルのソフトウェアエンジニアの @keiitaj です。 この記事は、 Merpay & Mercoin Tech Openness Month 2025 の21日目の記事です。 概要 本記事は、2025年6月16-17日に日本で初開催されたKubeCon + CloudNativeCon 2025 Japan の参加レポートです。 この記事の内容: 日本初開催のKubeConイベントレポート 注目セッション Envoy拡張用Wasmフィルタのローカル環境上のデモ実装 執筆者の学び: EnvoyとWebAssemblyを活用したAPI管理手法を実際に実装することで、セッションで得た知識をより深く理解できました。また、参加前は技術的ハードルが高いと感じていましたが、実際は職種やレベルを問わず楽しめるイベントであることを発見しました。 目次 はじめに 参加の動機 イベントの規模と熱気 注目したKeynote & Session 参加して感じたこと おまけ:Envoy + Wasmフィルタのデモ実装 まとめ はじめに 私は普段、Platform Engineerではなく、KubernetesやCloud Nativeの技術で構成された基盤の上でサービス開発を行うエンジニアとして、Tekton、Argo、Istio、Envoyなどを使って仕事をしています。 参加の動機 技術的な興味 業務でKubernetesやCloud Nativeの技術(Tekton、Argo、Istio、Envoy、Spinnakerなど)に日々触れる中で、これらの技術の最新動向やコミュニティの活動に強い興味を持つようになりました。 また、AI技術の進化により、サービス開発エンジニアがPlatform構築により深く関わる機会が増えていくと感じました。 そのため、Cloud Nativeエコシステムの全体像を把握しておきたいという思いもありました。 日本初開催の歴史的なイベント CNCF(Cloud Native Computing Foundation)の主要イベントとして世界各地で開催されてきたKubeConが、日本で初めて開催されることも参加の大きな動機となりました。 実は、この日本開催実現までには長い道のりがあったそうです。 以前、5月に開催されたCloudNative Daysで、Linux FoundationのNoriaki Fukuyasu氏による KubeConを日本に招致するまでの経緯 についての講演を聞く機会があり、その内容がとても印象的で、今回のKubeCon参加のきっかけの一つにもなりました。 Fukuyasu氏の話によると: 2023年以前、日本はクラウドネイティブ技術後進国と言われていた 大企業での採用実績が少ない アジャイル、マイクロサービス、コンテナを知らない人が多数 Cloud Native Community Japan を立ち上げ、月に複数回のmeetupを開催 継続的なロビイング活動を通じて、ついに日本への招致に成功 このような背景を知ったことで、日本初開催のKubeConに参加することの意義をより深く感じるようになりました。 イベントの規模と熱気 会場と参加者 会場となったヒルトン東京お台場で開催されたこのイベントは、1,500枚のチケットが完売し、日本のCloud Nativeコミュニティの盛り上がりを肌で感じることができました。 ちなみに、今年ロンドンで開催されたKubeConは12,418人が参加する 大規模なイベント でしたが、日本開催はコンパクトながらも内容の濃いイベントでした。 イベントの楽しみ方 KubeConの魅力は、単にセッションを聞くだけではありません。初参加で感じた楽しみ方をご紹介します: セッション参加 : スケジュール を見て、興味のあるKeynoteやセッションに参加 ブース巡り :セッションの合間に、OSSパビリオンや企業ブースを訪問 OSSプロジェクトの開発者と直接話す貴重な機会 最新プロダクトのデモを体験 各社のノベルティグッズ収集 企業ブースでの発見 各企業ブースを回ることで、最新のプロダクトやサービスの動向を直接確認できました: PagerDuty AIエージェントが過去の対応履歴を基に、インシデントの原因分析や重要度判定を支援 Splunk Observability Cloudの新機能を展示、AIチャット機能による差別化を強調 Toyota コネクテッドカーの研究開発でCloud Native技術を活用し、自動車業界でもCloud Nativeが浸透していることを実感 注目したKeynote & Session Opening Keynote: Community Opening Remarks Community Opening Remarks – Chris Aniszczyk氏(CNCF CTO) 開会の挨拶では、以下の印象的な発表がありました: 1,500枚のチケットが完売したことへの感謝 CNCF、Kubernetesへのコントリビューションで日本がTOP10入り 2026年も日本でKubeConを開催することが決定! 日本のCloud Nativeコミュニティの成長が認知されていることを実感しました。 技術セッション: Full Lifecycle API Management in Kubernetes With Envoy and WebAssembly 特に印象に残ったのは、 Full Lifecycle API Management in Kubernetes With Envoy and WebAssembly というセッションです。 セッションの概要 KubernetesにおけるAPI管理の課題に対して、EnvoyとWebAssembly(Wasm)を活用した革新的なアプローチが紹介されました: L3/L7プロキシ機能の統合 JWT認証とルーティングによる高度なAPIトラフィック管理 eBPFとOpenTelemetryを活用したオブザーバビリティの向上 WebAssemblyフィルタの活用 複数言語での開発が可能 より高速な配布時間 ランタイムでのセキュリティロジックの実装 実践的なデモ Authorizationヘッダーのチェック機能をWasmで実装 認証なしのトラフィックをブロックする仕組みの構築 技術的な洞察 このセッションで特に興味深かったのは、WebAssemblyの用途が拡大していることです。元々はブラウザ上でのパフォーマンス向上のために開発されたWebAssemblyが、今やサーバーサイドのプラグイン機構として活用され始めています。 参加して感じたこと 技術トレンドの観察 イベント全体を通じて感じた技術トレンド: OpenTelemetry + eBPF :オブザーバビリティ関連のセッションで頻繁に言及 WebAssembly :サーバーサイドでの活用事例が増加 AI統合 :各種ツールにAI機能が標準装備 コミュニティの多様性 印象的だったのは、専門的な内容から初心者向けまで幅広いセッションが用意され、ライトニングトークやパネルディスカッションでは専門以外の話題(コミュニティでの友達作りやコントリビューションのモチベーションなど)も語られていたことです。 参加のハードルが高いイメージがありましたが、実際は職種やエンジニアのレベルを問わず、誰でも楽しめるイベントであると感じました。 言語の壁と対策 Keynoteやセッションは全て英語で行われるため、英語が苦手な方には少しハードルが高いかもしれません。 私がとった対策は、Google Meetのマイクでスピーカーの音声を拾い、Geminiに議事録を作成してもらって内容を把握することでした。 Google Docsの音声入力は途中で音声が途切れると入力がストップしてしまったり、AppStoreに公開されている幾つかの音声の書き起こしアプリは有料でさらに時間制限があったりしたので、色々試行錯誤した結果、この方法が一番良かったと感じました。 また、参加した仲間とセッションの内容を共有し合うことで、理解を深めていました。 効率的な参加のコツ 同一時間帯に複数のセッションが開催されるため、私は興味のあるセッションを絞って参加しましたが、複数人で参加する場合はより効率的な立ち回りができると感じました: 手分けして異なるセッションに参加 Coffee Breakで情報交換したり、お互いにセッション内容のメモを共有 おまけ:Envoy + Wasmフィルタの実装とローカル環境のデモ KubeConで紹介されたEnvoyとWebAssemblyによるAPI管理の技術についてより深く理解するため、実際にEnvoyを拡張するGolang製のWasmフィルタを実装し、ローカル環境上で動作確認を行いました。 実装の詳細やソースコードは、 GitHub で公開しています。 デモの概要 このデモでは、Bearer トークン認証を行うWasmフィルタを実装し、以下の機能を備えています: Bearer トークンによる認証機能 /health エンドポイントの認証スキップ 認証成功時のカスタムヘッダー追加 認証失敗時のJSONエラーレスポンス 実装のポイント 1. 使用技術・ツール Envoy : v1.34-latest以降 Go : 1.24以降 (wasip1/wasm target) proxy-wasm/proxy-wasm-go-sdk : Wasm plugin development SDK for Envoy 2. シンプルな認証ロジック package main import ( "github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm" "github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types" ) func main() {} func init() { proxywasm.SetVMContext(&vmContext{}) } type vmContext struct { types.DefaultVMContext } func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext { return &pluginContext{} } type pluginContext struct { types.DefaultPluginContext } func (p *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus { proxywasm.LogInfo("plugin started") return types.OnPluginStartStatusOK } func (*pluginContext) NewHttpContext(contextID uint32) types.HttpContext { return &httpAuthContext{contextID: contextID} } type httpAuthContext struct { types.DefaultHttpContext contextID uint32 } func (ctx *httpAuthContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action { // Get path path, err := proxywasm.GetHttpRequestHeader(":path") if err != nil { proxywasm.LogErrorf("failed to get path: %v", err) path = "/" } proxywasm.LogInfof("Processing request to path: %s", path) // Skip health check if IsHealthCheckPath(path) { proxywasm.LogInfo("Health check endpoint, allowing request") return types.ActionContinue } // Get Authorization header authHeader, err := proxywasm.GetHttpRequestHeader("authorization") if err != nil { authHeader = "" } // Validate token authResult := ValidateToken(authHeader) if !authResult.IsValid { proxywasm.LogWarnf("Authentication failed: %s", authResult.Reason) return ctx.denyRequest(authResult.Reason) } // Add user type header proxywasm.LogInfof("Valid %s token", authResult.UserType) proxywasm.AddHttpRequestHeader("x-auth-user", authResult.UserType) return types.ActionContinue } func (ctx *httpAuthContext) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action { proxywasm.AddHttpResponseHeader("x-wasm-filter", "go-auth") return types.ActionContinue } func (ctx *httpAuthContext) denyRequest(reason string) types.Action { body := CreateErrorResponse(reason) err := proxywasm.SendHttpResponse(401, [][2]string{ {"content-type", "application/json"}, {"x-wasm-filter", "go-auth"}, }, []byte(body), -1) if err != nil { proxywasm.LogErrorf("failed to send response: %v", err) } return types.ActionPause } ローカル環境でのデモ Docker Composeを使用してローカル環境で動作確認を行えるようにしました: Client → Envoy Proxy (Wasmフィルタ) → Backend Service 以下の3つのシナリオで動作を確認できます: 認証成功 : 正しいBearerトークンでのリクエスト 認証失敗 : 無効なトークンでのリクエスト 認証スキップ : ヘルスチェックエンドポイントへのアクセス 学びと今後の可能性 このデモ実装を通じて、Envoy Wasmフィルタの実用性と多くのメリットを実感できました: Wasmフィルタの主要メリット 言語の自由度 – Go、Rust、C++など慣れ親しんだ言語で開発でき、既存のツールチェーンを活用可能 安全性 – Wasmのサンドボックス環境で実行されるため、Envoyプロセスをクラッシュさせるリスクが低く、メモリ安全性も保証 パフォーマンス – ネイティブコードに近い実行速度を実現 配布とバージョニング – 単一の.wasmファイルとして配布でき、バージョン管理やデプロイメントパイプラインへの組み込みが簡単 特に実際のプロジェクトでは、既存のGo/Rustコードベースがある場合、同じ言語でプロキシレイヤーのロジックを実装できることが大きな価値となります。 認証、ログ処理、メトリクス収集などのビジネスロジックを統一言語で管理でき、JWT検証やレート制限、OpenTelemetry連携など、より高度な機能への拡張も現実的です。 まとめ 初参加したKubeCon + CloudNativeCon 2025 Japanは、日本のCloud Nativeコミュニティの盛り上がりを実感できる貴重な体験となりました。 技術面では、EnvoyとWebAssemblyを活用したAPI管理手法が特に印象深く、実際にWasmフィルタを実装してローカル環境でデモを動かすことで、セッションで学んだ概念をより深く理解できました。また、OpenTelemetryとeBPFを組み合わせたオブザーバビリティ技術や、WebAssemblyのサーバーサイド活用、AI統合の進展など、Cloud Native技術の進化を直接体感することができました。 また、参加前は技術的なハードルが高いイメージがありましたが、実際は職種やエンジニアレベルを問わず楽しめるイベントであることも発見できました。多様な参加者との交流や企業ブースでの最新技術の体験も、魅力だと感じました。 来年2026年の日本開催も決定しており、Cloud Native技術に興味がある方にはぜひ参加をお勧めします。 本記事で紹介したセッションの動画は、 CNCFの公式YouTubeチャンネル で公開されています。興味のある方はぜひご覧ください。
こんにちは。メルペイで機械学習とAIのチームのEMをしている@hiroです。 この記事は、 Merpay & Mercoin Tech Openness Month 2025 の21日目の記事です。 メルカリ、メルペイでは生成AIの活用を非常に積極的に推進しています。今回の「Merpay&Mercoin Tech Openness Month 2025」においても、自然発生的に多くのメンバーが生成AIをテーマに選択しており、これは会社全体でのAI活用の機運の高まりを示していると感じています。従前からAIの取り組みはありましたが、会社としてのコミットメントの深まりとエンジニアを含むメンバーたちの熱量が高くなっており、数々のプロジェクトが生まれています。 この記事ではその中から、CXOの@naricoと共に推進している「PJ-Aurora」(プロジェクトオーロラ)について共有します。 Design/Creative x AI 2024年のメルカンの記事『 「Must」を「Fun」に!メルカリCPOとCXOが語る、“AI-Led Growth Company”としてのAI活用の未来 』にも書かれていますが、以前より「pj-ai-creator」を立ち上げ、デザイン領域における生成AIの活用について実験的な取り組みを行ってきました。PJ-AuroraはAI Creatorを経て正式に立ち上がったプロジェクトです。 PJ-Auroraは生成AIの活用を通じて、メルカリ、メルペイにおけるものづくりのアプローチを変革し、よりMove Fastにアイデアを実現してお客さまに届けることができるようになることを目指しています。あしもとでは特に、アイデアからのUI生成や評価、UXシミュレーション工程のプロセスイノベーションに挑戦しています。 とはいえ、基盤モデルの性能が日毎月毎に改善されていく中、生成AIを使って達成できることは何か、という問いの答えも変わり続けています。私たちも常に学習し続け、期待値とスコープを更新し続ける必要があると認識しています。 アイデアからUIを生成する プロンプトからUIを生成するタスクは生成AIの発展とともに流行しているタスクの一つで、Figma社のFigma Makeをはじめさまざまなサービスが生まれています。メルカリでは各サービスの試験的な利用もしつつ、Agentic Workflow(複数のAIエージェントが連携して作業を進める仕組み)を構築し、独自のUI生成プロセスを構築する営みも並行して進めています。 このタスクは昨今、精度向上が目覚ましく、正直なところ、最終的には内製のシステムではなく外部のサービスを使う形になるかもしれません。しかし、この取り組みを通じて得られる知見と資産は、AI時代における競争優位性の源泉になると考えています。 AI時代のデザイン資産 たとえば、デザインシステムは人間のデザイナー/エンジニアが理解し活用するために作られていることが多いですが、AI時代においては「AIが理解し活用できる形」での資産化が重要になってくると思います。 構造化されたデザイン言語 : ブランドアイデンティティやデザイン原則をAIが解釈可能な形で体系化 AI-Friendlyなデザインシステム : コンポーネントやパターンをMCP(Model Context Protocol)等を通じてAIが参照・活用できる状態に整備 ドメイン特化の知識ベース : 特有のUXパターンやユーザー行動をAIが理解できる形で蓄積 これらの資産は、外部サービスだけでは実現困難な「メルカリらしさ」を保ちながらAI活用を進めるための基盤となります。仮に将来的に外部サービスを利用することになったとしても、これらの構造化された資産は他のAIツールとの連携や、独自のワークフロー構築において価値を持ち続けると想定しています。 一方、基盤モデルを利用するだけで高精度のUI生成が可能になった場合、外部サービスを利用するのではなく、メルカリ内部のシステムやワークフローに接続しやすいようにあえて「基盤モデルのAPIを使った内製のUI生成システム」に着地する可能性もありえるかもしれません。 UI生成の実装の概要 いくつかのコンセプトから構成されていますが、ここでは2つのAgentを紹介します。Agentic Workflowの実装は現時点では、GoogleのADK(Agent Development Kit)を使っています。 コンセプトリファインAgent UI生成Agent コンセプトリファイン UI生成ツールのユーザーが記述した機能やサービスのアイデアを、UI生成Agentに入力するためのデータ(プロンプト)に変換するための機能です。基盤モデルの性能向上によって簡単な指示でもある程度の品質のUIを生成してくれるようになりつつあります。一方で、実現したいことや作りたいもの、制約等をよく言語化し、構造化することの価値は変わらず高く、生成されるものの品質を大きく左右すると感じています。 以下は実装のイメージです。 def create_concept_refinement_agent() -> LlmAgent: """ ユーザーのコンセプト案をブラッシュアップするためのシンプルなLlmAgentを作成します。 """ return LlmAgent( name="ConceptRefinementAgent", model="gemini-2.5-pro-preview-05-06", description="ユーザーのデザインコンセプト案を受け取り、より詳細で具体的なアイデアにブラッシュアップするエージェント。", instruction=( "あなたはデザインコンセプトを具体化・洗練させるAIアシスタントです。\n" "ユーザーから与えられたコンセプト案を読み、**それを元に最大限具体的で魅力的なコンセプト案を生成してください。**\n" "生成する際は、以下の点を考慮・推測し、具体的に記述してください:\n" "- **ターゲットユーザー:** (例: 20代後半のテクノロジーに関心のある都市部在住者)\n" "- **解決する課題/提供価値:** (例: 煩雑なスケジュール調整をAIで自動化し、自由な時間を創出する)\n" "- **コア機能/体験:** (例: 自然言語でのイベント登録、参加者の都合の良い時間を自動提案、ビデオ会議連携)\n" "- **差別化要因:** (例: 業界特化のテンプレート、独自のレコメンデーションエンジン)\n" "- **雰囲気・トンマナ:** (例: ミニマルで洗練されたデザイン、直感的でスムーズな操作感)\n" "- **具体的なUI構造:** (例: イベント登録するためのフォーム、参加者の都合の良い時間を提案するカレンダー)\n" "**ユーザーに質問を返さないでください。\n" "**与えられた情報からコンセプト案を構築し、完成したコンセプト案のテキストのみを返してください。\n" "**前置きや挨拶、説明は不要です。" ), tools=[], sub_agents=[], ) UI生成 以下がプロンプトをもとにHTMLでUIを生成するAgentのサンプルコードです。 既出のセクションにも書きましたがUI生成はさまざまなサービスが生まれており、群雄割拠です。前述の通り最終的に内製のAI Agentをさらに作り込んでいくかどうかはわかりません。一方、生成ロジック以外の要素、例えば自社のデザインシステムをAIからReadableな状態にすること、デザインのアイデンティティやコンセプトを言語化・構造化すること、AIを前提としたアプリ制作のワークフローを発明すること等は、組織の資産であり、独自性であり、差別化要因になりうる点だと想像しています。 def create_page_generate_agent_v0_3(model_name: str) -> LlmAgent: """HTML生成エージェントを構築します。""" mcp_toolset = get_ds_mcp_tools() html_generation_agent = LlmAgent( model=model_name, instruction=""" ユーザーのアイデアを基にデザインを新規生成してください。 特に指示されない限りはスマホアプリのデザインを生成してください。 メルカリのデザインシステムに厳密に従った高品質なHTMLを生成するため、以下のステップを順守してください。 **ステップ1: デザインシステム参照画像の確認** メルカリのデザインシステムに準拠した表現を行うため、関連するコンポーネントやパターンの参照画像を必ず確認してください。 - `mcp_get_ds_master_image_map` ツールを呼び出し、利用可能なDS Master Imageのカテゴリと画像のリストを取得します。 - ユーザーの要求や生成する画面のコンテキストに合致する画像があれば、その画像の `category` と `filename` を引数として `mcp_get_ds_master_image_details` ツールを呼び出し、詳細な説明と画像URLを取得します。 - 取得した画像URLは、必ず `download_and_save_image_as_artifact` ツールを使用してその内容をシステムに読み込ませ、実際に画像を確認してください。 - これらの参照画像を十分に確認し、スタイル、レイアウト、インタラクションなどがメルカリのデザインシステムに沿っているかを確認した上で、HTML生成に活かしてください。 **ステップ2: アイコン・ロゴ素材の利用** アプリケーションで使用する汎用的なアイコンやロゴは、必ず `mcp_get_image_asset_map` ツールを使用して画像アセットのURLリストを取得し、そこから適切なものを選択してHTMLに埋め込んでください。 **ステップ3: HTML生成と出力** 上記のステップで得られた情報と、以下の「基本デザイン情報」を総合的に判断し、HTMLを生成します。 - **出力形式:** 純粋なHTMLコードのみを出力し、他の説明やコードブロックは含めない。完全な HTML コードのみを出力してください。説明や ```html ... ``` は不要です。 - **単一ファイル:** CSS/JavaScriptは外部参照せず、`<style>`タグや`<script>`タグで内部に埋め込む。 プレースホルダー画像 ユーザーアイコンや商品画像のプレースホルダーが必要な場合は、`get_random_sample_image_url` ツールを使ってください。 **画像のURLをmcpやツールで取得した場合:** 1. mcpやツールから取得したURLの画像を処理する必要がある場合 (例: 画像の内容を説明する、画像から情報を抽出する、画像に基づいて何かを生成する)、まず `download_and_save_image_as_artifact` ツールを使用して画像を取得し、システムに保存してください。 2. このツールを実行すると、システムが自動的に画像を読み込み、あなたがその内容を理解できるようになります。 3. もし画像URLへのアクセスにMCPの認証が必要だと判断される場合は、ツールの `use_mcp_auth` 引数を `True` に設定してください。それ以外の場合は `False` に設定してください。 """, name="HtmlGeneratorAgent", description="Generates a single HTML page based on user idea.", output_key="generated_html", tools=[ get_random_sample_image_url, check_link_status, download_and_save_image_as_artifact, mcp_toolset, ], before_model_callback=before_model_load_artifact, ) return html_generation_agent UI/UX評価の取り組み 以上はUIを生成する仕組みの一端ですが、並行して、生成されたものをUI/UXの観点で評価する仕組みの構築にも取り組みはじめています。品質評価観点を定め、仮想的なペルソナを生成し、自動生成されたUIにフィードバックをします。 静的な画面の評価に加えて、Browser Use等を用いて画面操作をさせつつ、フィードバックを獲得していく仕組みです。全体のイメージとしては、Amazon社の「 UXAgent: An LLM Agent-Based Usability Testing Framework for Web Design 」のような構成で、AIによるUX評価の概念実証に着手しており、納得性の高いフィードバックを得られるケースも確認できています。 UI生成については内製のフロントエンドがあるのですが、UI/UX評価に関してはCursor等のエージェントを使いながら小さく開始しています。有用性が確認できたら、どういう実装であるべきか、アプリ開発のワークフローの中でどう使っていくのが有効かを検討していきたいと考えています。 おわりに PJ-Auroraの取り組みを通じて、生成AIの可能性と課題の両面を実感しています。技術の進歩は目覚ましく、UI生成の精度は日々向上していますが、同時に「何を作るか」「どう作るか」「私たちの仕事の仕方はどう変わるか」という本質的な問いに向き合うことがより重要になってきていると感じます。 メルカリでは引き続き、お客さまにより良いサービスと体験を提供するために、新しい技術と向き合いながら開発をしています。生成AIという新しい道具を使いこなすために、私たち自身も学び続けていきます。
こんにちは。メルペイ Payment & Customer Platform Manager of Managers の @abcdefuji です。 この記事は、 Merpay & Mercoin Tech Openness Month 2025 の19日目の記事です。 要旨 2024年末から2025年6月の半年間で、メルカリではAIツールの導入において劇的な変化を遂げました。数十名から始まったパイロットプロジェクトが、わずか4ヶ月で1,100アカウントを超える全社規模の導入に成功しました。エンジニアの9割以上がAIコーディングアシストを活用する組織へと変貌しています。 この記事では、エンジニアリングマネージャーの視点から、組織変革の成功要因を分析し、技術負債解消への新しいアプローチや個人の開発体験の変化について紹介します。特に、トップダウンのビジョン、ボトムアップの自発性、環境整備、そして可視化による推進力の4つの要素がどのように組み合わさって変革を実現したかを詳しく解説します。 始まりは一つのリクエストから 2024年末の状況 全ての始まりは、同僚からの「Cursorを使ってみたいのですが、導入可能でしょうか?」というシンプルなリクエストでした。 当時のメルカリには、既にAI Code AssistsツールとしてGitHub Copilotが導入されていましたが、実際の利用状況は以下の通りでした: 一部のアーリーアダプターである数十名〜100名(weekly active user)規模で利用されている しかし、多くのエンジニアが「まだ使うには早い」と感じている状況 高度なコンテキスト理解が不十分で、単一ファイルや行単位の修正提案が主流 プロジェクト全体を理解した提案には至らず、AIアウトプットの質がプロダクション開発に適応できていない状況 正直、私自身もGithub Copilotを使っていましたが、開発の現場で本格的にAIを活用するレベルには程遠いと感じていました。 転換点:2025年2月の承認 Cursorは2024/04〜07頃に一度検討されましたが、当時は導入の判断には至りませんでした。 しかし、2025年2月、会社として本格的なAI導入の承認が下りました。数十名のパイロットプロジェクトとしてCursor導入がスタートしました。 初めてCursorを触った時の感動は今でも鮮明に覚えています。特に印象的だったのは、Cursorの「コードのインデックス化」機能でした: プロジェクト全体のコンテキスト理解 既存のパターンを学習した文脈に沿った提案 大規模リポジトリでのコード理解スピードの向上 まだ数万行を超える巨大なリポジトリでは不安定さや上手く機能しない場面もありましたが、主にオンボーディングの側面でスピードが爆速になりました。マネージャーである自分はコードへのコミット機会が減りつつありましたが、Cursorを使ってどの機能がどのように実装されているか非常に容易に特定できるようになりました。 爆発的普及の4ヶ月間 驚異的な成長 2月から6月現在までの数字を見ると、その変化の大きさが分かります: (図: Cursor Usage Summary) アカウント数 :数十名 → 1,100アカウント超 エンジニア利用率 :9割以上が何らかのAIコーディングアシストを活用(Cursor以外にもJetBrains AI、Google Code Assist、Claude Codeなど) 普及範囲 :エンジニアからPdM、デザイナーまで拡大 社内の熱量の変化 数字以上に驚いたのは「熱量」でした。3月から5月の間、社内で起こっていたことは以下の通りです: 毎週複数のAI関連イベントが社内で開催 一つのイベントに100名以上の参加者がいるケースも エンジニアだけではなく、PdMなどの別職種への広がり 社内のオフライン、Slack上で聞こえる会話がAI一色に染まっていきました。 (図: 社内AI開発支援ツールについて語ろう企画) 「隣のチームでCursorの勉強会やるらしい」 「今度MCPについて話すイベントやります」 「AIで○○を楽にしました」 エンジニアから始まった波は、さまざまな職種の人たちにも広がっていきました。マネージャーとして、この自発的な学習意欲の高まりを目の当たりにできたのは本当に感動的でした。 成功の4つの要因 この爆発的な普及を振り返ると、4つの要因が絶妙に組み合わさっていたことが分かります。 1. トップダウンの明確な意志 経営層からの「AIを活用していく」というメッセージは、単なる推奨ではありませんでした。会社の未来への投資であり、明確なビジョンの表明でした。トップが本気だからこそ、現場も本気になれる。その土台があったからこそ、後に続く変化が可能になったのです。 そしてそれを推進するリーダーがいました。私はCursor導入を担当しましたが、Cursorだけではなく、エンジニア職種を超えて生成AIを導入する非常に強いリーダーシップが社内にモメンタムを生み出しました。 2. ボトムアップの自発的な情熱 トップダウンが生み出したモメンタムをさらに加速・継続させたのは「Move Fastな人たち」の存在でした。通常、組織変革では推進役を各チームに配置し、計画を立て、ロードマップを作成しますが、今回のCursorに関しては以下のような声が、あちこちから自然発生的に生まれました: 例として メルカリモバイルのAI Hackathon PCP LLM Week アーリーアダプターがいる。挑戦する文化がある。そして何より、学んだことを共有したがる人たちがいたことにより推進が大きく加速しました。 3. 環境の整備 このモメンタムの維持には環境整備を支えてくれたチームも大きな要因です。CursorだけではなくさまざまなAIツールが登場し、社内で利用したい声が多く上がりました。Cursorもここまでの人数規模が利用できる状態にするために社内のプロセス整備が行われました。ワンボタンでアカウント申請できる仕組みや、新規ツール導入時のセキュリティレビュー・予算レビューなどのさまざまなプロセスを、一体となって環境整備をしてくれました。 Cursorにおいては、Slackから簡単にアカウント発行までできるように調整していただきました。 (図: Cursorアカウント発行アナウンスメッセージ) 4. 可視化という触媒 最後の要素は、「ダッシュボード」による可視化です。 (図: Cursor Dashboardn) (図: Devin Dashboard) CursorをはじめDevin、Claude Code with LiteLLM、GitHub Copilotのダッシュボードを用意し、チームがどのくらいAIを使っているかを可視化しました。これにより、使いこなしているチームとまだ利用頻度が高くないチームを把握し、それぞれの背景を深掘りしていくことで、さらなる浸透のためのアクション定義につなげました。 可視化による競争ではなく、「触発」が生まれました。同僚の活用方法を見て学び、自分なりの使い方を発見する。そんなポジティブなサイクルが会社全体に広がりました。 チームレベルの開発における変革 ここからは組織ではなく1チームの開発状況の変化に関して話します。 技術負債への新しいアプローチ AIの導入が進む中で、私たちのチームに予想外の変化が起こりました。 私たちPayment & Customer Platformチームは、リリースから6年以上が経つシステムです。6年間、さまざまなプロダクトチームからの要求に応え、機能を追加し、時には妥協しながら成長を続けてきました。その結果、技術負債が蓄積されていました: 従来の課題: yak shaving状態:積み重なった実装・複雑な仕様により、一つの小さな改善に大きなコストが伴う課題 改善系のタスクの優先度が低く、時間が確保できず放置された課題 AI(Cursor / Claude Code)による変革: 大規模な内部リファクタリング・リアーキテクチャのような優先度が低く設定されやすいタスクの解消スピードが向上 ルール・コンテキストの共有による一貫性のある修正が可能 これまで「いつかやろう」で終わってしまいがちだった大規模な改修プロジェクトに、以前よりも継続的かつ素早く技術負債解消できる可能性が出てきたと感じています。 今後への展望 さらなる活用領域の拡大 – 開発だけではなく、開発プロセス全体でAIを活用していく仕組み作り( One Person, One Release ) PMもEngineerも壁を越えていきます。一人の人が企画から開発、QA、リリースまで一気通貫で出来ることを目指します。 技術の壁を越え、ドメイン知識を越え、役割を越えて行くためのAIの活用とし、それらを使い熟すのです。 標準化 – 個人やチームの知見や開発手法の横展開していく仕組みづくり 例えば、CLAUDE.mdをどのように作成し、どのようなルールを記載しているか、どのようにドメインを表現しているか、チームによって独自に進化が進んでいます。それぞれのチームがAIによってさらなる生産性を得るために、導入や利用のプロセス自体の標準化を行いたいと考えています。 このAIトレンドのスピードの中で、さまざまな手法が即座に古くなっていくと思います。古くなったものを即座に捨て去る覚悟を持ちつつ、AIを活用し生産性を向上させていく未来への道のりを作り始めています。 まとめ この半年間で、メルカリはAIツールの導入において以下を実現しました: 組織的な成功 :1,100アカウントを超えるユーザーへのCursor導入 文化的な成功 :自発的な学習・普及文化の醸成 成功の鍵は、トップダウンのビジョン、ボトムアップの自発性、環境整備、そして可視化による推進力の組み合わせにありました。AI時代の組織変革において、技術導入だけでなく、文化と人の変革が重要であることを改めて実感しています。 最後に この目まぐるしい変化に楽しく向き合えているのは、周りの同僚たちの存在です。 毎日のように新しいツール、開発体制、ユースケースなどのインプットとアウトプットする機会に溢れており、AI関連の情報交換は純粋に楽しく刺激的でした。この「集合知」でAIに対して前向きに挑めています。 以上、ありがとうございました。 明日の記事は cyanさんです。引き続きお楽しみください。
Design System チームの engineering manager をしている vwxyutarooo です。 私達はメルカリのアプリ・ウェブ開発に利用している Design System をフルリニューアルしました。 この記事で Design System に抱えていた問題とそれをどのように解決しようとしているのか、そのコンセプトを紹介していきます。 既存の Design System に抱えていた課題 既存の Design System は社内で 3.0 と呼ばれており、 GroundUp と呼ばれるメルカリのアプリとウェブを刷新するプロジェクトの一部として2020年頃からデザイン・開発が始まりました。 3.0 と聞くと随分進んでいるように見えますが、様々な開発背景により特定プラットフォームを対象にしたものや、日の目を浴びることのなかった過去のバージョンなどが含まれており、実質 3.0 が全社的に取り組んで開発された最初の Design System v1 となっている背景があります。 おおよそ 5 年の運用期間を経て、3.0 で作られたコンポーネントは当初の利用想定ケースを大きく超える状況に対処する場面が多く見られるようになりました。その結果、多数の新規機能開発で Design System のコンポーネントでは表現できず、シンボルをディタッチして変更を加えたコンポーネントや社内でカスタムコンポーネントと呼んでいる非公式のコンポーネントが多数作成される事態に陥っていました。 なぜこのようなことが起こったかを、ItemObject と呼ばれているコンポーネントの例を用いながら簡単に解説します。 これは複数のスクリーンで頻繁に使用されるコンポーネントです。3.0開発時は共通と思われるパーツだったため単一のコンポーネントとして切り出され、いくつかのユニークな要素をプロパティによって表示・非表示を切り替えることで対応していました。社内ではこれを polymorphic API と呼んでいます。 しかし 3.0 リリース後の継続した機能開発により必要な要素は増え続け、必要とされる表示パターンは増え続けました。 この方式の難しいところは個別の UI 最適が進むほど考慮すべき組み合わせパターンが倍に増えていく点です。さらに、特定の要素 A が表示されているときに出現する要素 B or C のように構造が深くなっていき、複雑さが増していきます。私達はこの構造をコンポーネントの Polymorphic API と定義し避けるべきコンポーネントデザインと考えています。 この状況を打開するため、コンポーネントの定義を刷新し異なるコンセプトで Design System を4.0として再構築することにしました。 Atomic Design Methodology 新しいコンポーネントの設計指針として Atomic Design を採用することにしました。古くから存在した概念で、2013年に Brad Frost によってそのアイディアが初めて提唱されたものです。 Atomic Design – Brad Frost Atomic Design は旬をすぎたものとして扱われるようになって久しいですが、これは多くの場面で誤解のもとに運用されたり、拡大解釈されたりすることで、本来意図していない利用をされていることが大きいと考えています。 Brad Frost: Is Atomic Design Dead? – Hatch Conference Berlin 2023 よくある誤解として Atomic Design を実装リードで適用しようとしてしまう、或いは実装でのみ実現しようとしてしまう例がよく見られます。 私達の解釈では、Atomic Design は Design System を開発・運用するデザイナーとエンジニアのためのコンポーネント設計フレームワークであり共通言語です。実装が Atomic Design を強く意識する必要はなく、利用者に強調すべき情報でもありません。 Atomic Designでは、UIの部品を最小単位の「atoms(原子)」に分解し、それらを組み合わせて「molecule(分子)」のようなより大きな部品を構成します。以前は一つの部品として扱っていたものを、複数の小さな部品に分割して組み立て直す考え方です。 Atomic design によるコンポーネントの分解・設計手法に関しては Brad Frost 本人を含む多くの解説記事や動画が存在するため詳細は省略しつつ、先程紹介した Item Object を 4.0 の考え方で構築した例で簡単に紹介します。 まずセオリー通り各コンポーネントをその役割の最小単位にまで分割していきます。 以下の画像の例も、3.0 では1つのコンポーネントとして扱われていましたが、4.0 は 2 つの atoms と呼ばれる最小単位のコンポーネントになります。そしてこれらのパーツを組み合わせてさらにパーツを構成します。この atoms から構成されるコンポーネントを molecule と呼びます。 これを繰り返し、最終的にバラバラのパーツから ItemObject などのよりハイレベルなパーツを構築可能にします。前提として UI をパーツで組み立て可能にするという点を念頭に置きつつ、組み立て後のパーツが汎用的なコンポーネントであるものを molecules や organisms として提供します。 ItemObject のようにユースケースが細かく別れているコンポーネントに関しては使用頻度の高い汎用的なものを優先的に Design System のコンポーネントとして管理しつつ、利用シーンが多くないものや僅かな要素の違いを持つユースケースにはあえて organisms として完成形を提供せず、利用シーンで組み立てるようにしています。 コンポーネントを利用時に組み立てる、というのも場合によっては利用者の負担になります。そのため、組み立て方法の例をレシピ/設計図として配布し補助的に活用しています。 レシピ/設計図を提供するかどうかは、コンポーネントの利用頻度やコンテンツ/コンテキスト依存度から判断しますが、レシピや設計図 (Blueprint) に関しては Atomic Design とは異なる概念となるため次の節でもう少し詳しく紹介します。 Component Design Strategy Atomic design は Design System のコンポーネントの分解・構築のためのフレームワークを提供しますが、なにがコンポーネントであるべきか、どんなコンポーネントが Design System として管理されるべきかその境界を示してはいません。 私のチームでは Design System から内向きのレイヤーを Atomic Design で、外向きのレイヤーを自分たちで独自に設計しました。次の図はそのレイヤーを簡易的に表現したものです。内側に行くほど Design System で、外側に行くほど Design System ではなくなります。厳密に Design System チームの持ち物として責任を追うのは青の領域ですが、現実的にはっきりとした境界線を引けることは稀で、その境界はグラデーションになっていることが多いため、そのグラデーションを意図してこのような図で表現しました。 1つ1つのレイヤーを順番に解説していきます。 Snowflakes ワンオフコンポーネント。コンテンツやコンテキストに依存しているなどの理由から Design System としては考慮されない 控えめな使用を推奨 Custom Component Design System のコンポーネントスペックでは表現できない UI を構成するため、シンボルからディタッチされたり、stroke など Figma 上で制約を設けることができないプロパティをコンポーネントのスペックを超えて改造されたものを指す Design System としては非常に不本意なコンポーネントであるため将来的にそのスペックが Design System でサポートされるか、或いは UI の仕様を調整することで薄くなっていくべきレイヤー Blueprint 直訳すると青写真という意味になりますが、設計図や完成予想図の意味で使用される Blueprint は、Figma のデザインデータから iOS, Android, Web のソースコードまで包括的にその設計図が提供される 主に Design System Component とするにはコンテンツ/コンテキスト依存が強いが頻繁に活用されるもの、或いは snowflakes のようなワンオフに近い用途を持つが、その組み立て方法が複雑なときに活用する Design Recipes Figma のデザインファイルでのみ設計図が提供されるコンポーネント。ソースコード上では提供されない フレームワークの恩恵を受けるなど実装上コンポーネントとして定義する必要性が低いものに対し、デザイン効率化のため Figma のデザインファイルでのみコンポーネントとして利用 (レイアウト系のコンポーネントに多い) Blueprint がデザイン (Figma) とソースコード両方のレシピを提供するのに対し、Design Component はデザイン (Figma) のレシピのみが提供される Design System コンテンツ/コンテキスト非依存で再利用可能な独立したコンポーネント 実はこれらのレイヤーは Brad Frost により提唱されている vocabulary に深く影響を受けているため、彼に詳しい人にとっては既視感のあるものになっています。 ただこれらには Atomic Design のような明示的な名前はついていないため、単に記事中の表現から component vocabulary と呼ぶことにします。 Design system components, recipes, and snowflakes すべての UI コンポーネントが Design System で完結するデザイン組織が最も strict なデザイン組織と言えるかもしれません。実現は難しいですが、そのような組織も少なからず存在しているようです。 このモデルは、もう少し合理的な妥協ラインを求めた場合にとてもフィットします。プロダクト開発でどうしても発生するコンテンツ依存なコンポーネントをワンオフとして一定数許容しつつ、そこにボキャブラリーとレイヤーを与えることで管理対象とし、薄く維持するためのマインドセットを生み出すことができます。そして、Design System と Snowflakes の間を埋める再利用可能だが Design System として管理するには十分な動機が (まだ) ないものをレシピとすることで、全体のコンポーネントレイヤーにグラデーションを与え、メンテナンスコストとリターンの最適化を図る意図があります。 コンポーネント設計・分割指針 次に Design System コンポーネントの設計・分割指針を見ていきます。冒頭で紹介した通り、以前のシステムでは最終的に1つのコンポーネントに振る舞いや variant を持たせ過ぎたことで利便性やメンテナンス性の低下を招きました。 これらの教訓を踏まえ、新しいシステムではセマンティックでシンプルな分解を重視し、以下の4つをコンポーネント設計の指針としました。 Semantic “ビジュアル的に近いものをコンポーネントとするのではなく、挙動や意味的な分類によってコンポーネントを定義/分割するし常に一貫した振る舞いを提供します。” 例としてメルカリにはチップと呼ばれているラウンド状のクリッカブルなコンポーネントがあります。 3.0 では全て1つのコンポーネントとして定義されていましたが、以下のようによく似た見た目を持つコンポーネントに対して大きく異なる振る舞いをすることが分かります。 トグル: タップする事にステートの変化 リムーバブル: タップすると消える 文字入力: タップが別のアクションのトリガーとなる 一見、共通コンポーネントの異なる状態を利用しているだけに見えますが、タップ可能領域やタップ時、およびホバー時 (Web) のスタイルなども違ってきます。1つのコンポーネントで表現するには不要な依存関係を考慮する必要が出てくるため、コンポーネントの分割対象とすることで依存関係がシンプルになりメンテナンス性が向上します。 Properties “異なる色、角の丸みや角ばっているなどに基づいてわずかな視覚的バリエーションを持つことができます。但しコンポーネントの形や振る舞いを変えることはできません。” 先に紹介したチップコンポーネントでは、ストロークのスタイルを solid/dotted のようなプロパティを持たせています。これは視覚的なバリエーションであり形や振る舞いを変えることはないため、1つ目の Semantic 指針を侵害しません。 Optional Elements “コンポーネントはオプショナルな要素を持つことができる (オプションのアイコンやテキストなど)” ボタンの prefix/suffix アイコンのような子要素を持たせることができます。 次の4つ目の指針で紹介する No polymorpihc API と相反することがないよう注意する必要があります。 No polymorphic API “一貫したAPIを持つべきである (必須となるプロパティが別のプロパティの存在の有無に基づいて変更されるべきではない)” 画像とコードの例を用いて解説します。次の画像は、3.0の古い Design System で定義されていた ItemThumbnail というコンポーネントで、3.0 では Large size のみに割引や値段の要素が許可されていましたが、これは polymorphic API とみなし、新しい指針では避ける設計としています。 “特定の条件の時に発生するネストされた条件”には、最終的に冒頭で紹介したような管理の複雑性を生じます。 Polymorphic API を含むコード例: ItemThumbnail( size = Medium ) ItemThumbnail( size = Large( discountPrice = 900¥, price = 1,000¥ ) ) 4.0 ではコンポーネントの分解と再構築により、これらの問題を回避しています。ItemTile という Organism コンポーネントを用意し、構成要素として ItemThumbnail を含む Atoms, Molecules を持たせています。 Polymorphic API を含まないコード例: ItemThumbnail( leftBottomContentSlot = <other atoms/molecules/organism> ) 結果 Atomic Design を採用した私達の Design System は、最終的に150弱の数のコンポーネントに再分解され、以下のようなコンポーネント分布の構成になりました。これが適切なのか過不足あるのかは現時点で判断することはできませんが、今後の運用で明らかになっていくはずです。 Atoms: 50 Molecules: 60 Organisms: 40 また、冒頭でから例として上げている ItemObject はそのレイアウトだけを提供する ObjectLayout と、パーツを組み上げる blueprint に分かれて提供する方法に着地しました。 ObjectLayout: ItemObject (blueprint): 条件分岐などで膨れ上がったコードも、iOS (Swift) で700行あったものが30行弱にまで削減されました。実際組立時に発生するコードもあるため純粋な削減とはなりませんが、コンポーネントの抽象化や汎用化に失敗していた部分が単純化できたと考えられます。 まとめ 今回の Design System 4.0 刷新プロジェクトを通じて、私達は過去の課題と向き合い、より柔軟かつ持続可能なシステムへと進化させるための重要な学びを得ました。 コンポーネントの過度な汎用化が複雑性を生み、メンテナンス性を著しく低下させる教訓から、Atomic Design の原則に立ち返り、コンポーネントを最小単位に分割し、再利用性を高める設計へと移行しました。これにより、各コンポーネントが単一の責任を持つようになり、変更やテストが容易になりました。 同時にコンポーネントがどうあるべきかを考え直しゼロから組み直すことで 3.0 で得た知識と経験を新しいシステムに反映することができました。 今後 Figma AI や Figma MCP をはじめとするデザイン及びコーディングの自動化において、ブランディングコンセプトを反映し、かつセマンティックな意味を持つ Design System コンポーネントはハブとしての役割や、AI に対してのコンテキスト提供者としてその重要性を増していくと考えています。 また続報があればお伝えしていきます。 最後まで読んでいただきありがとうございました。
こんにちは。メルコイン フロントエンドエンジニアの@y-arimaです。 この記事は、 Merpay & Mercoin Tech Openness Month 2025 の18日目の記事です。 本記事では、Web版メルカリからメルコインAPIへの疎通確認を行ったPoC(Proof of Concept)について、技術的な課題と解決策、そして得られた知見を紹介します。 背景と目的 現在、メルコインの機能を利用できるWebサービスは存在しません。そこで、技術的な検証として、Web版メルカリからメルコインAPIにアクセスできるかどうかを試してみることにしました。 今回のPoCでは、 Web版メルカリからメルコインAPIへの疎通確認 を主な目標とし、技術的な実現可能性を検証しました。 技術的な課題と解決策 1. 認証設計の複雑さ 既存のWeb版メルカリの認証システムは独自のユーザーID体系を使用していましたが、メルコイン側のマイクロサービスは異なるクラスタに存在しており、セキュリティ上の理由からそのIDをそのまま受け付けない仕様となっていました。 この問題を解決するため、プライバシーを考慮した識別子(PPID: Pairwise Pseudonymous Identifier)を利用する新たなOIDC(OpenID Connect)クライアントを作成する必要がありました。PPIDは、異なるサービス間でお客さまを安全に識別するための仕組みです。PPIDの詳細については、以下の記事をご参照ください。 メルコインにおけるシステム間のデータ分離を実現するための通信アーキテクチャ Applying OAuth 2.0 and OIDC to first-party services 2. インフラ周りの設定 メルコインAPIへのアクセスを可能にするためには、Gatewayやネットワーク周りなどのインフラ設定が必要でした。普段フロントエンドエンジニアとしての業務がメインの私にとって、この辺りは馴染みの薄い領域でした。 しかし、アーキテクトチームやSREチームなどさまざまな方にサポートいただき、必要な設定を進めることができました。この経験を通じて、マイクロサービス間の連携には多くのチームの協力が必要であり、またフロントエンドエンジニアとしても、インフラストラクチャーの知識の重要性を実感しました。 3. 未知のコードベースでの開発 今回のPoCでは、普段触れることのない複数のリポジトリでの作業が必要でした。大規模なコードベースを短期間で理解し、必要な修正を加えていく必要があり、これは大きなチャレンジでした。 この課題に対しては、最新のAIツール(特にCursorなどのAI搭載エディタ)を積極的に活用することで対応しました。特に新たなOIDCクライアントの設定では、普段触れることのないTerraformのコードを修正する必要がありました。しかしCursorの機能を活用して既存のOIDCクライアントの設定を分析し、その構造や仕組みを理解した上で、新しいクライアントの設定を進めることで、開発効率を向上させることができました。 実装の成果 今回のPoCでは、以下の2つの機能を簡易的に実装することで、Web版メルカリからメルコインAPIへの疎通確認を行いました: ビットコインの価格をチャートで表示する機能 取引報告書をダウンロードする機能 これらの機能実装を通じて、認証やAPI通信、ファイルのダウンロードなど、さまざまなパターンでの疎通確認を行うことができ、 Web版メルカリからメルコインAPIへのアクセスは技術的に実現可能である ことを確認できました。 PoCを通して学んだこと 一人での限界と効率的な進め方 PoCを進める中で、フロントエンドエンジニア一人でこのような大規模な検証を完遂することの難しさに直面しました。このような状況を受け、多くのチームの方々に協力いただきましたが、PoCという性質上、本番開発に比べて優先度が低く、各チームへの依頼が完了するまでに時間を要することも少なくありませんでした。そこで、未経験の領域にも果敢に挑戦し、「まずは自分でできることを探る」という姿勢で取り組むことで、チーム間のコミュニケーションコストを抑えつつ、効率的な開発を進めることができました。 AIツールの活用 前述した未知のコードベースの理解促進はもちろん、チャート機能や取引報告書のダウンロード機能の実装においても、AIツールは大きな効果を発揮しました。 開発の流れとしては、以下のプロセスを繰り返しました。 Cursorに要件を伝えてコードを生成 細部を自分で調整 または Cursorを活用して修正 動作確認 問題があれば2に戻る この方法により、極めて短期間で機能を完成させることができました。 また、これらの機能の実装では、フロントエンドエンジニアとして普段から慣れ親しんでいる領域だったことが、AIツール活用の大きなアドバンテージになりました。 正しいコードの形が頭の中にあるため、Cursorが生成したコードの良し悪しを即座に判断でき、適切な修正指示を出すことができたのです。この既存知識とAIツールの組み合わせにより、開発スピードは格段に向上しました。 複数のチームとの効率的なコミュニケーション メルカリグループのエンジニアリング組織は大規模であり、複数のチームから構成されています。 PoCを進める上で「誰に質問すれば良いか」が最初は不明でした。この問題に対しては、メルカリ全体のアーキテクチャを横断的に把握していアーキテクトチームに最初に相談し、必要なタスクと担当チームを特定しました。その後は、複数のチームに並行して質問や相談を行うことで、開発のブロッカーを最小限に抑えながら効率的に進めることができました。 まとめ 今回のPoCでは、Web版メルカリからメルコインAPIへのアクセスが技術的に実現可能であることを確認できました。この検証を通じて、フロントエンドエンジニアとしても認証やインフラなど、システム全体への理解を深めることの重要性を改めて実感しました。 また、AIツールの活用や効率的なチーム連携の方法など、今後のPoC開発にも活かせる知見を得ることができました。 この記事が、同様の技術的挑戦に取り組む方々の参考になれば幸いです。 明日の記事は @keitasuzukiさんです。引き続きお楽しみください。