TECH PLAY

株式会社メルカリ

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

261

こんにちは。メルカリ Engineering Officeのyasu_shiwakuです。 今年もメルカリとメルペイ・メルコインで2本のAdvent Calendarを実施します! ▶ Merpay & Mercoin Advent Calendar 2025 はこちら Mercari Advent Calendar とは? メルカリグループのエンジニアがプロダクトや会社で利用している技術、興味のある技術分野やちょっとしたテクニックなど知見をアウトプットしていきます。このAdvent Calendarを通じてクリスマスまでの毎日を楽しく過ごしていただければと思っています。 2024年のMercari / Merpay Advent Calendar Mercari Advent Calendar 2024 Merpay & Mercoin Advent Calendar 2024 公開予定表 (こちらは、後日、各記事へのリンク集になります) Date Theme / Title Author 12/1 Websocket XSS vulnerability discovery: My security journey at Mercari @philolo1 12/2 LLM Key Server: Providing Secure and Convenient Access to Internal LLM APIs @Hiroki Akamatsu 12/3 Shops Monorepo 5 years later: a tale of Bazel and Cursor @Jazz 12/4 Enhancing DX through Mercari’s Unified Platform Interface @whygee 12/5 [TBD] ハロのフロントエンドアーキテクチャ振り返り or Apollo MCP でテスト工数削減 @mattsuu 12/6 Engineering the Semantic Layer: Principles for Data at Scale @sathiya 12/7 [TBD] QAエンジニアがAIで日々の課題を解決した話 @yuga 12/8 Navigating Change: Learning to Reinvent in an Unstable World @Antony Chane-Hive 12/9 Search Results Quality Monitoring with LLMs @otter 12/10 [TBD] DCR の話 @task 12/11 [TBD] claims parameter の話 @kgoro 12/11 LiveContactToolにおける機微情報の取り扱い~CloudDLPを使ったマスキング @sters 12/12 TBD @tokku 12/13 [TBD] メルカリのナレッジマネジメント戦略 @t-hiroi 12/14 メルカリAdsが広告を届けるまでの話 @yanap 12/15 TiDB Resource Groupでワークロードを制御する @ogataka50 12/16 [TBD] From brownfield to greenfield: Shops FinOps journey @Sneha & @Darius 12/17 Building a Learning Culture with DevDojo @mariz 12/18 [TBD] Kubernetes Packet Capture @mshibuya 12/19 AI-Native開発を加速する AWS Kiro の導入と、Okta を活用したアカウント管理の自動化 @amenbo & @siroken3 12/20 PR駆動の変更、CI/CDで自動反映——Terraformで実現するJamf ProのIaC+GitOps基盤 @yu 12/21 [TBD] Non-AI Tasks in the AI Task Force @akkie 12/22 What It Takes to Trust a Token: Tales of OIDC & OAuth Security @Kahla 12/23 [TBD] Pj-neco development @Sneha & @Yu 12/24 メルカリのNotion Architecture ver.1 の話 @kiko & aisaka 12/25 TBD @kimuras 最初の記事は、「 Google CloudからGitHub PATと秘密鍵をなくす – Token ServerのGoogle Cloudへの拡張 」です。 どうぞお楽しみに!
アバター
こんにちは!メルカリ Engineering Office の @mikichin です。 来る11月13日、メルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます! 2018年に実施した「Mercari Tech Conf 2018」から7年の時を経て、久しぶりのオフラインでの開催となります。 テーマは「メルカリエンジニアリングの今」。 今年の全社的なテーマでもある「AI-Native」についてはもちろん、2018年以降メルカリグループのエンジニアリングがどのように変化してきたかを、技術・組織・カルチャーの観点からご紹介します。 オンライン配信はありませんので、ぜひ会場でご自身の目と耳で確かめてください!! セッションの紹介記事はこちらをご確認ください。 PASSION Stage のURL: https://engineering.mercari.com/blog/entry/20251008-mercarigears2025-passion-stage/ GROW Stage のURL: https://engineering.mercari.com/blog/entry/20251009-mercarigears2025-grow-stage/ MECHANISM Stage のURL: https://engineering.mercari.com/blog/entry/20251010-mercarigears2025-mechanism-stage/ 本記事では、オフラインイベントならではのセッション以外の楽しみ方をご紹介します! フロアマップ 会場は、メルカリのエンジニアリング組織における信念や行動の基盤となる共通認識を明文化した「 Mercari Engineering Principles 」をモチーフにした「PASSION Stage」「GROW Stage」「MECHANISM Stage」の3つのステージがあり、ここでプレゼンテーションを聞くことができます。 その他、Ask the SpeakerやTech Quizを実施している「COLLABORATION Lounge」、「Unconference」ルーム、「Break Area」があります。 スタンプラリー 会場に到着したら、名札を受け取ります。会場で参加者同士が話しかけやすいように、お名前や技術領域、所属など記載してくださいね。 受付時に、名札とあわせてスタンプラリーのカードをお渡しします。スタンプラリーの詳細はカードに説明文がありますが、セッションに参加したり、Tech Quizに回答したりするとステッカーをもらえるほか、参加者同士で交換しながら集めていきます。集めたステッカーの枚数でもらえるグッズが異なりますので、ぜひ全部集めてみてください! ポスターセッション 本イベントではプレゼンテーションだけではなく、ポスターセッションを準備しています。今回はEngineering組織だけではなく、メルカリR4Dラボでの研究も含め14つの発表があります。 ポスターセッションの詳細は、下記ブログ記事をご確認ください。 https://engineering.mercari.com/blog/entry/20251029-mercarigears2025-poster/ ポスターセッションでは、発表者の方が掲示されているポスターの前に立っているので、質問をしたり、情報交換をしたりできます。ぜひ、お気軽にお立ち寄りください。 ※常に、発表者がポスター前に立っているわけではありません。いない時間帯もありますこと、ご了承ください。 Ask the Speaker セッションは聞いて終わりではありません。各セッション終了後には、登壇者と直接お話しいただける時間を設けております。セッション内では触れられなかった詳細な内容から、率直なご質問まで、疑問を解消し理解を深めていただける貴重な機会です。 「COLLABORATION Lounge」までお越しください。 Unconference Area 事前に用意されたテーマを待つ必要はありません。ご自身が話したいトピックを持ち込み、その場で議論を始めてみませんか。メルカリメンバーと意見を交わすのはもちろん、当日に提示されるテーマをきっかけに知見を交換することも可能です。知識や経験が交差する場を、ぜひご活用ください。 「Unconference」ルームまでお越しください。 Tech Quiz メルカリのスペシャリストが用意したクイズに挑戦してみませんか。Backend、Clientなど各技術領域ごとにクイズを準備しています。普段あまり触れることのない分野でも大丈夫です。 Tech Quiz AreaにはQuiz作成者もいる予定なので、お気軽にお声がけください。また、参加者同士で意見を出し合って一緒に考えてみましょう! オリジナルグッズやお菓子 本イベント用に準備している「mercari GEARS 2025」オリジナルグッズです。 ぜひ、ステッカーを集めて「Stamp Rally Kiosk」でGETしてくださいね! 参加者同士でお話をするときのお供に、Coffee Standにて、オリジナルのお菓子やコーヒーを受け取ってください。 「mercari GEARS 2025」では、単なる情報伝達の場ではなく、オフラインイベントならではの経験を共有し、交流を通じて新たな機会が生み出されることを期待しています。 プレゼンテーション以外にもさまざまなコンテンツを準備していますので、ぜひ積極的にご参加ください。 「mercari GEARS 2025」のお申し込みは こちらから 。 イベント詳細 開催日時: 2025年11月13日(木) 11:00-18:00 概要: mercari GEARS 2025は、メルカリグループのエンジニアリング組織の技術への挑戦と、カルチャーを体感する技術イベントです。 本イベントは、単なる情報伝達の場ではなく、エンジニアたちが出会い、経験を共有し、交流を通じて新たな機会が生み出されることを目的としています。 参加費:無料 会場:TODA HALL & CONFERENCE TOKYO 参加方法: こちらのページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @MercariGears でお知らせしますので、気になる方はぜひフォローをお願いします。
アバター
こんにちは。株式会社メルカリ iOSエンジニアの kntk です。 9月19日から9月21日にかけて開催された「 iOSDC Japan 2025 」にメルカリはゴールドスポンサーとして参加しました。 本記事では、その参加レポートをお届けします! Swiftコードバトル 私kntkはiOSDC Japan 2025のday 0に開催された企画、 Swiftコードバトル2025 で優勝しました。 iOSDC Japan 2025の運営の皆さんには貴重な体験をさせていただき、本当にありがとうございました。 後日iOSDC Japan 2025運営から頂いた優勝記念品 Swiftコードバトルとは Swiftコードバトルはお題で指示された動作をするSwiftコードをより短く書けた方が勝ち、という競技です。 お題は決して難しいものではなく、少し練習すればSwiftプログラマであればどなたでも参加できる難易度を目指しています。 お題例1: 入力された文字列を逆順にして出力するプログラムを書いてください。 お題例2: 与えられた整数リストの要素の合計を計算するプログラムを書いてください。 Swiftコードバトル2025予選 の説明文から引用 一般的にはコードゴルフと呼ばれる競技になります。 昨年のiOSDC Japan 2024から開催されている企画で、今年が第2回目となります。 第1回目は私も参加し準優勝しました。 iOSDC Japan 2024に参加・登壇しました #iosdc #iwillblog 昨年からの変化として、問題の複雑度が上がったように感じました。その結果 回答が多様化し、戦略的な立ち回りが求められるようになった と思います。 その影響もあってか、今年は問題文と一緒にサンプルコードが提供されるようになりました。 感想 去年は決勝で敗退して悔しかったのですが、今年は問題との相性などが巡って無事優勝することができて非常に嬉しかったです。予選から接戦が多く、Swiftコードバトルの環境が成熟して来ているのを感じました。 また、 参戦することで対戦中により良い解法を思いついた際の爽快感や、逆に思い付けなかった際の悔しさを味わうことができ、Swiftコードバトルをより深く楽しむことができます。 是非皆さんも来年(開催された場合は)参戦してみてはいかがでしょうか。 Swiftコードバトルの詳しい解説や私の戦略を書いた記事もありますので、ぜひ興味があればご覧ください! Swiftコードバトル2025で優勝しました #iosdc #iwillblog 登壇 株式会社メルカリからは私がLTで登壇しました。 “奇妙”なSwift (LT5分): kntk Swiftにはさまざまな文法があり、それらは明示的・直感的で読みやすいことに定評がある一方で、Swiftの特定の文法を応用すると一見"奇妙"なプログラムも記述できます。 ”奇妙”なプログラムの背景にはさまざまなSwiftのテクニックが含まれており、解き明かすことで新たな発見を得ることができます。 このLTでは、”奇妙”なSwiftの例とそれらの背景にあるテクニックを3つ紹介しました。特に2つ目の例で紹介した、Switch文の内部で利用されているパターンマッチング演算子は利用することで冗長な表現を減らせる実用的なテクニックだと考えています。 実際にSwiftSyntaxなどの1st party libraryでも利用されています 。 また、最後の例ではSwiftコードバトルで利用できる関数呼び出しの文字数短縮テクニックを紹介しました。この構成はプロポーザル提出時に考えたものなのですが、day0のSwiftコードバトルで優勝したことによって綺麗なオチになって良かったなと思います。 メルカリスポンサーブース メルカリスポンサーブースではAIツールに関するポストイット企画を実施しました。1日1問、合計3問の質問を用意し実施しました。このセクションでは、ポストイットの回答結果を共有します! ※目視で回答の集計を行っている関係上、集計結果はおおよその値となります。 Day 0: 普段iOS開発で使っているAI Coding Assistant Toolは何ですか? 合計回答数: 約90件(1件のポストイットに対して複数回答あり) 回答数上位のツールから順に列挙すると以下の様になります。 Claude Code 月定額で利用でき、利用上限も多くコスパが良いと感じているため。 GitHub Copilot 企業が導入しているため。 学生は無料で利用できるため。 Gemini 学生は無料で利用できるため。 Cursor ChatGPT Codex Devin Amazon Q Developer Codeium Alex Sidebar Xcode用のAI Coding Assistant。 Zed Grok 私が初耳のツールも含まれており、新しいツールを知る良い機会となりました。 Day 1: iOSアプリの開発で、生成AIが最も役立つと思う作業は何ですか? 合計回答数: 約180件 次の回答が上位となりました。 テストコード生成 プロトタイプ作成 UI実装 コードレビュー 調査・コードリーディング リファクタリング また、来場者の方から具体的なプラクティスも聞くことができました。 実装より先にテストコードを生成することで、AIが特定の実装に依存したテストコードを書くのを防いでいる。(テストコード生成) AIの生成したコードは品質に疑問があるので、主にコードを読ませる用途で利用している。(調査・コードリーディング) 全体的にAIの使い方を試行錯誤しているお話が多く、さまざまな取り組みや現状の感触を共有いただきました。今後AI Coding手法が発展していくのが楽しみですね! Day 2: 生成AIがアプリ開発者の作業をどう効率化していると思いますか? 合計回答数: 約100件 全体的に作業効率化に関する回答が多く、具体的には次の項目の効率化が大きいという声がありました。 アイデア出し・壁打ち 調査 プロトタイプ 実装 レビュー 効率化の結果、「設計に集中できる」「意思決定が早くなった」というお話もありました。 私も業務でAIを使い冗長な作業が減った結果、設計に集中できるようになったと感じており、共感できるお話が多くありました。 まとめ メルカリブースに来てくださった参加者の皆さん、AIツールに関するノウハウを共有していただきありがとうございました!私自身も参加者の方とAIツールのノウハウについて話す中で大変勉強になりました。 最後に、iOSDC Japan 2025 の運営の皆様お疲れ様でした&ありがとうございました!また来年も参加したいなと思います! #iosdc #iwillblog
アバター
こんにちは。株式会社メルカリ iOSエンジニアの kntk です。 私kntkは9月19日から9月21日にかけて開催された「 iOSDC Japan 2025 」のday 0に開催された企画、 Swiftコードバトル2025 で優勝しました。 iOSDC Japan 2025の運営の皆さんには貴重な体験をさせていただき、本当にありがとうございました。 せっかくの機会なので、この記事では 私がどのような戦略やプロセスで参戦したのかを言語化 しようと思います。 後日iOSDC Japan 2025運営から頂いた優勝記念品 また、メルカリは「 iOSDC Japan 2025 」にゴールドスポンサーとして参加しており、その様子はこちらをご確認ください! iOSDC Japan 2025に参加しました #iosdc #iwillblog Swiftコードバトルとは Swiftコードバトルはお題で指示された動作をするSwiftコードをより短く書けた方が勝ち、という競技です。 お題は決して難しいものではなく、少し練習すればSwiftプログラマであればどなたでも参加できる難易度を目指しています。 お題例1: 入力された文字列を逆順にして出力するプログラムを書いてください。 お題例2: 与えられた整数リストの要素の合計を計算するプログラムを書いてください。 Swiftコードバトル2025予選 の説明文から引用 一般的にはコードゴルフと呼ばれる競技になります。 昨年のiOSDC Japan 2024から開催されている企画で、今年が第2回目となります。 第1回目は私も参加し準優勝しました。 iOSDC Japan 2024に参加・登壇しました #iosdc #iwillblog 昨年からの変化として、問題の複雑度が上がったように感じました。その結果 回答が多様化し、戦略的な立ち回りが求められるようになった と思います。 その影響もあってか、今年は問題文と一緒にサンプルコードが提供されるようになりました。 何をする競技なのか Swiftコードバトルの問題には文字数短縮余地のある 「最適化ポイント」 が複数個存在し、我々選手は 個々の最適化ポイントに対して文字数短縮方法を考え、文字数短縮を行っています。 問題が複数個の小問で構成されており、小問の合計スコアで競っている、というイメージを私は持っています。(実際には小問が相互に関係しあう場合があり、単純に可分できるわけではない。) 最適化ポイントについて、昨年の決勝問題を例に紹介します。 標準入力の各行に、ちょうど5文字からなる英単語が一つずつ並んでいます。 与えられた単語と「iOSDC」のハミング距離を出力してください。大文字と小文字は区別します。 「iOSDC」なら「0」、「CDSOi」なら「4」、「iosos」なら「4」を出力します。 すべての行についてこの手順を繰り返してください。 // 回答a while let a = readLine() { print(zip("iOSDC", a).filter { $0 != $1 }.count) } // 回答b while let a = readLine() { print(zip(a, "iOSDC").reduce(0) { $0 + ($1.0 != $1.1 ? 1 : 0) }) } この問題には結果的に以下の最適化ポイントがありました。 “iOSDC”と入力にどのようにアクセスするか? a. それぞれにインデックスアクセス b. zip でまとめてからアクセス (最短解) 異なる文字数をどの様にカウントするか? a. カウンタを持ってfor文でインクリメント b. reduce でカウンタをインクリメント c. filter.count (最短解) これらの最適化ポイントは問題に明示されていないので、まず最適化ポイントを発見する必要があります。 「ここは複数の書き方ができるな」と、一目見ただけで発見できるわかりやすいポイントもあれば、問題を解く中で問題の理解度が上がることで発見できるポイントや、間違い探しのようにじっくり考え込んでやっと発見できるポイントもあります。 最適化ポイントを発見した後は文字数短縮方法を考えて実装します。 Swiftの知識と競プロ的な知識を総合的に活用して短縮方法を考える必要があります (詳しくは後述)。 実際の回答を見てみると、回答aだと1, 2両方のポイントで最短解を採用できている一方で、回答bだと2で非最短解であるreduceを採用しており、2.の短縮方法で勝敗が決まった結果になっています。 このように、 問題に存在する最適化ポイントを発見し、最適な短縮方法を考える ことがこの競技の基本的な作業になると考えています。問題が複雑な場合は全ての最適化ポイントを発見・回答しきれず時間切れになることもあり、 最適化ポイントを発見する速さと短縮方法を考える速さも重要になってきます。 サンプルコード vs 0から実装 問題文と一緒にサンプルコードが提供されるようになったことにより、 大きな方針として二つの作戦 が存在していました。(コードバトル予選でも参加者間で話題になっていました。) サンプルコードを元に文字数短縮を行う作戦 初期実装コストがなく、個々の最適化ポイントに順に対処していけば安定してスコアを伸ばせる利点があります。その一方で、サンプルコードに存在する冗長な表現の修正に時間を要したり、既存のロジックや構造に縛られて大幅な変更をしにくいなどの欠点があります。 サンプルコードを用いず0からコードを実装する作戦 サンプルコードの構造やロジックに縛られないため、最初から一気に短いプログラムを記述して高いスコアを狙える利点があります。その一方で、初期実装コストが必要な上、テストケースが通らない間違ったコードを書いてしまい、時間を消費する危険性があります。 実際に取った作戦 私はサンプルコードを元に文字数短縮を行う作戦で進めました。理由としては後者に必要となる競プロ的な能力に自信がなかったというのと、前者の安定してスコアを取れる点が複数試合を行う上で有利だと考えたためです。 対戦前の準備 競プロ等でも一般的に有効な手法だと思いますが、 傾向を把握し、その対策を行っていました。 事前に頻出パターンとその短縮方法(テクニック)調査して知識化し、対戦中はそれらの知識を適用できるようにしていました。これによって、問題に存在する複数の最適化ポイントのうち 8-9割程度を事前知識で瞬時に発見して解くことができ、対戦時間を残りの1-2割(初見のパターンや一般化が難しい複雑なパターン)への対処に集中できていました。 具体的にどのような短縮テクニックを調査・利用していたのか、実際の準決勝の問題を例に紹介します。 標準入力の各行に、英字のみからなる文字列が与えられます。キャメルケースをスネークケースに変換し、改行区切りで出力してください。 出題側から提供されるサンプル回答(読みやすさのため一部変更) while let line = readLine() { var result = "" for (index, character) in input.enumerated() { if character.isUppercase && index > 0 { result.append("_") result.append(character.lowercased()) } else { result.append(character.lowercased()) } } print(result) } この問題では次のような文字数短縮テクニックが利用できます。 String.append(Character) は += で代替可能 RangeReplaceableCollection の実装由来。 String は RangeReplaceableCollection に準拠しているため。 If aaa && bbb は if aaa, bbb に代替可能 変数名の一文字化 共通項の抜き出し( r += c.lowercased() ) それらのテクニックを利用したプログラム while let l = readLine() { var r = "" for (i, c) in l.enumerated() { if c.isUppercase, i > 0 { r += "_" } r += c.lowercased() } print(r) } その他、多数のテクニックをドキュメントにまとめておき、対戦前に眺めていました。 また、 「この手法では短縮できない」という知識も持っておくことで、対戦中の試行錯誤時におけるノイズを減らしていました。 例を一つ紹介すると for 文より .forEach で書いた方が短い?-> for文の方が常に短い。 for i in a { と a.forEach { i in を比較すると後者の方が5文字多くなります。 また、 forEach のクロージャーで省略引数名 $0 を使った場合 i in を省略できますが、ここでの省略数は3文字なのでメソッド呼び出し部分だけで結果に2文字多くなり赤字です。 // 8文字 for i in a { // 13文字 a.forEach { i in // 10文字 a.forEach { 対戦中 先述の通り、対戦中は冒頭に事前知識を用いて頻出のパターンの文字数短縮を行い、 ほとんどの時間を初見パターンや一般化が難しい複雑なパターンの文字数短縮方法を考えることに集中していました。 具体的に文字数短縮方法を考えるプロセスについて紹介すると、 各最適化ポイントについて、 文字数短縮方法には主に二つの側面 があると考えていました。 A: 文法・記法を工夫する B: ロジックを工夫する A: 文法・記法を工夫する 既存の記述の文法や記法を工夫することで文字数短縮を行う側面 です。先述の準決勝での例にあるように変数名を一文字にしたり、 String.append(Character) を += に置き換えたりするなどが当たります。 また、予選の問題ではSwiftの型推論や標準ライブラリの関数・メソッドを応用して文字数を減らす場面がありました。(Swiftらしさが強く現れる問題で特に記憶に残っています。) コードバトル予選、ROT13変換問題の私の回答 while let p = readLine() { print(String(p.map { a in let k = a.asciiValue! &- 52 return a.isLetter ? .init( .init( 13...38 ~= k ? k % 26 + 65 : (k - 32) % 26 + 97 ) ) : a })) } Character.init(UnicodeScalar.init(...)) を .init(.init()) で代替 型推論によって型名を省略 String.init の期待する型( [Character] )が p.map の帰り値の型を経由してクロージャーのreturn statementの型推論まで伝播 Range.contains を ~= で代替 標準ライブラリに演算子定義が存在 オーバーフロー演算子 &- を利用して事前計算 通常の演算子だとランタイムエラーになるテストケースが存在 このように、 Swiftの知識(型推論・文法・言語機能・標準ライブラリなど)が活かされる側面 です。Appleの公式ドキュメントや TSPL (The Swift Programming Language) を読むことでこの側面の思考力が鍛えられると思います。 B: ロジックを工夫する 既存のロジックをより短い記述のロジックに変えることで文字数短縮を行う側面 です。こちらは平たく言えば競プロ的な側面です。ただし、実行速度向上ではなく文字数短縮が目的です。 実は先述した準決勝の私の回答は最短解ではなく、さらにロジックを工夫することで短縮できる余地がありました。(前回優勝者にご指摘いただきました。) while let l = readLine() { var r = "" for c in l { if c.isUppercase, r != "" { r += "_" } r += c.lowercased() } print(r) } index > 0 というのは、つまり「最初以外の要素の時」を意味する条件なので、こちらは r != "" で代替可能なわけです。また、コードバトル予選では有名な「番兵法」を利用することで文字数を大幅に減らすシーンもありました。 このように、 問題・プログラムの意図を読みとるのがこちらの側面になり、競プロ的な力が活かされる側面 です。競技プログラミングサイト等で過去問を解くことで、この側面の思考力を鍛えることができると思います。 また、AとBの側面は排他的ではなく、Bを適用した後の記述に新たにAが適用できる場合もあり、 AとBの組み合わせによって文字数短縮方法が多数存在していました。 戦略 A・Bの例で示したように、 より短い解に辿り着くにはAとB両方の側面を組み合わせて解法を考えることが必要になってきます。 しかし、解法を考える際はコードを書いてみないと実際に文字数短縮が可能か分からないことが多く、制限時間の中で試せる解法の候補数も限られてくるため、 ある程度解法に”あたり”を付ける必要があります。 ここで、 私は迷ったらAを優先して攻める戦略を立てました。 理由としては私がAの方が得意というのと、「Aの側面を極めた回答の方がSwift特有のテクニックが現れて面白いだろう」と考えたからです。 結果的に決勝でもSwiftの文字列展開を利用した手法を選択し、Swiftらしいコードで優勝ができたのは良かったなと考えています。 アスキーアートを出力する決勝問題の私の回答(見やすさのため一部スペースを省略) let a = "######", i = a + a, f = "\(i)##", j = f + f (中略) print( """ \(f) \(j) \(f) \(j) ## \(a) \(a) ## \(a) \(a) \(a)#### ## \(a) \(f+a) \(a) \(a)#### ## \(a) \(f+a) \(a) (中略) """ ) まとめ Swiftコードバトルは問題に存在する最適化ポイントを発見し、Swiftの知識と競プロ的な知識を総合的に活用して最適な短縮方法を考える競技です。制限時間があるため、事前に頻出パターンの対策を行うことによって対戦時間を有効に活用することができます。 Swiftコードバトルのテクニックは一見奇妙で役に立たなそうに見えるかもしれません。しかし その背景にはSwiftの文法・言語機能の知識やロジックを読みとる力などが隠れており、それらは日々の開発でも有益なものだと考えています。 自分も参戦する中で多くを学ぶことができました。 また、参戦することで対戦中により良い解法を思いついた際の爽快感や、逆に思い付けなかった際の悔しさを味わうことができ、Swiftコードバトルをより深く楽しむことができます。是非皆さんも来年(開催された場合は)参戦してみてはいかがでしょうか。 最後に、改めてiOSDC Japan 2025・Swiftコードバトル2025 の運営の皆さん、予選・本戦で対戦してくれた選手の皆さん、本当にありがとうございました! #iosdc #iwillblog
アバター
こんにちは!メルカリ Engineering Office の @mikichin です。 来る11月13日、メルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます! 2018年に実施した「Mercari Tech Conf 2018」から7年の時を経て、久しぶりのオフラインでの開催となります。 テーマは「メルカリエンジニアリングの今」。 今年の全社的なテーマでもある「AI-Native」についてはもちろん、2018年以降メルカリグループのエンジニアリングがどのように変化してきたかを、技術・組織・カルチャーの観点からご紹介します。 オンライン配信はありませんので、ぜひ会場でご自身の目と耳で確かめてください!! また、今回はプレゼンテーションだけではなくポスターセッションもあります。 ポスターセッションでは、発表者の方が掲示されているポスターの前に立っているので、質問をしたり、情報交換をしたりできます。ぜひ、お気軽にお立ち寄りください。 ※常に、発表者がポスター前に立っているわけではありません。いない時間帯もありますこと、ご了承ください。 本記事では、会場でしか見れないポスターセッションを一挙ご紹介! プレゼンテーションの紹介は下記記事をご参照ください。 PASSION Stageのセッション紹介は こちら 。 GROW Stageのセッション紹介は こちら 。 MECHANISM Stageのセッション紹介は こちら 。 まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちら からお願いします。 メルカリグループにおけるAI-Nativeなインシデント管理の全貌と未来像 LLMの普及により、インシデント対応・管理のあり方も大きく変わりつつあります。 メルカリグループでは、複雑で負担の大きいインシデント管理を「AI-Native」に進化させることを決定しました。 すでに導入している「IBIS」をはじめ、その周辺の仕組みや他のAI活用事例も紹介します。 AIを取り入れることで、MTTRの短縮だけでなく、対応者の負担・ストレス軽減やコスト削減、さらにサービス信頼性の向上が期待できます。 ただし、人間が担うべき領域も残ります。本発表では、メルカリグループの現在の取り組みと今後の展望をお伝えします。 The 3A’s: Simple Steps For Clean Unit Tests ソフトウェア開発のスピードが加速する中、新機能の追加や修正には、既存の機能を意図せず壊してしまうリスクが常に伴います。適切な安全策がなければ小さなミスが本番環境にリリースされ、多くのお客さまに影響を及ぼす可能性があります。 だからこそ、ユニットテストは極めて重要です。優れたユニットテストはコードの動作を検証するだけでなく、プロダクトの安定性と信頼性を確保し、開発チームが自信を持って変更を行える環境を支えます。 では、どうすればテストをシンプルでクリーン、かつ効果的に保つことができるのでしょうか。 そのための実績あるアプローチのひとつが、Arrange(準備)、Act(実行)、Assert(検証)の3Aフレームワークです。この3つのステップに従うことで、明確で保守性が高く、信頼できるユニットテストを簡単に書けるようになります。 Autonomous Support – Leveraging AI Bots for Scalable and Intelligent Operational Assistance 現在、エンジニアはSlack上での場当たり的かつ反復的な質問対応や、絵文字によるトリアージといった非効率なワークフローに多くの時間を費やしており、チームによっては業務時間の10〜20%以上が問い合わせ対応に割かれるという課題があります。私たちはこの課題に対し、Slack上の雑多な問い合わせを迅速で信頼性の高い回答と標準化されたチケットに変換する、AI支援の自律型サポートシステムを構築しています。このbotはSlack上で直接対応を行い、適切なJIRA/GitHubチケットのトリアージや共有ナレッジベース(ドキュメント、過去のチケット、Slack、ソースコード)の検索を行い、回答を提案します。人間の対応が必要な場合は担当者へ引き継ぎ、自己完結可能な場合はその場で対応を完了し、そこから学習を重ねます。これにより、応答と解決の迅速化、中断の削減、そして自律解決率、エスカレーション率、削減できたエンジニア工数、CSAT(顧客満足度)、特定されたナレッジギャップといった指標を通じて効果を測定します。また、既存のプラットフォームツールを再利用することで、迅速な開発を可能にしています。 Toward a Global Identity Platform メルカリは2019年に越境EC事業をスタートしました。開始当時、海外のお客さまは機能の限られた代行業者の購入ページを使って商品を検索し、購入する必要がありました。その後、海外のお客さまにより良い購買体験を提供するため、メルカリはシステムを拡張し、海外でのサービス展開を始めました。この拡大において重要な要件がグローバルアカウントの導入です。本セッションでは、これまでの取り組みで達成した成果を共有するとともに、複数の国のお客さまをサポートするためにアイデンティティ基盤をさらに拡張していく今後の計画についてお話しします。 非エンジニア組織のAI-Native化に伴走した実践知 非エンジニア組織が「AI-Native」へと変革する過程には、エンジニアの伴走が不可欠です。 本セッションでは、そのリアルな経験を紹介します。 (1) AI活用で期待する結果を得るために入出力形式を工夫した事例 (2) AIワークフローが突然停止した事例から学ぶライフサイクル管理の教訓 (3) AI生成アプリをGASを使って安全にデプロイする手法 といった、AI活用をプロトタイプから実運用への導くための実践知を共有します。 From Cluttered to Clear: Improving the Web Accessibility Design for Screen Reader Users in E-commerce With Generative AI 視覚障がい者や弱視のユーザーは、スクリーンリーダーを使ってオンラインショッピングサイトを利用する際に、多くの障壁に直面しています。複雑なレイアウト、不明確なコンテンツ構造、視覚重視のデザインにより、特に初めて利用するサイトではストレスが多く非効率な体験となっています。これまでの支援ツールは商品説明や画像の代替テキストなど、個別の要素に焦点を当てられてきましたが、ページ全体におよぶ構造やナビゲーションの課題には十分対応できていませんでした。本研究では、生成AIを活用してショッピングサイトのHTMLコンテンツを自動的に再構成し、アクセシビリティを改善する方法を検討しました。研究は3段階の構成で行い、まずスクリーンリーダーのユーザーにインタビューを行い、次に生成AIを搭載したブラウザ拡張機能を開発し、最後に自動監査と実際の使用で評価を行いました。このツールはスクリーンリーダーの操作パターンに合わせてウェブコンテンツを動的に整えます。実験の結果、生成AIで再構成されたページではナビゲーション効率、コンテンツの分かりやすさ、全体的な使いやすさが大きく改善することが分かりました。参加者からは「セクションの順序がより論理的になった」「閲覧による疲労が減った」といった声が寄せられました。この成果は生成AIが既存サイトの構造そのものに作用することで、包括的かつユーザー中心のアクセシビリティ改善を実現できる可能性を示しています。 量子インターネット ー安心・安全でサステナブルなオンライン社会の実現に向けてー メルカリの研究開発組織「R4D」では、近い将来に到来が予想されている「量子前提時代」を生き抜くメルカリを作るために、量子情報通信技術に関する研究を行っています。本ポスターでは、R4Dの量子チームが国内の研究機関と共同で行なっている量子インターネットに関する研究開発の全体像について紹介します。 中性原子量子コンピュータにおける表面符号を用いた消失エラー耐性プロトコル 光ピンセットによる中性原子アレイは、その優れた特性から量子コンピュータの有望な候補とされていますが、非パウリ誤り、消失誤り、リーケージ誤りが大きな課題となっています。従来の研究では、リーケージ誤りを消失誤りに変換できることは示されていましたが、変換された消失誤りが継続的に発生・蓄積する問題が残っていました。本研究では、この課題に対して、脱分極誤りと消失誤りを含む回路ベースのモンテカルロシミュレーションにより、消失誤りが平面コードに与える影響を評価しました。さらに、消失誤りへの耐性を高めるための新しいプロトコルを提案します。このプロトコルでは、オンラインでのコード変形を利用して、消失誤りが蓄積した「トラップ」から論理量子ビットを新しいトラップへと転送します。 「使い続ける力、未来をつなぐ」 人が使わなくなった製品を一度で使い終えず、次の誰かへ繋ぐ「リユース」は、私たち消費者が持続可能な社会のために選べる、最も身近で実践しやすい選択肢の一つです。本プレゼンテーションでは、リユースによって製品の使用期間がどれほど延長され、新品の購入をどれだけ代替できるのか、そのインパクトを明らかにします。 このお話を通して、皆様がモノを手放すとき、あるいは新しいモノが欲しくなったときに、リユースを当たり前の選択肢として生活に取り入れ、「モノに隠された新たな価値」を実践していただくためのきっかけをご提供します。 オンラインフリマアプリにおける商品説明の人間–AI協働執筆:売り手および買い手の視点からの考察 オンラインのフリマアプリは、個人が中古品を他の個人に販売する手段として、特に日本で人気を博しています。出品のプロセスには、出品者が写真をアップロードし、潜在的な購入者が閲覧するための商品説明を書く作業が含まれます。近年は、大規模言語モデル(LLM)を用いた商品説明作成を通じて出品時の出品者の負担を軽減する、人間とAIの協働の応用領域が注目されています。本研究では、LLMに基づく支援が出品者の体験や商品の出品価格に与える影響に加え、人間とAIが協働して作成した商品説明の魅力に対する買い手の主観的な印象や選好にどのように影響するかを検討します。本研究の結果は、LLMベースのツールがオンライン中古市場に及ぼし得る影響の理解に寄与するとともに、フリマアプリ向けの人間—AI協働執筆システムの設計上の考慮点や今後の研究の方向性に関する示唆を提供します。 メルカリAdsにおけるAIを活用した広告審査の取り組み 2024年9月に開始したメルカリAdsは、当初広告主から入稿いただいている広告に対しての審査を手動運用にて審査していました。 効率的な審査を模索し、AIを活用した広告審査システムを構築することで運用コストを削減しつつ、多くの広告素材に対して審査することが可能となりました。 そのAI活用事例を共有します。 BFF保守の課題とgRPC Federationによる解決アプローチ マイクロサービスアーキテクチャにおけるBFF開発では、複数サービス間の型変換や依存関係管理により保守コストが増大します。本発表では、この課題に対してgRPC Federationを採用し、Protocol BuffersにDSLで定義することによってBFFを自動生成し、保守コストを大幅に削減した実例を紹介します。また、AIを活用したDSL記述支援の取り組みについても報告します。 Engineering Office is a Hub, connecting Engineering together Engineering Officeはエンジニアリング部門のあらゆる部分を繋ぐハブの役割を持ちます。共通のオンボーディングからプロジェクトのサポート、エンジニアリングに関する情報まで、さまざまな要素を通してグループが方向性を合わせ、集中できるようにします。 本発表では、自動化やAI、継続的なサービスライフサイクルを活用してビジネスニーズに迅速に対応し、メルカリ独自のエンジニアリング文化を維持するための、私たちのプロジェクトの一部をご紹介します。 Mercari における Recommendation System の概要 メルカリではホームスクリーンや商品詳細画面など様々な所で recommendation が行われており、その裏側にはそれぞれの特性に応じた技術が使われています。 本発表ではメルカリにおける様々な recommendation とその裏で使われている技術について概要を共有し、議論を通じて情報交換したいと考えています。 「mercari GEARS 2025」のお申し込みは こちらから 。 イベント詳細 開催日時: 2025年11月13日(木) 11:00-18:00 概要: mercari GEARS 2025は、メルカリグループのエンジニアリング組織の技術への挑戦と、カルチャーを体感する技術イベントです。 本イベントは、単なる情報伝達の場ではなく、エンジニアたちが出会い、経験を共有し、交流を通じて新たな機会が生み出されることを目的としています。 参加費:無料 会場:TODA HALL & CONFERENCE TOKYO 参加方法: こちらのページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @MercariGears でお知らせしますので、気になる方はぜひフォローをお願いします。
アバター
1. イントロダクション こんにちは、Cross Border(XB) Engineeringのバックエンドエンジニアのosari.kです。本日は私が所属するリーダビリティチームの活動と、具体例として開発したバックエンドの共通パッケージについて紹介します。 メルカリグローバルアプリは、開発複雑性を抑えながら拡張性を保つためモジュラモノリスアーキテクチャを採用しています。モジュール間の依存関係を厳格化するため、システムはBFF層とTier1-4の階層構造で構成され、リクエストは上位から下位Tierへ流れます。モジュール間通信はProtocol Buffer + gRPCで標準化されています。詳しくは ブログシリーズ をご参照ください: グローバル展開にむけたアプリと基盤の再構築 グローバル展開を支える基盤の裏側 しかし、モジュラモノリスを採用するだけでは、マイクロサービス開発で発生した課題を解決できません。サービス間の差異によるメンテナンスコストやオンボーディングコストの増加は、モジュール間でも同様に発生する可能性があります。これらを解決するには、コードのリーダビリティと一貫性の維持が不可欠です。 そこで、グローバルアプリ開発の当初から リーダビリティチーム が組成されました。このチームは、モジュラモノリスの利点を最大限活かすため、Backendシステム全体のコードのリーダビリティを改善・維持する役割を担っています。メンバーは、アーキテクト、SREメンバー、バックエンドエンジニアで構成され、日本とインドの両拠点から参加しています。 一貫性のあるコードを維持することで、開発者を柔軟にアサインでき、効率的な配置が可能になります。また、AI Agentを活用した開発においても、明確なガイドライン、自動チェック、一貫したコードベースがAIの活用効果を高めます。 2. リーダビリティチームの役割と活動 2.1 目的 リーダビリティチームの主な目標は、コードの可読性を向上させることです。可読性が高く、一貫性のあるコードは、以下の効果をもたらします: 新しいエンジニアの学習曲線を緩和し、オンボーディングを加速 組織内での担当変更やチーム間の貢献を円滑化 バグの検出や修正を容易にし、開発の品質とスピードを向上 2.2 活動内容 リーダビリティチームは以下の活動を通じて、コードの品質向上と開発スケールを支援しています: コードレビュー : 複雑度の高いPRを中心にレビュー ガイドラインの作成と維持 : コードおよびPRガイドラインをGitHubリポジトリに集約 自動化ツールの開発 : CIによる自動チェックを実装 ワークショップの開催 : ベストプラクティスの共有 隔週ミーティング : ガイドライン、課題、改善点の議論 メトリクス駆動の改善 : 開発ボトルネックの特定と継続的な改善 中でもメトリクス駆動の改善については、GitHubのメトリクスを活用して目標を設定し、定期的にボトルネックを分析しています。特に以下の2つのメトリクスの改善に取り組んできました: 一人あたり週何個のPull Requestをマージできたか Pull RequestをOpenしてからマージまでの時間 これらを可視化することで、開発プロセスのボトルネックを特定し、継続的な改善につなげています。 3. AI時代のスケーラブルな品質管理 開発初期はメンバーが少なく、リーダビリティチームがほぼ全てのPull Requestをレビューできていました。しかし、開発が本格化し、開発メンバーの増加やAI Agent活用の普及により、PRのボリュームが急増し、従来の方法では対応できなくなってきました。 幸い、ガイドラインをGitHubリポジトリに集約・維持していたため、LLMを活用したレビューの自動化基盤は整っていました。課題は、この基盤でどうスケーラブルに品質を担保するかでした。以下、具体的な取り組みをいくつか紹介します。 Claude活用 ClaudeでPull Requestを複雑性とサイズの観点から自動分類し、ラベル付けを行っています。Claudeは、PRをより小さい単位に分割する助言も提供します。 このラベルを使い、複雑度が高いPull Requestを優先的にレビューできるようになりました。 また、GitHubに集約したガイドラインを活用したClaudeによるレビューの自動化で、コードレビューとガイドラインの適用を効率化しています。 効率的レビュー リーダビリティチームのレビューは必須ではありません。少なくとも一人のコードオーナーからレビューをもらえばPRはマージできます。これにより、リーダビリティチームが開発のボトルネックになりません。 一方で、マージされたPRの中で複雑度が高いものは後追いでレビューします。こうした複雑なPRから課題を検知し、新しいパターンやライブラリを導入することで、今後の開発を改善していきます。このアプローチで、効率的にレビューリソースを配分し、最も重要な部分に注力できています。 自動化 ガイドラインを全て把握するのは困難なため、機械的にチェック可能なルールはCIに組み込んでいます。 例えば、データベースのスキーマ設計では、社内のDatabase リライアビリティエンジニアと相談し、 PostgreSQL ガイドライン などを参考にガイドラインを策定しました。これを SQL Fluff のプラグインとして実装し、自動チェックを行っています。 これにより、レビュアーの負担を軽減し、人間のレビュアーはより高度な設計判断やアーキテクチャの妥当性に集中できます。 4. Feature Flag伝搬システムの設計 ここからは、リーダビリティチームが設計した品質管理の具体例として、Backendシステム全体で利用されるFeature Flag伝搬の仕組みを紹介します。 4.1 背景: Experiment Platformとモジュラモノリスアーキテクチャ グローバルアプリでは、新機能のリリースを安全に行うため、メルカリの基盤システムである Experiment Platform を利用しています。この中でもFeature Flagを活用しており、お客さまごとに各種機能のオン・オフを管理できます。 Feature Flagを使うことで、Web UI上で機能をオンにするお客さまを段階的に増やせるため、新機能のリリースを様子を見ながら進めることができます。問題が発生した場合も、システム自体を再デプロイすることなく、Web UI上で機能をオフに設定し、即座に無効化できます。Experiment Platformは割当(Assignments)を管理し、システム側でこの割当を取得して実装に組み込みます。 Feature FlagはMobileアプリやWebアプリでも利用されています。これらのクライアントアプリでは、1人のお客さまが継続して利用するため、アプリ起動時などにFeature Flagを取得してキャッシュできます。一方、バックエンドシステムではリクエストごとにお客さまが異なるため、Experiment PlatformのAPIを毎回呼び出してデータを取得する必要があります。 前述の通り、グローバルアプリのBackend systemではモジュラーモノリスを採用しており、クライアントアプリからの1リクエストが内部的には複数のモジュールへのリクエストを発生させます。 図1. 単純化した商品ページの例 全てのモジュールがFeature FlagのAssignmentsを必要とする可能性があります。 このようなアーキテクチャのため、もし各モジュールが毎回Experiment Platformからデータを取得する場合、APIのレイテンシがその分増加してしまいます。 図2. 各モジュールがExperiment Platformを呼び出すとレイテンシが増加 グローバルアプリの開発が進み、Feature Flagを利用する状況になってきた中で、レイテンシの増加を防ぐため、効率的にAssignmentsを参照するメカニズムとガイドラインが必要になりました。 4.2 設計要件と実装 Assignmentsの効率的な参照メカニズムを設計するにあたり、以下の要件を定義しました: Experiment Platformを一度だけ呼び出す ネットワークトラフィックを抑える 割当に型安全なアクセス手段を提供する 既存のコードが割当を使いたくなった場合のコードの変更量を最小限にする これらの要件を満たすために、 最終的に採用した解決策は、以下の3つの要素を組み合わせたものです: gRPC metadataを使ってモジュール間のAssignments伝搬 : シリアライズしたAssignmentsをgRPC metadata(HTTP Header)で運ぶ BFF層のServer InterceptorがExperiment PlatformのAPIを呼び出し、Assignmentsを取得 各モジュールのClient interceptorがAssignmentsをシリアライズしてgRPC metadataに設定 BFF層以外のServer InterceptorがgRPC metadataから取得し、デリリアライズしてAssignmentsを取得 context.Contextを使ってモジュール内のAssignments伝搬 : Server InterceptorがAssignmentsを context.Context に格納 アプリケーションロジックはAssignmentsを context.Context から取得 Protocol Bufferでの型定義 : Assignmentsを明示的に定義し、型安全性を確保かつコンパクトなシリアライズを実現 図3. BFFがExperiment Platformを呼び出し、AssignmentsをgRPC metadataで伝搬 BFFモジュールがExperiment platformのAPIを呼び出しAssignmentsを取得し、それを下位Tierのモジュールを呼び出すときにgRPC metadataで伝搬しています。 先程の図と異なり、BFFのみがExperiment platformを呼び出すため、レイテンシへの影響を抑えることができています。 モジュール内の伝搬に context.Context を利用しているので、アプリケーションロジックがAssignmentsを参照したくなった場合も、コードの変更は最小限に抑えられます。 一方でAssignmentsをリクエストに付与することでネットワークトラフィックには影響があります。そこで効率的なシリアライズ方法が必要です。 Experiment PlatformのAssignmentsは、パラメータ名と値のkey-value形式です。Feature Flagの値は "true" 、 "false" 、または未割り当ての3つの状態を取ります。未割り当ては、段階的リリースでお客さまの一部のみが割当対象になっている場合に発生します。 例えば以下のような形式です("feature_flag1"は未割り当てのため含まれていない): { "feature_flag2": "false", "feature_flag3": "true", "foo": "10", "bar": "OK" } 当初は map[string]string のJSON文字列としてシリアライズする案を検討しました。しかし、この方法では パラメータ名の長さがシリアライズ結果に影響し 、数百〜数千のパラメータをサポートする場合に破綻します。 そこで、 AssignmentsをProtocol Bufferで明示的に定義し、シリアライズする ことにしました。 上記の例をProtocol Bufferで定義するとこのようになります: message Assignments { optional bool parameter1 = 1; optional bool parameter2 = 2; optional bool parameter3 = 3; optional int64 foo = 4; optional string bar = 5; } この方法により、以下の利点が得られます: コンパクトなシリアライズ結果 : パラメータ名はシリアライズ後のバイト長に影響を与えることがなくなり、Experiment Platform利用者はわかりやすい名前を使うことができます 型安全性 : optional をつけることで、未割り当ての場合とfalseを区別できます。 *bool 型とすることで、Experiment Platformの利用時に陥りやすい罠である、未割り当て( nil )と false の区別が明示的になりました Protocol Bufferで明示的に定義する方法は、新規パラメータ追加時にProtoファイルの変更が必要という欠点があります。しかし、どちらの方法でもGoコードの変更とデプロイは必要です。一方で、 どのパラメータがどこで利用されているか明確に把握できる 利点を我々は重視しました。 4.3 検討の詳細 ここでは設計で候補案として上がったものとの比較内容を通じて検討の詳細の一部を紹介します。 4.3.1 in-memory cache案 gRPC metadataを使ったモジュール間の伝搬以外の方法として、in-memory cacheを利用したデータ共有という案がありました。 Experiment Platform ClientをProxyしてin-memory cacheのデータを返すことで、API呼び出しのレイテンシを削減する方法です。 in-memory cacheの場合、モジュール間でAssignmentsの伝搬をする必要がないため、ネットワークトラフィックを抑えることも可能です。 特に、多くのモジュールがAssignmentsを利用しない場合にgRPC metadataを使う方法に対して優位性があります。 図4. in-memory cacheを利用した方法(BFFとTier2 ProductだけがAssignmentsを利用する場合) 最終的には、Protocol bufferを利用したassignmentsのシリアライズによりネットワークトラフィックの優位性が小さいこと、 分割して運用が可能なモジュラモノリス を実現していく中で、モジュール間でcacheが共有されないケースが増えていくことが予想されるため gRPC metadata を利用した方法を選択しました。 4.3.2 明示的なリクエストフィールド案 gRPC metadataではなく、Protocol Bufferで明示的なリクエストフィールドとして定義する案も検討しました。グローバルアプリBackendでは、API仕様の可視性や型安全性の観点から、一般的には明示的なフィールドを選択しています。 しかし、この方法には全てのモジュールの全てのエンドポイントにAssignmentsフィールドを定義しなければならないという問題があります。Tier2のProductモジュールがAssignmentsを必要とする場合、中継するだけのTier1のエンドポイントにも同様のフィールドが必要になります。すでに多くのエンドポイントが開発されており、全てに修正を加えるのは現実的ではありませんでした。 また、Protocol Bufferを利用することでgRPC metadataの長さも十分小さくなることが分かったため、gRPC metadataによる伝搬を選択しました。 4.4 将来対応 gRPC metadataを使うため、Headerのサイズ制限に引っかからないよう対策を講じています。ユニットテストで最大バイト長になりうるシリアライズ結果がしきい値を超えていないか検知できるようにしています。 現在は全てのパラメータが optional bool 型であるため非常にコンパクトですが、しきい値を超えた場合の対応策として、どのモジュールがどのパラメータを参照しているかを静的に解析し、必要なパラメータだけを伝搬するように機能を拡張する予定です。Protocol Bufferで明示的にパラメータを定義しているため、Assignmentsの参照の解析が容易になります。これも、明示的な定義を選択した利点の一つです。 5. まとめ 本記事では、メルカリグローバルアプリのリーダビリティチームの活動と、Feature Flag伝搬システムの設計について紹介しました。 リーダビリティチームは、モジュラモノリスアーキテクチャの利点を最大限活かすため、コードの可読性と一貫性を維持し、開発をスケールさせる役割を担っています。GitHubメトリクスを活用した継続的な改善、Claudeによる複雑度分析、CIによる自動チェックなど、様々な活動を通じて品質を担保しています。 Feature Flag伝搬システムでは、以下を重視しました: Protocol Bufferによる明示的な型定義 : 型安全性と利用状況の可視化 gRPC metadataとcontext.Contextによる透過的な伝搬 : 既存コードへの影響を最小限に これらの設計判断は、技術的な実装の問題だけでなく、開発チーム全体のスケーラビリティを考慮したものです。 AI時代において、ガイドラインの明文化、自動チェック、一貫したコードベースの維持は、AI Agentを活用した開発の重要な基盤となります。リーダビリティチームは、開発の品質とスピードの両立を目指して活動を続けていきます。 最後までお読みいただき、ありがとうございました。
アバター
こんにちは。検索領域でエンジニアをやっております、shinpeiです。 本記事は 連載企画:メルカリ初の世界共通アプリ「メルカリ グローバルアプリ」の開発舞台裏 の一環として、メルカリグローバルアプリの検索バックエンドをスクラッチで開発することに伴い、大事にした設計のポイントをご紹介します。また今回の新たな要求を契機に既存の検索基盤の拡充が必要だったのでそれについても書かせていただきました。 グローバルアプリでの検索の要件と課題 先日、弊社からの発表の通り、メルカリはグローバルアプリの提供を開始しました。これに合わせて、検索もグローバルな検索を作るべく準備をすすめてきました。 グローバル展開にむけたアプリと基盤の再構築 で紹介したようにグローバルアプリを提供するにあたりバックエンド基盤の再構築を行っています。基盤を活かしながら必要な部分は新しく作り直すアプローチをとっており、検索バックエンドもそれに合わせて再設計を行いました。最低要件は、3年で50カ国展開。出品数は累計40億です(2025年9月時点)。日本事業(日本のお客さま向けメルカリアプリ)の検索との違いは複数ありますが、主なものは以下です。 複数国展開をするための多言語対応 検索対象として、アイテムモデルとプロダクトモデルとの両立 越境事業においてフォーカスしていく際のエンタメホビー領域に特化できるような独自の検索結果チューニング 1.は日本語以外を扱うための要件です。世界展開となれば、言語の壁は避けては通れない課題です。全文検索はそれぞれの言語自体を処理する必要があります。中国語のクエリ、英語のクエリ、フランス語のクエリ。これらを商品情報とマッチさせる必要があります。現在は日本で出品された日本語の商品をメインに扱っていますが、長期的には日本語以外の商品を扱う可能性も考慮する必要がありました。 2.は検索エンジンで検索対象として扱うデータモデルの話です。アイテムとは、現在のメルカリの主流である、単一の商品が検索対象となるようなデータモデルです。一方、プロダクトモデルとは、一つの検索対象だけど、例えば色違い(バリアント)が複数存在させることができるようなデータモデルです。C2Cの商品はアイテムモデルで対応できるのですが、B2Cの商品の一部はバリアントを持つため、プロダクトモデルが必要になります。メルカリはC2Cマーケットプレイスとしてスタートしたため、日本事業の検索では今もなお、アイテムモデルで動いていますが、グローバルアプリではアイテム、プロダクト双方を同等に扱える必要があります。 3.はグローバルアプリは検索結果を独立してコントロールしたいという意味です。グローバル展開を考えたときに国ごとのチューニングや事業の方向性に合わせた柔軟性が必要になります。例えば、クエリを自分たちで組み立てて、自由に検索結果をチューニングもできるように作る必要があります 。検索は日本事業と越境事業両方で重要な機能であり、開発の優先度やリソースなどい違いに影響を受けないようにすることも重要です。 Vertex AI Search for Commerce の採用 日本事業の検索ではElasticsearchを使っています。グローバルアプリでは日本にある商品全体を扱う予定だったので、売上に比べてデータ量が桁違いに大きい状態です。売上とコストを両立させるにはElasticsearchの再利用くらいしか思いつきませんでしたが、多言語対応や独立性の確保、リリースまでの時間と開発リソースを考えると、どうしてもその前の交通整理に長い時間がかかります。どうやるか思案していた時に、思いがけず案に上がってきたのがGoogleが提供してるVertex AI Search for Commerce(以下、VAIS:C)です。今回の例では以下の点で魅力的でした。 フルマネージドな小売サイト向け検索サービス リクエストベースの課金モデル(トラフィックがなければ課金されない) 多言語対応あり 入力するデータはプロダクトモデル(バリアントあり) ある程度の検索結果チューニングが可能 ユーザーイベントベースの検索結果最適化あり グローバルエンドポイント(世界中から使える) これだ!と思いました。要件とVAIS:Cができることを見比べていただければわかりますが、グローバルアプリにとって必要な要求をほぼ満たしており、ネックなのはコストだけです。そこで我々が立てた戦略は以下です。 VAIS:Cを導入し、素早くスモールスタートする トラフィックが伸びてきて、ペイできないレベルになれば、Elasticsearchに切り替える この方法であれば、Elasticsearch側をグローバルアプリに適用するために必要な準備期間も稼げると思いました。一方で、ビジネス側の懸念は現在の日本事業の検索と、同様の売り上げを得る検索結果をだすことができるかどうか、でした。そこはやってみなければわからなかったので、A/Bテストを行うことになりました。 簡単にVAIS:Cを説明しますと、商品情報と、ユーザーイベントを入れると、最適な検索結果が返ってくるというものです。最適化に必要となるユーザーイベントは、Google Analytics 4(以下、GA4)で収集したものが前提となってましたが、スキーマさえ合わせれば独自イベントの入力も可能でした。メルカリはGA4ではなく、独自のイベント基盤を持っているため、なんとか変換して動かしました。(Google Cloud Japanの皆様には多大なるご協力をいただきまして、大変お世話になりました。) 結果的には、我々の商品情報と、なんとか変換したユーザーイベントでは、日本事業の検索よりも結果が劣ることを確認できました。また、後述するいくつかの要件を満たすことが難しいこともわかりました。ですが、このリスクを補ってあまるメリットがあるのも事実です。(これを全部、私一人でできてるのですから!)検索エンジンが変わることでのリスクは合意した上で、グローバルアプリの初期リリースはVAIS:Cで行う、と決めました。 新しい検索バックエンドの設計 検索エンジンの目処が立ったので、次はバックエンドの話です。ここでは、特にこだわった点をご紹介します。 私は7年前、現在の日本事業の検索システムの設計にも関わっていました。当時は理想や期待を込めて設計しましたが、実際に運用を続ける中で「これは設計から見直した方がいい」と感じる部分も多く、今回はそれらを改善する形にしています。 データモデルに依存したAPI データを取得するタイプのインターフェースは”どんなデータ”を対象とするかでガラッと設計が変わります。汎用的になものを作ろうとすると、抽象化が進みすぎて、余計わかりにくくなってしまいがちです。対象が無限に増えるわけではないので、汎用化はせずに、たとえばProductをSearchするためのエンドポイント、というふうに割り切りました。Productのデータモデルは決まっています。タイトルがあって、商品の説明があって、値段があって、、、と、どこに行っても同じです。 柔軟な処理を可能にするプラグイン機構 ElasticsearchやSolrなどにもあるように、検索クエリや結果に対して独自の処理を加えたいというニーズはどの検索システムにもあります。日本事業の検索開発でも、これまで多くの条件分岐(if文)がコードに埋め込まれ、整理が難しくなっていました。そこで、今回のグローバルアプリ向け検索バックエンドでは、クエリの前処理・後処理をフックできるプラグイン機構を導入しています。検索機能の開発者は、必要な処理をプラグインとして追加するだけで拡張が可能です。多くのソフトウェアでも似たような仕組みが使われていますが、結局この方法に行き着くよな、という実感があります。 検索エンジン機能の実装と抽象をわける 基本的なロジックは抽象層にまとめ、実装部分は切り替え可能な構成にしています。もともと、VAIS:CとElasticsearchの両方で動く必要がありましたが、この要件がなくても同じ設計にしたと思います。というのも、検索エンジンの世界はまさに“戦国時代”で、Vector検索に強い新しいエンジンなど、次々と登場しています。現在はElasticsearchを使っていますが、将来的に他の選択肢が有力になる可能性もあります。このため、抽象化しておくことで、後々の移行や比較コストを大きく減らせると考えてます。 その他 グローバルアプリでは、もともとバックエンド全体に関する設計方針が明確にあります ( グローバル展開を支える基盤の裏側 を参照)。このおかげで、何がどこにあるかが、ある程度明確になってます。特に大事だと思うのは、BFFの切り分けです。BFFはここにあるよ(逆にいうと、ここにしかないよ)というのは、見る箇所が限定できるので探索のコストが減るのです。これまでのマイクロサービスでは、どこの誰が検索APIを叩いて、それをお客さまに出しているかをこちらから把握するのは困難でした。検索バックエンドでも、ドメイン特化のノウハウがあります。何をどこに実装するかを明確に提示してるのは新しい検索バックエンドの特徴です。バックエンド全体の設計でも、期せずして同じようなことをしているのは、これまでの苦痛が似ているからだと思います。だれでもなんでもどこにでも作れるというのは、メンテナンスコストを上げる結果になっているという経験則だと思います。 プロダクトオーナーからの想定外の要求で冷や汗 最初はVAIS:Cを使うとはいえ、長期的にはElasticsearchに切り替えなければなりません。私はこれまで、Elasticsearch as a Service (以下、EaaS) という、 ECK などをベースに作った社内のElasticsearchホスト基盤を開発&運用してきました。チームの活躍で、グループ内のほぼすべての検索サービスはEaaSの上で動いてると言えるところまで来ています。関連するエコシステムも充実させてきました。カスタマイズ性も高く、実際、メルカリの複数のビジネスで使われていることがその証左です。グローバルアプリの準備期間中、責任者である@Suwenさんと直接話す機会が多く、EaaSはなんでもできるので安心してください、と伝えてました。そこで何度もフィードバックされたのが、以下のような点です。 「日本事業のこの検索機能、グローバルアプリでも使いたいな」「日本事業のこの機能、グローバルアプリだったらこういうふうにカスタマイズしたらいいよね」 さぁ、ここで私の過去の記事を読んでいただけたみなさまなら、私が冷や汗を流した理由がおわかりですね?EaaSは、Elasticsearchの提供が主であり、その上に作られた機能の再利用までは責任を持っていません。もちろん、プラットフォームとして、機能の再利用性を無視していたわけじゃありません。Elasticsearchにはプラグイン機構があり、実際にそのプラグインを用いた機能なら再利用できます。しかしメルカリではJavaエンジニアは少数派で、Elasticsearchプラグインの開発はほぼ進みませんでした。機能のほぼ全てはGoのマイクロサービスに作り込まれています。以下に、課題感を説明するのに使ったスライドの一部を晒します。日本事業の作り込んだ検索機能資産が使いたいけど、使えないという状態です。 実はこの問題は以前にもぶつかってました。広告事業からも、EaaSを使ってもらっていたのですが、ビジネス側からの期待値は、EaaSを使えば、日本事業の検索と同じクオリティの検索結果がでてくると思われていたのです。実際には、EaaSは日本事業の検索と同じ検索結果を提供するわけではないので、この時は日本向けに作られたシノニムや日本語形態素解析などのライブラリを広告チームのバックエンドから再利用してもらう形で落ち着きました。この頃にスライドを書き、日本の検索チームへ、Goで作られた検索機能の再利用性を高めるべきだとの問題提起はしてきました。が、当時の日本事業の優先度的には、再利用性にリソースを割いてもらうことはなかなか難しかったのです。 All for oneで検索基盤の拡充へ 私はここからは迷走しました。日本事業の開発や優先度を邪魔しない範囲で、なんとか機能の再利用化を進める案を捻り出そうとしました。一時は、必要な機能をElasticsearchプラグインで書き直すか、とまで考えていました。ここで肝となった問題点を整理します。 EaaSは最初から複数事業での利用を見据えた設計であるが、その上に作った日本事業の検索サービスは日本事業に強く結合しているため、他事業からの再利用が困難である 日本事業の検索は7年運用してきたコードベースであり、前述のとおり、うまく整理されていないなどの負債がある 日本事業の検索は引き続き重要であり、このコードベース自体を再利用できるように改変しつつ、日本事業向けの開発を同時並行するのは困難 グローバルアプリの技術責任者である@deeeeetとも議論を重ねて、以下のような案を出しました。いまあるEaaSの上に、再利用可能な機能を一個ずつ切り出して使用するというものです。 日本事業側にも問題と案を再掲示し、議論を重ねました。最終的に、グローバルアプリの優先度が上がったこともあり、日本事業側からも積極的に動いてくれて、日本事業の検索機能を再利用するための新しい層を作ることが決まりました。この層に関しては、主導権があるわけではないので、私からはEaaSというプラットフォームが大事にしているところをなるべく共有して、いまのところ共通した方針のもと一緒に作っています。具体的には以下です。 Platformがその下で使われてるオープンソースソフトウェアに必要以上の制約を加えないこと ここでいうオープンソースソフトウェアとは、我々の場合はElasticsearchです。Elasticsearchには我々がただ使ってないだけで、まだまだたくさんの可能性があります。これを現時点では使わないからという理由で上のプラットフォームを経由すると使えなくなるのは本末転倒だと思ってます。実はここは議論になりやすい点で、制約を加えた方が不可測事態が避けられて、メンテが楽になるという話もありますので、慎重な説得と周りの理解が必要です。 各ビジネスドメインから独立して使えること 共通基盤を作って、それを複数のオーナーから利用する時に問題になるのは機能の開発優先度だと思います。事業Aは規模が小さいから後回し。事業Bのオーナーは発言力があるから、優先。。などなど、いわゆる”政治”になりやすいところだと思います。完全な独立は不可能ですが、これをなるべく避けるためには、基盤への開発が開かれていることが重要です。開かれていると言っても、自由に作れるとはまた違います。ブログの前段で説明した通り、どこでもだれでもいじれると収拾がつかなくなってしまいます。それを解決する一つの手はプラグイン機構です。どこをどうフックするかはまだまだ議論していく必要があるのですが、基本的な方針に関しては同意できています。 こうして、現在のグローバルアプリの検索は、VAIS:CとEaaSの上に作られた新しい仕組みとのハイブリッドで稼働しています。 まとめ 今回はグローバルアプリでの新たな検索要求に対してどのような方針で対処したのかについて書かせていただきました。従来の日本事業の検索とは毛色の違う要求をこなすために、フルマネージドの検索サービスである、VAIS:Cを一時的に導入しました。また、グローバルアプリの開発要求を起点に議論が広がり、社内検索基盤を拡充させることで、今後の要求についても対処できるように基盤を作っていることについても触れさせていただきました。具体的な多言語対応方法など、今回、書ききれなかった部分もあるので、また次回以降でご紹介できればいいなと思ってます。 参考 ”メルカリの検索基盤の変遷について” https://engineering.mercari.com/blog/entry/20220207-776318b784/ 月間2000万人が使う メルカリ検索機能のアーキテクチャ https://findy-tools.io/articles/mercari-elasticsearch/38
アバター
はじめに こんにちは、Cross Border (XB) EngineeringでSRE & Enablingを担当している @ryotarai です。 本記事は 連載企画:メルカリ初の世界共通アプリ「メルカリ グローバルアプリ」の開発舞台裏 の一環として、このプロジェクトのバックエンドAPIのE2E(End-to-End)テストについて深掘りします。特に、開発者全員がメンテナンスできるE2Eテスト基盤をどのように実現したのか、その設計思想と実装について紹介します。 なぜE2Eテストの改善が必要だったのか 従来のE2Eテストが抱えていた課題 バックエンドAPIのE2Eテストは、システム全体が正しく動作することを確認する重要な役割を担っています。しかし、多くのプロジェクトで以下のような課題に直面します: セットアップの複雑さ: テスト環境の準備に時間がかかり、開発者が気軽に実行できない 並列実行の難しさ: テスト間でリソースの競合が発生し、実行時間が長くなる 属人化: QAチームが主にメンテナンスし、開発者が触りにくい 学習コストの高さ: 専用のフレームワークやDSLを学ぶ必要がある このプロジェクトでも当初、これらの課題に直面していました。特に、QAチームのみがE2Eテストのメンテナンスを担当する状況では、以下の問題が発生します: APIの変更時に、E2Eテストの更新が後回しになる テストの追加に時間がかかり、カバレッジが低下する 開発者がテストの実装を理解せず、デバッグが困難になる 目指した姿:開発者全員が参加できるE2Eテスト 私たちが目指したのは、QAチームだけでなく、APIのコードを書いている開発者全員がE2Eテストのメンテナンスを行える体制です。 これを実現するためには、以下の要件を満たす必要がありました: 開発者が日常的に使っている技術でテストを書ける 学習コストが低く、すぐに書き始められる IDEの補完やリファクタリング機能が使える ローカルでもCIでも同じように実行できる フレームワークの設計思想 「普通のgo testで書ける」という哲学 メルカリ グローバルアプリのバックエンドAPIは、Goで実装されています。そのため、最終的に私たちは普通のGoコード(go test)でE2Eテストを書く方式を選択しました。その理由は: 学習コストがゼロ: 開発者は既にgo testの書き方を知っている 型安全性: Connect のクライアントコードをそのまま使え、コンパイル時に型をチェックできる IDEの恩恵: 補完、リファクタリング、定義ジャンプなどが使える デバッグのしやすさ: 通常のGoプログラムとしてデバッグできる 既存コードの活用: テストヘルパー関数やモックなどを再利用できる この決定により、E2Eテストを特別なものではなく、日常の開発フローの一部にすることができました。 私たちが実装したE2Eテストフレームワークの核心は、「普通のgo testで書ける」という設計思想です。 実際のテストコード例を見てみましょう: func TestUpdateNickname(t *testing.T) { t.Parallel() tests := []struct { name string userID int64 nickname string wantCode connect.Code }{ { name: "Success", userID: createTestUser(t).ID, nickname: "NewNickname", wantCode: connect.CodeOK, }, { name: "Blank nickname returns error", userID: readonlyUser().ID, nickname: "", wantCode: connect.CodeInvalidArgument, }, { name: "Non-logged in user returns error", userID: 0, nickname: "TestNickname", wantCode: connect.CodeUnauthenticated, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() testenv.Run(t, func(params env.RunParams) { client := accountv1connect.NewBFFAccountServiceClient( http.DefaultClient, params.Server.URL, ) req := connect.NewRequest(&accountv1.UpdateNicknameRequest{ Nickname: tt.nickname, }) if tt.userID != 0 { // 認証ヘッダーを設定 setAuthHeader(t.Context(), req.Header(), tt.userID) } _, err := client.UpdateNickname(t.Context(), req) if connect.CodeOf(err) != tt.wantCode { t.Errorf("error code = %v, want %v", connect.CodeOf(err), tt.wantCode) } }) }) } } このコードは、go testのテーブル駆動テストという標準的なパターンで書かれています: t.Parallel() で並列実行を指定(通常のgo testと同じ) テストケースを構造体のスライスで定義 t.Run() でサブテストを実行し、各サブテストも並列実行 testenv.Run() の中でテストサーバのURLを取得 Connectの自動生成されたクライアントをそのまま使用 通常のgo testと同じアサーション E2Eテスト特有の複雑な記述はほとんどなく、普段のユニットテストと同じように書けることが分かります。 さらに、普通のGoコードで書けるということは、Claude CodeなどのAIコーディングツールも効果的に活用できるということです。テストケースの追加やエッジケースの洗い出しなど、AIの支援を受けながら効率的にテストを書くことができます。 QAチームなど、バックエンドエンジニア以外でGo言語に慣れていないメンバーもいますが、AIを活用することでテストコードを作成できるようになっています。 実際に、既存のJestで実装されていたE2Eテストをこのフレームワークに移行する際にも、AIを大いに活用しました。既存のテストコードを参照しながら、AIがGoのテストコードを生成し、開発者がレビュー・調整することで、移行作業を効率的に進めることができました。 全体アーキテクチャ E2Eテストの実行方法として、全員がアクセスできる共有のdevelopment環境にデプロイしたアプリケーションに対してテストを実行するという選択肢もあります。しかし、この方法では開発中のバックエンドの変更に対してすぐにテストを実行できないという問題があります。 私たちは、アプリケーションコードを変更しながらE2Eテストを通したり、追加・修正できたりする環境を重視しました。そのため、テストごとにサーバを動的に起動する設計を採用しています。これにより、開発者は自分の変更をすぐにE2Eテストで検証でき、テスト駆動での開発が可能になります。 フレームワークの主な責務は: テストサーバの自動起動と管理: 必要に応じてサーバを起動し、プールで管理 データベースの自動準備: AlloyDB Omniを起動し、論理データベースを作成してマイグレーションを実行 並列実行のサポート: 複数のテストが同時に実行できるようリソースを管理 クリーンアップの自動化: テスト終了時に自動的にデータをクリーンアップし、リソースをプールに返却 開発者から見ると、これらの複雑な処理は完全に隠蔽されており、 testenv.Run() を呼ぶだけでテスト環境が整う仕組みになっています。 内部実装の工夫 ここからは、フレームワークがどのように並列実行とリソース管理を実現しているか、内部実装を見ていきます。 リソースプールによる並列実行 E2Eテストの並列実行を実現するために、サーバをプール管理しています。 重要なのは、 testenv.Run() に渡した関数が終了すると、自動的にサーバがプールに返却される仕組みです。開発者は明示的にリソースを返却する必要がなく、通常のテストと同じように書くだけで、フレームワークが自動的にクリーンアップとプールへの返却を行います。 この仕組みにより: 並列実行時にリソースの競合が発生しない サーバの起動コストを最小化(プールから再利用) テスト間のデータ汚染を防ぐ(TRUNCATEで初期化) リソース管理が透明(開発者は意識する必要がない) データベースの管理 データベースについては、AlloyDB Omniのコンテナは1つだけ起動します。その中で、テストごとに論理データベースを自動的に作成し、マイグレーションを実行します。 この設計により: データベースコンテナの起動コストを削減(1つだけ起動すればよい) 並列実行でもデータが分離される(論理DBごとに独立) マイグレーションの実行も自動化(開発者は意識不要) 論理データベースもプールで管理されており、テスト終了後はTRUNCATEでデータをクリーンアップしてから再利用されます。 コードカバレッジの収集 このフレームワークは、Go 1.20以降で導入された go build -cover をサポートしています。 通常のテストカバレッジ( go test -cover )はテストコード内での実行しか計測できませんが、E2Eテストではサーバプロセスとして実行されているコードのカバレッジを計測する必要があります。これを実現するのが go build -cover 機能です。 フレームワークの実装では: サーバごとに独立したカバレッジディレクトリを自動作成 各サーバ起動時に一時ディレクトリを作成 GOCOVERDIR 環境変数を自動設定 並列実行でもカバレッジが正確に収集される 各サーバが独立したディレクトリに書き込むため、競合しない テスト終了時に自動マージ すべてのサーバのカバレッジデータを go tool covdata merge で統合 最終的に1つの統合されたカバレッジデータが生成される 開発者は特定の環境変数を設定するだけで、複数サーバのカバレッジを自動的に収集・マージできます: # カバレッジ付きでサーババイナリをビルド go build -cover -o server ./server # カバレッジを収集しながらテスト実行 GLOBAL_GOCOVERDIR=/tmp/coverage go test ./e2etest/... # カバレッジレポート生成 go tool covdata percent -i /tmp/coverage この仕組みにより、E2Eテストでのコードカバレッジを正確に計測し、APIの品質を定量的に評価できるようになりました。 Kubernetes上での実行 E2Eテストは、開発環境ではローカルで実行し、CIではKubernetes上で実行します。ここでは、Kubernetes上での実行方法について、いくつかの興味深い工夫を紹介します。 go test -c を使った高速なデプロイ 通常、Kubernetes上でテストを実行する場合、以下の手順を踏むかと思います: コンテナイメージをビルド イメージをレジストリにプッシュ Kubernetes Podでイメージをプル コンテナを起動 しかし、この方法には各ステップに時間がかかるという問題があります。E2Eテストでは実行速度が重要なので、私たちは異なるアプローチを取りました: # テストバイナリをビルド go test -c \ -o package/e2etest \ ./path/to/e2etest # サーババイナリをビルド go build \ -o package/server \ ./path/to/server # tarでアーカイブしてkubectl execで転送 tar -czf - -C ./package . | \ kubectl exec -c main -i -n ${POD_NAMESPACE} ${POD_NAME} -- \ tar xzf - -C /tmp/e2e # Pod内で直接実行 kubectl exec -c main -it -n ${POD_NAMESPACE} ${POD_NAME} -- \ /path/to/entrypoint.sh go test -c を使うことで、テストコードを実行可能なバイナリにコンパイルできます。これにより: コンテナイメージのビルドが不要 レジストリへのプッシュ・プルが不要 kubectl execで直接ファイルを転送 この方法により、テスト実行までの時間を大幅に短縮できました。具体的には1分半程度でビルドからテストの開始ができています。 なお、Kubernetes上で実行する理由は、並列実行に必要な十分なリソースを確保するためです。並列度を上げるとレースコンディションを防ぐためにその数だけサーバが必要となり、必要なリソースが線形に増えるため、Kubernetesクラスタを使用しています。 まとめ 本記事では、メルカリ グローバルアプリのバックエンドAPIのE2Eテストについて紹介しました。 このアプローチにより、E2Eテストは特別なものではなく、日常の開発フローの一部となります。開発者はAPIを変更した際に、躊躇なくE2Eテストを追加・修正できるようになっています。 もちろん、まだ改善の余地はあります。例えば: テストの実行時間のさらなる短縮 AIを利用して、変更箇所に関係するテストのみを実行する取り組みを進めています テストデータのセットアップの簡略化 テスト結果のレポーティング しかし、開発者体験を最優先にした設計により、持続可能なE2Eテスト基盤を構築できたと考えています。 同じような課題を抱えているプロジェクトの参考になれば幸いです。
アバター
Cross Border (XB) EngineeringでSRE & Enablingをしている hatappi です。私たちのチームはSREのみではなく、 Team Topologies におけるEnablingチームとしての役割を持っています。SREとして信頼性の向上やパフォーマンスの改善を行うだけではなく、XBのプロダクトチームの開発者体験と効率を向上させ、よりスムーズかつ高速に価値提供できるよう、技術的な課題解決や環境整備を通じて支援 (Enable) します。 2025年7月にPlatform NetworkチームからXB SRE & Enablingチームへ異動し、最初の仕事としてメルカリ グローバルWebの立ち上げに携わっています。本記事は 連載企画:メルカリ初の世界共通アプリ「メルカリ グローバルアプリ」の開発舞台裏 の一環として、アプリと同時に開発が進んでいるグローバルWebをテーマに、新しい環境でSREとして価値を出すために私が実践しているアプローチをご紹介します。 Enablingのための課題発見アプローチ 7月にXB SRE & Enablingチームへ異動してきて、私の最初のミッションは「グローバルWeb の立ち上げをEnablingすること」でした。しかし異動して間もないためどのような課題や改善ポイントがあるか分からない状態でした。そこでまずは現状を正しく理解することが不可欠だと考え、私は2つのアプローチをとりました。 1. まずは自分でやってみる グローバルWebのメンバーがどういった過程で困っていて何を改善できるかを知り、共感するためには、自分で体験してみるのが早いです。そこで1つの機能開発タスクに取り組みました。これによりただローカル環境をセットアップして動作確認するという点だけでなく実装をしてプルリクエストを作成して、レビューを受け、マージするまでの一連の開発サイクルを体験しました。 このアプローチによって「CIの実行が遅く、フィードバックを得るまでの待ち時間が長い」「ローカルサーバーの起動が遅い」など様々な改善点を特定できました。 2. 現場の声を聞く 自分1人の体験だけでは、どうしても視野が狭くなってしまいます。特に日常業務としてグローバルWebを開発をしているメンバーの声を聞くのはとても重要です。Slackで改善点を聞いたりプランニングやレトロスペクティブの会議に参加するなどして情報を収集しました。 これらにより最初のアプローチでは発見できなかった課題を見つけられただけでなく優先度の選定にもつながりました。 例えばCIの実行時間が遅いという改善点を最初のアプローチで特定しました。これは間違いなく改善点です。しかし実際の開発でCIの実行時間が気になるのは、他のメンバーからレビューを受け取る最後の段階です。それよりも、時々不安定になって失敗するCIやローカルサーバーの起動時間の遅さのほうが、より大きな課題だと感じているようでした。 Platform Engineeringの経験から得た気づき この2つのアプローチを実践する中で、以前のPlatform Networkチームでの経験を振り返る機会となりました。 Platform NetworkチームではPlatform Engineeringとして、メルカリの複数のプロダクトで横展開できる共通基盤やツールを提供してきました。メルカリには複数のプロダクトがあり、それぞれが異なるコンテキストやドメイン知識を持っています。そのためPlatform側からすべてのプロダクトの現場に深く入り込んで理解することは難しいという課題がありました。 今回、XBのSRE & Enablingとして2つのアプローチを実践することで、現場に深く入り込む重要性を再認識しました。一方で、Platform Engineeringの経験から、メルカリ全体を考えたときの横展開の重要性も理解しています。 メルカリでも、両方の経験を持つエンジニアはまだ多くありません。だからこそ、今はXBで得た経験、例えば今回のグローバルWeb関連の改善内容を、Platformチームに積極的にフィードバックしながら一緒に改善を進めています。 AIを活用した課題解決 前のセクションの2つのアプローチによって、取り組むべき課題の解像度が大きく上がりました。しかし、改善すべき課題が分かっても、まだ異動して間もない私はグローバルWebやCross Borderのコンテキスト、Web関連の技術など多くの情報をキャッチアップする必要がありました。グローバルWebの立ち上げをスムーズにEnablingするためにもAIを活用することでこのプロセスをスムーズに進められないか試みました。 学習・調査 例えば CIの実行時間が遅い、という課題に取り組むとします。これを理解するためにはそもそもどのような仕組みで動いているのかを理解する必要があります。そこで下記に説明するように Claude 、 Claude Code を活用しながら必要な情報や改善策を検討していきました。 まず初めに、Claude Codeを使用して既存のCI関連の設定を調査します。メルカリではGitHub Actionsを使用しているためActionの目的を尋ねたり、Job間の依存関係を確認するなどソースコードを読みながら理解を深めます。調査を進めていると、自分の知らない技術が出てきます。例えば Turborepo などです。 知らない技術が出てきた時はそれを理解するためにも一次ソースである公式のドキュメントを読みます。その際にドキュメントの要約などのためにClaudeを活用します。それだけであればClaude Codeをそのまま使うこともできます。Claude を使用した理由は ClaudeのArtifacts機能を利用するためです。(Fig1) ArtifactsはClaudeとの会話中に作成・編集できる独立したコンテンツを作成するための機能です。これを使用することで知らなかった技術を深堀りながら最終的にまとまったドキュメントが完成するため後から見返しやすくなりました。 Fig1: Claude Artifacts 最後のステップは改善のための調査です。改善方法の検討のための第一歩として一般的な改善策を収集するためにClaude Researchを活用しました。例えば「Turborepoを使ったリポジトリでCIを高速化する一般的な方法を調査」といった内容です。これにより、キャッシュ戦略の改善や並列実行の最適化など、複数のアプローチを短時間でリストアップでき、改善策の仮説を効率的に立てることが可能になりました。またArtifactsを活用することで調査した内容をもとに具体的な案など最終的な実装へ向けた情報を一緒にまとめることも可能でした。 実装・レビュー 改善の仮説が立ったら、次に行うのは実装です。調査でまとめた情報はArtifactsに存在しておりMarkdownとして出力できます。それをClaude、 GPT、 Geminiなど任意のツール・モデルで使用できます。 私はメインでClaude Codeを利用していますが、その理由は Slash commands があるからです。Slash commandsはClaude Code上で / から始まる特殊なコマンドで、Claude Codeで特定の操作を実行することができます。私は自分が開発の中で行うプロセスをこのSlash commandsに移行しています。 例えば変更内容からプルリクエストを作成するSlash commandがあります。このSlash commandには単なるプルリクエストの作成だけでなく変更内容からコミットメッセージを検討してコミットするなど私がよく行うステップを定義しています。 実装が終わったらレビューです。 Claude Code 自身にもレビューはさせるのですが自分でもレビューします。今までは git diff やエディターについている diff viewer などを使用していました。しかしローカルでレビューしたときは問題ないと思ったのにGitHubでプルリクエストを作成して再度レビューすると改善点に気づくということがよくありました。変更を加えて毎回pushしてプルリクエスト上で確認するのは時間がかかります。この問題を解決するために difit を使いはじめました。 difitは、GitHub ライクなビューをローカル環境で実現してくれる CLI です。(Fig2) npm パッケージとして追加されているのでインストールも簡単ですぐ使い始められます。GitHubライクなビューにより今までプルリクエスト上で行っていたことをローカルで行えるようになりました。またdifitはコメント機能がついており、追加したコメントはAIにプロンプトとして渡せるようなコピー機能がついています。おかげでClaude Codeで開発しながらレビューして改善というサイクルをローカルで完結するようになりました。 Fig2, difit ( https://github.com/yoshiko-pg/difit ) デバッグ 最後はデバッグです。 私は普段 Chromeを使用することが多いです。Chromeを用いたデバッグではChrome DevToolsが欠かせません。しかし、様々な機能があるため、どの機能を使ってどこを見たら自分が知りたい情報を見ることができるのか毎回苦労していました。 そこで最近リリースされた Chrome DevTools MCP を活用してみました。これは、自然言語で指示するだけでMCP Serverを介してDevToolsを操作して必要な情報を引き出してくれる機能です。例えば、「グローバルWebのこのページのパフォーマンスをチェックして」と入力するだけで、関連する指標を分析してくれます。 これにより毎回苦労していたDevToolsの操作をスムーズに行うことができ、問題発見までの時間を短縮することができました。 Enabling活動から得られた学び 今回のグローバルWebのEnablingを通じて学んだことが2つあります。 現場に入り一次情報に触れることの重要性 1つ目は、現場の一次情報に触れることで初めて、本当に解くべき課題とその優先順位が見えてくるという点です。もし私が客観的なメトリクスだけを見て判断していたら開発メンバーが感じていたCIの実行時間よりも「CIが時々不安定になること」や「ローカルサーバーの起動時間」がより問題であることに気づくのは難しかったでしょう。 新しい技術領域へ挑戦する際のAIの有効性 2つ目は、AIが新しい技術領域へ挑戦する際のハードルを下げてくれる、ということです。 1つ目の学びの重要性を理解していても、実践するまでのハードルが高いと躊躇してしまいます。しかしAIを活用することでこの「最初の壁」を乗り越えやすくなったと感じました。もちろんAIがすべてを解決してくれるわけではないですが、まずは動くものを作ってから、その仕組みを深く理解していくという私の好きなアプローチが高速でできるようになったと感じています。 今後の展望 グローバル展開にむけたアプリと基盤の再構築 でも触れられていたように、今後3年以内に50カ国・地域への展開が予定されており、これは技術的にも非常にチャレンジングです。このスピードで世界に展開するためには、どのような実装や設定が必要か、どのように効率化できるか、データはどこに配置するか、Webサーバーはどこに置くのか、CDNはどのように活用できるかなど、考えるべきことが多数あります。考えることが多いからこそ面白く、SRE & Enablingの腕の見せ所になると感じているので、非常に楽しみです。 おわりに 本記事では、Platform Networkチームから異動して新しい環境でグローバルWebのEnablingをどのように進めているかを紹介しました。 2025年11月13日に、メルカリグループのテックカンファレンス「mercari GEARS 2025」が開催されます。私は異動前の Platform Networkチームの時に行ったCDNマイグレーションについて話します。 他にも面白そうなセッションが沢山あるのでぜひお越しください! 参加登録はこちら 👉 https://gears.mercari.com/ 明日の記事は @gia さんです。引き続き 連載企画:メルカリ初の世界共通アプリ「メルカリ グローバルアプリ」の開発舞台裏 をお楽しみください。
アバター
こんにちは!メルカリ 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つのステージがあります。 本記事では、「MECHANISM Stage」のセッションをご紹介! まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちらから お願いします。 13:00 – 13:20 メルカリハロでのLLM活用 メルカリハロはスキマバイト領域におけるメルカリの新規事業です。2024年の3月にサービスがローンチされて以来、成長を続けており、先日登録者数1200万人を突破しました。 メルカリハロのMLチームはサービスローンチから約半年が経過した2024年10月のタイミングで始動し、以来、AI/MLを用いた多くのプロダクト改善に取り組んできました。 本セッションではその中でも特にメルカリハロのLLMを用いた機能やそれらを支えるLLMOps基盤について紹介を行います。具体的にはLLMを用いた求人の自動作成機能である「かんたん求人作成」やLLMを用いた求人の掲載前リスク予測等についてです。メルカリハロでは既に多くのLLMを用いた機能をリリースしており、用途の異なる50種類以上のプロンプトを本番で運用しています。そのためプロンプトの品質を管理するためのLLMOps基盤も非常に重要です。 本セッションを通して、メルカリハロでLLM実装を進める中で得られたLLMのプロダクト実装のための勘所や、プロンプト管理・自動評価基盤などの実践的なLLMOpsのためのTipsといった知見を共有できればと思います。 13:30 – 13:50 FastlyからCloudflareへ 100%移行を達成したMercariのアプローチ メルカリでは、2023年よりCDNプロバイダーをFastlyからCloudflareへ段階的に移行を開始し、2025年現在、移行が完全に完了しました。 このセッションでは、安全かつスムーズに移行を進めるために実施したアプローチと、その過程で得た学びを共有します。 CDN プロバイダーの比較ではなく、移行プロセスを主に話すため、CDNプロバイダーの変更を考えていない方にも、移行に関する考え方やプロセスのヒントを持ち帰っていただけると考えています。 14:15 – 14:35 The Invisible Backbone: AI-Native Observability for Modern Platforms もし、自動で設定され、変化にもシームレスに適応し、多すぎるアラートのノイズを一掃してくれるオブザーバビリティがあったら?本セッションでは、メルカリがどのようにAI-Nativeなプラットフォームを構築し、設定不要のモニタリング、一貫した可視性、そしてAI活用型のアラートを標準機能として実現したのかをご紹介します。 信頼性が高く開発者にやさしいクラウドプラットフォームの未来を、自律型オブザーバビリティがどのように形作るのか。ぜひご参加のうえ、その目でご覧ください。 14:35 – 15:05 Running 1000 End-To-End Web Tests Daily Mercari USでは非常に多くの E2E Webテスト を実行していますが、それらを素早く、かつ本当に役立つテストにすることが大きな課題となっています。本セッションでは、プルリクエストごとにテストを実行する、新しいテストを追加する、各機能領域を対象にしたテストを実行するなど、私たちが行っている工夫をご紹介します。毎日何千件ものE2Eテストをどのように回しているのかを知りたい方には、まさにぴったりのセッションです。 15:15 – 15:35 Mercari’s Internationalization Journey この2年間、私たちは海外のお客さまがメルカリのマーケットプレイスで商品を購入することを可能にしてきました。 本セッションでは、プロダクトを海外展開していくための道のりを、とくにユーザー生成コンテンツ(UGC)の翻訳に焦点を当ててご紹介し、翻訳コストを100分の1に削減するうえでLLM(大規模言語モデル)がどのように役立ったかについてもお話しします。 16:00 – 16:20 EGP – Mercari’s CRM Platform: Built Once, Powering Many もともとシンプルなハードコードのCRMとして生まれたEGPは、マーケター向けのスケーラブルでUI主導のプラットフォームへと進化してきました。システムが拡大するにつれ、とりわけEGPの利用規模が大きくなると、その複雑さが使いやすさや運用面での課題を引き起こすようになりました。本セッションでは、私たちがシステム設計やAI活用によるUI改善を通じてこれらの課題にどのように取り組んできたのか、そしてその過程でどのような学びを得たのかを共有します。 16:30 – 16:50 Securing the Future of Workflow Automation and AI Agents 企業がワークフローの自動化やAIエージェントを積極的に活用するにつれ、孤立したシステム、過剰な権限を持つエージェント、複雑に絡み合った権限モデルといった新たなリスクが生じています。本セッションでは、これらの課題をどう解決し、自動化とAIが持つ潜在能力を安全かつ最大限に引き出す方法を探ります。さらに、セキュアでスケーラブルな導入を実現しつつ、ユーザーが安心してイノベーションに取り組めるようにするための実践的なアプローチをご紹介します。 17:00 – 17:20 AI/LLMが拓くデータ活用の新時代:人間とデータ分析AI エージェントが協業する分析基盤へ 私たちは、自然言語での対話を通じてデータ分析を行えるAIエージェント「Socrates」を開発・提供しています。Socratesの登場は、SQLクエリの生成から実行、結果の可視化や解釈までを誰でも簡単に実行できるような変革をもたらし、データ活用のハードルを大きく下げました。本セッションでは、Socratesが誕生した背景やSocratesを支える技術、そしてAIとの協業によってもたらされるデータ活用体験の未来像についてお話しします。 「mercari GEARS 2025」のお申し込みは こちらから 。 また、その他のセッション紹介は下記をご確認ください。 PASSION Stageのセッション紹介は こちら 。 GROW Stageのセッション紹介は こちら 。 イベント詳細 開催日時: 2025年11月13日(木) 11:00-18:00 概要: mercari GEARS 2025は、メルカリグループのエンジニアリング組織の技術への挑戦と、カルチャーを体感する技術イベントです。 本イベントは、単なる情報伝達の場ではなく、エンジニアたちが出会い、経験を共有し、交流を通じて新たな機会が生み出されることを目的としています。 参加費:無料 会場:TODA HALL & CONFERENCE TOKYO 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @MercariGears でお知らせしますので、気になる方はぜひフォローをお願いします。
アバター
こんにちは!メルカリ 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つのステージがあります。 本記事では、「GROW Stage」のセッションをご紹介! まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちらから お願いします。 13:00 – 13:40 Leader’s Talk: Moving Fast Without Breaking Things メルカリのバリューのひとつに「Move Fast(はやく動く)」があります。 その一方で、開発者が柔軟に複数のサービスを行き来できるようにすることも必要です。では、その両方をかなえるにはどうすればよいのでしょう? 本セッションでは、AI時代においてメルカリのエンジニアリング組織がいかに開発プロセスを進化させ、スピードとレジリエンスのバランスを取ろうとしているのかを、リーダーたちが自身の視点から紹介します。 発表は主に英語で行いますが、日本語での質問も大歓迎です! 14:15 – 14:35 Google Customer Engagement Suiteを使った顧客エンゲージメント変革 2025年に行われたGoogle Cloud Next Tokyoにて、メルカリは基調講演とブレイキングセッションを通し、Google社が提供するCustomer Engagement Suiteを活用した顧客エンゲージメントの変革について発表しました。このセッションでは、その発表で紹介されたプロダクトがどのような方法で構築されたのかについて紹介します。 14:45 – 15:05 PJ-Auroraが描く未来と、UI品質評価を自動化するエージェント開発 メルカリのモノづくりのアプローチを変えることを使命とする「PJ-Aurora」。本セッションではその未来像を紹介し、あわせてUI品質評価を自動化するAIエージェント開発の現在地をお話しします。AI-Native時代における品質保証の可能性を探る試みを共有します。 15:15 – 15:35 なぜ、メルカリはノーコードを選ばなかったのか? 社内問い合わせ工数を60%削減したLLM活用の裏側 生成AIブームの中、多くの企業がノーコードツールを試す一方で、メルカリは既存の生成LLMを社内データで徹底的にチューニングすることで、高い精度と柔軟性を追求してきました。本セッションでは、社内問い合わせ工数を60%削減したLLM活用事例「HiYo-Chan」を中心に、ノーコードツールでは実現できないメルカリ独自の技術的な工夫、そしてその裏側にあるビジョンまで、赤裸々にお話しします。 16:00 – 16:40 AI Native への道のり ― 数字でみる全社推進と現場の実践 メルカリグループは「AI-Native」を掲げ、組織と現場の両輪で挑戦を進めてきました。本セッションでは、その全体像をデータと実例で解像度高く共有します。まず、社内の開発状況を可視化する取り組みを通じて、AI活用の広がりとインパクトを数値で示します。次に、全社でAIエージェントを使える組織づくり、既存事業を「AI-Native」な開発体制へ移行する設計と運用、そこで直面した課題と理想の姿を掘り下げます。最後に、新規事業開発を題材に、生成AIを活用してPMとエンジニアが要件定義から実装までをどう加速しているか、開発を支える標準化ドキュメント「Agent Spec」の中身と運用を具体的に紹介します。新規事業と既存事業にAIを組み込みながら、新しい開発の型をつくるための実践的な知見をお届けします。 17:00 – 17:30 LTセッション 6人のLTを行います。 未定 / kuu GitHubリポジトリの調査から分かったマイクロサービス開発でのデータベースの課題 / Tomoyuki Koyama Claude Codeで仕様駆動開発をする中で考えたエンジニアの役割 / Toshiki Kawamura Mercari Ads Optimizations For Profitable Revenue Stream / Kumar Abhinav Exploring LLM-Driven Formal Verification for Robust Continuous Integration of Services / Cheng-Hui Weng Evaluations for LLM Apps / jd 「mercari GEARS 2025」のお申し込みは こちらから 。 イベント詳細 開催日時: 2025年11月13日(木) 11:00-18:00 概要: mercari GEARS 2025は、メルカリグループのエンジニアリング組織の技術への挑戦と、カルチャーを体感する技術イベントです。 本イベントは、単なる情報伝達の場ではなく、エンジニアたちが出会い、経験を共有し、交流を通じて新たな機会が生み出されることを目的としています。 参加費:無料 会場:TODA HALL & CONFERENCE TOKYO 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @MercariGears でお知らせしますので、気になる方はぜひフォローをお願いします。
アバター
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の参加受付 も始まりました。このブログをきっかけに、読者のみなさまがワークショップを試してみたり、海外のカンファレンスへの参加に挑戦してみようと思っていただけたら、とてもうれしいです。
アバター