この記事は、 Merpay Advent Calendar 2023 の6日目の記事です。 はじめに こんにちは、MerpayでBackend Engineerをしている @panorama と申します。 今年(2023年)の4月に新卒として入社しました。 今回は「メルペイに新卒入社して1年目にやったこと」という内容で、入社後から現在にかけてどのようなことをしてきたかご紹介したいと思います。 今後入社される方やメルペイ新卒エンジニアの1年目の動きに興味がある方の参考になればと思います。 (一部プロジェクトは社外秘で内容は伏せています🙏) それでは早速始めていきます。 4月~6月 研修期間 4月~5月の頭にかけてはメルカリグループの新卒研修である「DevDojo(※1)」を受けていました。 DevDojoでは特定の分野に限らず Backend、 Frontend、 セキュリティ、 アーキテクチャ、 Spanner 、・・・ などさまざまな技術について学びます。 また今年は新しい試みとしてマナー研修もありました。 「人生に1度きりの新卒研修なのでマナーについて学んでおこう」というものです。 名刺の渡し方や席の座り方(※2)、社内の人間の呼称など基本的なマナーを勉強しました。 今年のDevDojoは取材も入っていて、上記のマナー研修の様子もYouTubeに上がっているのでご興味があればぜひ見てみてください。 業務開始 DevDojoが終わってからは本格的に業務に入っていきました。 そのとき進んでいたプロジェクトとして「メルカード審査完了後に即座にカード番号を利用できるようにする」というものがあり、その機能の一部の実装を担当しました。 今まではカードを利用するためにカードの到着を待つ必要があったのですが、上記のプロジェクトによってオンラインでの決済であれば審査後すぐにご利用いただけるようになりました。 審査完了後すぐカード番号が利用可能に そのプロジェクトが終了してからは他の機能も実装しつつ、少し大きめの改善系のタスクなども実施していました。 これに関しては以前記事(※3)を書いたため、気になる方はそちらをご覧ください。 また上記の期間を通してドメイン知識のキャッチアップや運用の理解、QA環境の用意の仕方やリリース手順などBackendが関わる基本的な作業についても学んでいました。 ※1 技術トレーニングDevDojoで実際に使用されている学習コンテンツを公開しています。 こちら をご参照ください。 ※2 ちなみに余談ですが、筆者のpanoramaはこのマナー研修後にExec(役員)と新卒のランチ会に30分遅刻(😇)し、なぜか上座が空けられていたので座ったという体験をしています。そしてなぜか誰もそれを気にしていませんでした。(補足すると遅刻の理由は寝坊ではなく直前のMTGの終了時刻がランチの開始時刻であったことと、ヒルズを出た後迷子になったというダブルパンチによるものです。) ※3 Cloud Tasksで外部APIへの流量制御をするときに考えたこと 7月~9月 7月からは業務の幅を広げて、お問い合わせの調査なども積極的に拾うようになりました。 私のチームでは、お客さまからのお問い合わせは基本的にはCS(カスタマーサポート)チームが対応するのですが、サポートツール上からはわからない事象だった場合はBackendが調査を行う体制になっています。 また8月からはオンコールのシフトにも入るようになりました。 オンコールとは「サービスのパフォーマンスが悪化したり、停止が疑われたりする場合に備えて担当者が常時対応できるようにしておく仕組み」です。 メルカリグループではPagerDutyを使用してオンコールシフトを管理しており、PagerDutyに紐づけられた特定のDatadog Monitorが閾値を超えた場合、自動で担当者を呼び出す仕組みになっています。 5月~6月にかけて知識のキャッチアップや運用の理解を進めてきたため、(難なくとは言いませんが)お問い合わせやオンコールに対応できるようになりました。 (※またオンコールは万が一手に負えない場合、エスカレーションする仕組みがあります。) オンコールで使用しているツール (左: Datadog, 右: PagerDuty) (Datadog 画像 出典: https://www.datadoghq.com/ja/about/resources/) (PagerDuty 画像 出典: https://www.pagerduty.com/brand/) DatadogのロゴになっているワンちゃんはBitsという名前みたいです 合わせて8月1日から入ってこられたインターン生(※4)のメンターにもなりました。 メンターの主な役割はインターン生のサポートですが、メルカリグループでは新しくチームに入られた方に対してメンターランチ(※5)やチービルランチ(※6)を行う文化があるためそういったサポートも実施しました。 インターン生の方はみなさんとても優秀ですが、社内の知識に関しては初めてのことばかりなので、メンターとしてタスクを適切に分割してお渡ししたり、実装に必要な知識をお伝えしたり、場合によっては巻き取って進められるように自分もタスクを追ったりしていました。 8月中旬以降は新しいプロジェクトに参加しました。 そのプロジェクトは今までに経験したことのない別のチームと連携して行うもので、かつ延期が難しいハードスケジュールのものでした。 自分のチームから担当としてアサインいただいたのですが、開発終盤で別のチームとの依存関係を見落としている箇所があることが発覚し、ギリギリで実装を追加することで乗り切りました。 (他の開発チームと特にQAの方にご協力をいただいてなんとか無事故・不具合なしで期日内にリリースできました。) この経験以来、他チームとの調整がある場合にはなるべく早い段階で変更箇所を確認し、定期的にsyncしていく必要があることを意識するようになりました。 上記はプロジェクトの内容を伏せてしまっていますが、他にはFIDOの対応などもやっていました。 FIDO認証画面 ※4 参考: mercari careers / Students ※5 メンターランチ: メンターとメンティー(新入社員・インターン生)とのランチ。チームメンバーや他チームを紹介がてら行います。 ※6 チービルランチ: 目的はメンターランチと同じでrelationship buildingですが、関係性はメンターとメンティーに限りません。 10月~現在 10月の中頃でメンティーだった方のインターン期間が終了しました。 そして新しく動き始めたプロジェクトにBackendの担当としてアサインされました。 このプロジェクトではまず機能自体の調査とそれを実現するための調査が必要でした。 機能に関する資料と調査結果をチーム内で読み合わせ、ある程度固まったら関連するチームも巻き込んで共有会を行いました。 担当のBackendとしてこの調査や会議のリードを任せていただき、現在は設計に入っています。 ありがたきUnipos (社内投げ銭サービス(※7)) 今まではタスクがアサインされた時点でやることが決まっていることが多かったのですが、今回は「何をどこまでやるのか」「どうすれば実現可能か」という段階からPMと一緒に関わらせていただいているので非常に新鮮に感じています。 先述の通りまだ設計中で、その後にbreakdownして実装に入るので、引き続きプロジェクト達成に向けて努力していく所存です。 また上記のプロジェクト以外だとBe a Pro Days(※8)と呼ばれる取り組みで自動化のためのBotを作ったり、キャンペーン施策のBackendの実装をいくつかやったりしました。 ※7 参考: メルカリのピアボーナス制度「メルチップ」、メッセージ累計数が100万を突破しました〜!#メルカリな日々 ※8 参考: 「自分自身が発揮できる価値」に向き合う──1人ひとりがオーナーシップを持って課題解決を取り組むために導入した「CD Be a Pro Days」 まとめ 今回は私が新卒入社後にどのようなことをしていたか、(振り返りの意味も込めて)記事化してみました。 入社前には自分が1年目でインターン生のメンターになったり、一部のプロジェクトのリードを任せてもらえるとは思っていなかったため本当に「Go Bold」の考え方が実践される素晴らしい環境だと感じました。 また多少の修羅場(?)やさまざまなチームの方とのコミュニケーションの機会を通じて、技術一辺倒だった学生時代よりも色々なスキルを身につけた気がします。 内容としては個人ブログのような部分も多かったかもしれませんが、社内レビューを通っているので”公認”で社内の話についていろいろ言及できた気がします。 メルペイ(メルカリグループ)の新卒入社後について気になっている方がいて、具体例として参考になっていれば幸いです。 それでは、ありがとうございました。 明日の記事は @Malli さん, @ben.hsieh さんです。引き続きお楽しみください。
こんにちは。メルペイ Engineering Engagement チームの mikichin です。 この記事は、 Merpay Advent Calendar 2023 の5日目の記事です。 11月のOffice Weekで「Fintech Tech Talk at Office Week」を開催したので、その様子をお届けします。 Fintech Tech Talk at Office Week について Office Week とは? メルカリグループでは、「YOUR CHOICE」という制度があり、約90%以上のメンバーがリモートワークで働いています。 関係性が薄くならないようにメルカリグループのFintech領域では「Office Week」というイベントをだいたい半期に1度開催し、なるべく出社し集まることでチーム内・他部署・経営とのコミュニケーション機会の創出、関係強化を図っています。 メルカリ、多様な働き方を尊重した 「メルカリ・ニューノーマル・ワークスタイル “YOUR CHOICE”」の活用状況を公開 Fintech Tech Talk とは? エンジニアリング組織全体で得た知見を共有するLT大会です。 発表時間は5分、話すテーマは技術的な話はもちろん、趣味の話など何でもOKというゆるいルールです。 リモートワークが中心となった今、オフラインで全体に知見を共有する機会も少なくなりました。そこで、他チームのメンバーや取り組みを知り、交流のきっかけになればと考えて運営しています。 当日の様子について どんなLTがあったのか 内容は業務にとどまらず、興味のある領域も対象です。キーボードの話や直近チームで取り組んだプロジェクトについての話、メルカリグループの部活として行っている 技術書典 の話など、さまざまなテーマのLTがありました。 △メルペイVPoEのkeigowさんが「Introduction of Competitive Programming」の発表をしている様子 メルペイ Frontendエンジニアの @yutaro さんは、以前 社外イベント で発表した「内製UIコンポーネントのアクセシビリティテストを支えるOSS」を社内用にアレンジして発表をしました。社外イベントの資料は公開していますので、興味がある方はぜひこちらをご確認ください。 メルペイ Backendエンジニアの @Liu さんが発表した「LINE 公式アカウントPJ」については、下記記事をご確認ください。 Flow Control Challenges in Mercari’s LINE Integration 参加者の反応について イベントには、メルペイ新CEO @Takeshiさんをはじめエンジニアリング組織以外のメンバーも含め、100名以上が参加しました。 現在のメルカリグループは、約50カ国のメンバーで構成されています。本イベントに全員が参加できるよう、Global Operation Team(GOT)※ の同時通訳を入れ、登壇者の言語にあわせた言語で司会進行しました。 ※:社内の通訳・翻訳を担当する専門チーム GOTの取り組みはぜひ、メルカン記事「 言語を活用してメルカリのビジネスやD&Iをサポート!──Global Operations Teamが提供する通訳・翻訳業務以上の価値 」をご確認ください。 イベント中、Slackには「アクセシビリティ、大事だよねぇ」「全然知らない内容でおもしろい」といった内容についての反応や「日本語だけではなく、英語のLTもあってよかった」「おもしろかった」といったイベント全体への感想が投稿されていました。 Office Weekにあわせて出社した社員はもちろん、Fintech Tech Talkはオンラインでの参加者もたくさんいました(Google Meetで社内向けに配信していました)。 おわりに 社内向けLT大会は、参加者が発表をきいて何かを得ることも大事ですが、それよりもわいわいみんなで楽しむことができること、気軽に発表をするという経験をすること、が大事かなと思っています。 今回、イベント当日の朝に飛び込みで登壇が決まったLTがありました。プレゼン資料はなく、完成したばかりのシステムの画面を使ってアップデート箇所を紹介するLTだったのですが、このLTもとても盛り上がっていました。こういうふうに気軽に発表でき、みんなで盛り上がる場所を今後もつくっていきたいなと思います。 明日の記事は panoramaさんです。引き続きお楽しみください。
こんにちは!横浜国立大学理工学部情報工学EP3年の @shion1305 です。今年の10月から株式会社メルペイ Settlementチームにてバックエンドエンジニアのインターンとして所属しています。 この記事は、 Merpay Advent Calendar 2023 の4日目の記事です。 Settlementチームでは、メルペイ加盟店で発生した売上金を加盟店に振り込む際に、指示を出したりデータの管理を行ったりするマイクロサービスの開発を行っています。Settlementのマイクロサービスについては こちらの記事 でも紹介されています。 私がJoinして早々担当したタスクの一つが、Settlementサービスに対するKubernetesのPod Distruption Budget(PDB)設定の見直しでした。Kubernetesについてはこれまで個人開発で少し調べたことがある程度でした。今回PDB見直しを行う中で仕様についてリサーチをしていたのですが、多くの記事がある中で実際の挙動について自分が思うような記事があまり見つかりませんでした。今回のAdvent Calendarを機に、自分なりにわかりやすくまとめてみることにしました。 本記事では、特に以下にフォーカスします。 PDBの挙動 パーセント指定を用いた場合のPDBの動き minAvailable maxUnavailable それぞれのポイント Pod Disruption Budgetの概要 PDB(Pod Disruption Budget)は、 Voluntary Disruptions(システムの計画的な中断) からアプリケーションの可用性を保護するKubernetesの機能です。 Voluntary Disruption の具体例としては以下が挙げられます。 kubectl drain でのNodeからのPod退避 Nodeスケールダウン時のPod退避 Node間のPodの移動 (NodeからPodを他のNodeに退避させる操作を、以降Drain操作と表記します。) 例えば、以下のように記述すると、 Voluntary Disruptions において、使用できないPodの割合を33%までとなるように指定できます。 apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: pdb-sample namespace: namespace-sample spec: maxUnavailable: 33% selector: matchLabels: app: pdb-tester PDBの設定においては、 minAvailable または maxUnavailable のいずれか一方を指定することが可能です。 minAvailable では、指定したPod群の中で常に稼働していなければならない最小限のPodの数または割合を指定でき、 maxUnavailable は、一度に中断または利用不可となっても良いPodの最大数または割合を指定できます。 自動スケールによってPod数が変動する場合において固定値を設定するのみではPod数に応じたPDBの挙動を設定することができないため、パーセント指定が用いられることがあります。実際、メルカリグループのマイクロサービスで設定されているPDBの多くでは、パーセント指定が用いられています。 しかし、パーセント指定を行う場合、PDBがどのような挙動をとるのか、分かりにくくなってしまいがちです。 パーセント指定におけるPDBの挙動 公式ドキュメントでの記載 公式ドキュメントには以下のように、パーセント指定で中途半端な数になった時には数が繰り上げられることが明記されています。 When you specify the value as a percentage, it may not map to an exact number of Pods. (中略..) Kubernetes rounds up to the nearest integer, so in this case, 4 Pods must be available. When you specify the value maxUnavailable as a percentage, Kubernetes rounds up the number of Pods that may be disrupted. Thereby a disruption can exceed your defined maxUnavailable percentage. https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget 対応するソースコードを見てみる 中途半端な数になった際の繰り上げの振る舞いについて、実際のソースコードを確認してみます。 minAvailable と maxUnavailable の読み取りに対応する部分は以下のようになっています。 /pkg/controller/disruption/disruption.go L797-L800 (2023/12/1時点) maxUnavailable, err = intstr.GetScaledValueFromIntOrPercent(pdb.Spec.MaxUnavailable, int(expectedCount), true) if err != nil { return } minAvailable, err = intstr.GetScaledValueFromIntOrPercent(pdb.Spec.MinAvailable, int(expectedCount), true) if err != nil { return } ここで用いられている GetScaledValueFromIntOrPercent の中身の実装はこのようになっていて、上記では パラメータとして roundUp: true が指定されているため、繰り上げ処理がされていることが確認できます。 func GetScaledValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) { (中略...) if isPercent { if roundUp { value = int(math.Ceil(float64(value) * (float64(total)) / 100)) } else { value = int(math.Floor(float64(value) * (float64(total)) / 100)) } } return value, nil } PDB設定時の動作例 前述で繰り上げ処理が行われることはわかりましたが、受け付けた値に対してPDBがどのような動作をするのかについて、いくつかケースを想定して検証しました。 今回想定した流れは以下の通りです。 Nodeが2つ存在している 片方にPodが入っていて、PDBが設定されている Podが存在しているNodeに対して kubectl drain が実行され、Podの退避処理が実行される ケース1: Pod数:2, maxUnavailable:50% maxUnavailableのPod数は1Podとして計算されます。その結果、図のように可用性を担保した状態で Drain操作ができることが確認できました。 ケース2: Pod数:1, maxUnavailable:50% maxUnavailableのPod数は1となります。そのためDrain操作が可能となりますが、退避するPodの中断処理と新しいPodの起動処理は同時に実行されるため、Drain操作中に利用可能なPod数が0となる可能性があります。 このようにmaxUnavailableを用いる場合、最小pod数を考慮する必要が出てきます。(Pod数が1の時にあえてDrainできないようにする手段もあるようです。 公式ドキュメント ) ケース3: Pod数:2, maxUnavailable: 80% maxUnavailableのPod数は2となります。そのため2Podに対して同時に退避処理が実行されます。そのため、drain操作中に利用可能なPod数が0となる可能性があり、可用性に問題が出る可能性があります。 ケース4: Pod数:1, minAvailable: 50% minAvailableのPod数は1となります。PDBはdrain操作のためにPod数の調節を行うことはしないため、PDBの条件を満たすDrain操作ができず、Drain操作は止まったままの状態となります。 このように、minAvailableを用いる場合でも最小pod数を意識する必要が出てきます。 minAvailableとmaxUnavailableの整理 これまで具体的なケースにおけるPDBの影響を確認しました。 PDBではminAvailableとmaxUnavailableどちらかのみしか設定することができません。それぞれを採用することによるメリット、考慮すべき点について以下にまとめます。 minAvailable メリット 0より大きい数を指定しておけば、Drain操作時において必ず1Pod以上動作させて可用性を持たせることができる。 考慮が必要な点 (パーセント指定ではなくPod数で指定した場合) スケールアップして多くのPodがPDBの管理対象となっている場合、Drain操作で一度に多くのPodが利用できない状態となり、パフォーマンスに影響が出る可能性がある。 適切に値を設定しないとDrain操作ができなくなってしまう。(特に管理対象のPodが少数である場合は注意が必要) Drain操作ができなくなる条件 パーセント指定の場合、現存のPod数に対して計算を行い繰り上げ処理が行われた結果、minAvailableのPod数がPDBが対象とするPod数と同数になる時。 Pod数指定の場合、minAvailableのPod数がPDBが対象とするPod数より多くなってしまう場合。 maxUnavailable メリット Drain操作ができなくなる状態は基本発生しない。 考慮が必要な点 適切に数値を設定しないとDrain操作中に全てのPodが中断してしまう可能性がある。 Drain操作ができなくなる条件 maxUnavailableを0に設定する。 Pod数が1の状態のままでは可用性を持ってDrain操作をすることができないため、あえて maxUnavailable: 0 を設定して警告を出すために設定する方法もあるようです。 公式ドキュメント まとめ PDBの設定に関しては、minAvailable と maxUnavailable のどちらが良いという一般的な答えは存在しません。システムによって要件は異なるのでPodの最小稼働数や中断許容範囲を理解し、それに基づいて適切な設定をすることが重要です。今回の記事が、皆さんのPDBに関する理解を深め、より効果的なKubernetesの運用に役立つ一助となれば幸いです。 明日の記事はmikichinさんです。引き続きお楽しみください!
はじめに こんにちは。メルペイVPoEの @keigow です。 この記事は、 Merpay Advent Calendar 2023 の2日目の記事です。 今年の3月まではソウゾウでHead of Engineeringとして働いていましたが、4月にメルペイに2年ぶりに戻ってきました。本日はメルペイのProduct組織の改善とProgram組織への移行の取り組みについてご紹介します。 以前のProject Matrix型組織 2022年9月までは、Microservicesの単位をベースとして構成されたFunctionチーム(Growth、Platform、与信領域など)から、3ヶ月ごとに決めているProject(新機能開発、他社連携など)に各メンバーをアサインしていくという形でProduct開発を推進していました。 会社のOKRとして合意した目標に沿って、Productチーム内でProjectの優先度を決めて左から順に並べ、Project毎にProject LeaderとTechnical Project Manager(Engineeringのカウンターパート)を置くことで、以下のような良い点があったと考えています。 事業としてフォーカスされている点が理解しやすい 優先順位が明確なためアサインの判断がしやすい 結果として、会社として重要なProject(チーム横断な動きが必要なものであっても)をスピード感を持って推進できる 一方で以下のような課題感もありました。 組織の成長と人員増加に伴い、優先順位の調整コストが高まってきた 3ヶ月単位でProjectの見直しがあり、アサインの変更も随時行っていたため、チームビルディングのコストが高い 今後の運用や改善までを想定した中長期の計画づくりが難しくなっていた これらの課題感を踏まえて、2022年10月より新しいProgram型組織への移行を開始しました。 Program型組織の導入 特定のドメインごとに組織を分けて、より小さな単位で意思決定をできるようにしたチームをProgramと呼んでいます。現在メルペイには6つのProgramがあり、その役割ごとに大きくProduct / Foundation / Enablingという3つの領域に分けています。 Product: 支払いや与信、還元の仕組みなどお客さま体験のコアとなる部分の提供を担う。 Foundation: 各Product領域のProgramに対して汎用的に利用可能なPlatform機能を提供する。決済の中心となるマイクロサービスや、KYC(本人確認)、ポイント付与の仕組みなど。 Enabling: ArchitectやSRE、Data Platformなど、横断的な技術課題の解決や生産性向上など開発全体を支援する。 各ProgramにはProduct HeadとEngineering Headを置いています。Product Headは施策の優先順位の決定や、戦略・ロードマップの策定とその推進に責任を持ち、Engineering Headは中長期を見据えた技術的な戦略や方針の策定と推進に責任を持っています。 基本的にはOKRなど会社方針をベースにProgram内で意思決定が出来るようにしていますが、3ヶ月ごとにProgram HeadメンバーとCPO/CTO/VPsを交えたStrategy Reviewを行うことで、Program組織の戦略と経営の戦略の方向性を揃えられるようにしています。 Engineering組織のアップデート ドメイン毎のProgram組織を作ることで、Program内のアサインに柔軟性が生まれ、運用や改善も踏まえた、中長期の戦略への投資がしやすい環境になりました。一方でEngineering組織のレポートラインは職種別となっており、Backend、Frontend、iOS、Androidなど各職種別にEngineering Manager(EM)、Manager of Managers(MoM、EMのManager)が居るという体制になっていました。その結果として一部のEMやMoMが各Programにフォーカスすることが難しいという課題が有りました。 この問題を解決するため、今年の10月からProgram組織に合わせたレポートラインに変更し、それぞれのEMやMoMが自身の担当するProgramにフォーカスできるような体制変更を行いました。 振り返りと今後 Program組織にトライし始めたのは1年ほど前ですが、Engineering組織のアップデートも含め、細かい改善を積み重ねることで、少しずつ動きやすい状況が作れてきたと思います。とはいえ、まだまだ課題も多いため、1つずつ課題と向き合って解決していきたいと思っています。 余談になりますが、今回のような組織体制はメルペイとしては初めてではなく、Project Matrixをベースとした体制に移る前には、(当然今と違う部分はありますが)Program組織に近い体制を取っていた時期もありました。 組織変更はコストが高いので、頻繁に変えすぎるのは良くないと思っていますが、一定のタイミングでその時の状況やニーズに合わせて、変化をしていくこと自体は必要だし、やっていきたいと思っています。どのような組織もPros/Consがあるものだと思うので、ある意味自然な姿だとも感じます。 おわりに 明日の記事はkeigoandさんの「Merging teams for a Growth Platform」です。引き続きお楽しみください。
この記事は、 Merpay Advent Calendar 2023 の1日目の記事です。 hello hello hallo how high? メルペイで5月からVPoE の @nu2 です。 はじめに 2023年6月、メルペイはエンジニアリング組織の新体制を発表しました。 https://mercan.mercari.com/articles/39414/ (新体制になったメルカリグループのFintechのエンジニアリング。新CTOとVPたちが語る、グループLTV最大化のためにFintech事業が果たすべき役割) 今年の Merpay Advent Calendar はエンジニアリング組織新体制の元、オープナーとしてメルペイのこの1年を淡々と振り返ってみたいと思います。 特に私は5月に入社しましたので新鮮な視点をお伝えできればよいなと考えています。 https://engineering.mercari.com/blog/entry/20230704-merpay-techasset-first-impression/ (New Member として見たMerpay Tech Asset First Impression) LLM 入社日当日にLLM を活用した「ぐげん会議」を開催するからVP としてチームのスポンサーになってくれと言われました。全く前知識とコンテキストがないまま、これまでの経験から障害報告書を障害の状況から規定の形式に自動生成して書記をするAI を開発するチームをスポンサードする事に決めました。 https://mercan.mercari.com/articles/39144/ (LLMを活用してなにがつくれるか?——「ぐげん会議」開催から見えてきた、AI活用の新たな可能性) 私がスポンサードしたチームは見事にCTO 賞を受賞しました。 また、MVPを受賞した返済相談チャットシミュレーターを開発したチームはその品質の高さとともに、会社の決算資料にも報告を開始したクレジットサービスの債権残高 / 回収率にとても大きなインパクトを残しそうなポテンシャルを感じるAI プロダクトでした。 メルカード 2022年12月から提供を開始したメルカードの発行枚数が200万枚を突破しました。 https://jp.merpay.com/news/2023/11/2million/ (「メルカード」、すべてのお客さまへの提供開始から1年足らず(約11か月)で発行枚数200万枚突破) 提供開始からわずか半年で機能をアップデート、その約3ヶ月後に更にアップデートをしています。 https://jp.merpay.com/news/2023/06/20230627seisan/ (メルペイ、清算機能のアップデートで清算後すぐに「あと払い利用枠」が回復する機能を追加) https://jp.merpay.com/news/2023/10/20231016seisan/ (メルペイ、清算機能のアップデートで清算後すぐにポイントが付与される機能を追加) このような体験向上をデザイン面、エンジニアリング面から支えた結果がグッドデザイン賞を受賞した事につながっているのではないかと思います。 エンジニアリングとしてこのように短期間でアップデートをかけられる決済機能をこれまで日本国内で見た事はありません。 なぜこのような事が可能なのか?という事はMerpay & Mercoin Tech Fest 2023 の こちらのセッション にて発表されています。 グッドデザイン賞 https://about.mercari.com/press/news/articles/20231005_gdesign/ (メルカリグループのサービス、「メルカード」と「ビットコイン取引サービス」が2023年度グッドデザイン賞をW受賞) Merpay & Mercoin Tech Fest 2023 そしてエンジニアリング組織の新体制後初のTech Fest を開催しました。 Fintech 領域の業務経験やドメイン知識が不十分な状態で入社しましたので 個人的にもこのTech Fest は自分のインプットを増やす上で非常に有用でした。 https://mercan.mercari.com/articles/39180/ (8月22日より3日間にわたって開催!Fintech CTOと2名の新VPoEに聞く、「Merpay & Mercoin Tech Fest 2023」の見どころと意気込み) https://engineering.mercari.com/blog/entry/20231023-mmtf2023-day1-2/ (【書き起こし】How to Unleash Fintech – Shunya Kimura / Keigo Watanabe / Noriaki Utsunomiya 【Merpay & Mercoin Tech Fest 2023】) 現在配信したセッションの動画を全てテキストに書き起こしてくれているので予習、復習に最適です。 https://engineering.mercari.com/blog/entry/20231023-mmtf2023-list/ (Merpay & Mercoin Tech Fest 2023 セッション書き起こしまとめ) 求人プラットフォーム「メルカリ ハロ」 そしてTech Fest のトークセッションで「まだ言えない事がある」とCTO が言及していたのがこのスポットワーク事業に参入する話です。 https://about.mercari.com/press/news/articles/20231113_mercarihallo/ (メルカリ、2024年初春にスポットワーク事業に参入、本日より求人募集パートナーの先行受付を開始) “メルペイを通じて、給与デジタル払いを実現し、「メルカリ ハロ」をご利用いただいた際、「メルペイ」で給与を受け取れる体験を提供することを目指します。” プレスリリースから引用した文章のとおり、この体験の提供を実現するため現在急ピッチかつ慎重にプロジェクトを進行しています。 貸金業務取扱主任者制度 貸金業務取扱主任者制度 とは貸金業法で定められている国家試験です。 我々は貸金業を営んでいますので、所属する社員は誰でも会社の経費で受験する事ができます。ドメイン知識を習得する絶好の機会なので受験してきました。 毎年試験にチャレンジするエンジニアはかなりおり、試験前後は試験対策用に立てられたSlack チャンネルがとても盛り上がってました。 なぜこのような法律ができて、貸金業を事業とする事業者は資格の保有を義務付けられるのか?というこれまでの歴史的背景から学ぶ事も多くあり私は既に来年の試験に向けて毎日少しずつ学習を繰り返そうと考えています。 経済安全保障推進法 株式会社メルペイは経済安全保障推進法の特定社会基盤事業者として指定されました。 給与デジタル払いを実現するためにも必要なことであります。 https://www.fsa.go.jp/news/r5/economicsecurity/231117infrastructure.html (金融分野における経済安全保障対策) “経済安全保障推進法第50条第1項及び第2項の規定に基づき、特定社会基盤事業者を令和5年11月16日に指定し、同年11月17日に公示しましたので、別添をご確認ください。” https://www.fsa.go.jp/news/r5/economicsecurity/tokuteishakaikiban.pdf (特定社会基盤事業者として指定した者) 私が入社後ちょうど半年を経過したタイミングで国から社会インフラの一部として指定され、入社後丸一年経過する日までに法令に準拠する体制を構築しなければなりません。 私個人の経歴としてもインターネットポータル、検索、通信とICT の社会インフラ企業で経験を積んできましたので運命めいたものを感じてしまいました。 「守り」あってこその「攻め」を来年は実践していく所存です。 おわりに 2023年のメルペイは前年にリリースをした大きな機能を磨き上げる年になったと個人的に感じました。またその大きな機能に対してさまざまな反響をいただきました。 今後もお客さまの安心・安全を維持しながら新たな価値をお届けすることを、エンジニアリングで達成していきたいと思います。 明日の記事は VPoE のkeigowさんです。引き続きお楽しみください。 おまけ 今年無事。 所属する会社が変わってもこのフレーズをAdvent Calendar に投稿する事は私の恒例行事なので、 今年もILL-BOSSTINO のこの言葉を捧げます。 特に我々の業界は月跨ぎ、年跨ぎのタイミングでインシデントが発生しやすいです。 皆さま良いお年をお迎えください。 (THA BLUE HERB “今年無事” @ 東京 contact – 2019.12.29)
こんにちは。メルペイ Engineering Engagement チームの mikichin です。 早いもので来週から12月ということで、Advent Calendarの季節がやってきます!今年も、メルカリとメルペイ2社で Advent Calendar を実施します! ▶ Mercari Advent Calendar 2023 はこちら Merpay Advent Calendar とは? Advent Calendar の習慣にもとづいて、12月1日から25日までの期間毎日ブログ記事を投稿する、というブログ公開型イベントです。 メルペイ・メルコインのエンジニアがプロダクトや会社で利用している技術、興味のある技術分野やちょっとしたテクニックなど知見をアウトプットしていきます。このAdvent Calendarを通じてクリスマスまでの毎日を楽しく過ごしていただければと思っています。 2022年のMercari / Merpay Advent Calendar はこちら Mercari Advent Calendar 2022 Merpay Advent Calendar 2022 公開予定表 (こちらは、後日、各記事へのリンク集になります) Date Theme / Title Author 12/1 メルペイ VPoE による2023年の振り返り @nu2 12/2 メルペイのProgram型組織への移行 @keigow 12/3 Merging teams for a Growth Platform @keigoand 12/4 動作例からKubernetes PDBの挙動を理解する @Shion (Intern) 12/5 Fintech Tech Talk at Office Week を開催したよ! @mikichin 12/6 メルペイに新卒入社して1年目にやったこと @panorama 12/7 Enhancing Collaboration and Reliability: The Journey of Version History in our Page Editor Tool @Malli , ben.hsieh 12/8 メルペイでのインターンを2ヶ月経験してみて @Shion (Intern) 12/9 新卒エンジニアが Airflow のバグを発見してからコントリビュートするまで @champon 12/10 加盟店精算のインボイス対応 @ryuyama 12/11 Cypress + Gmail APIでメール+SMSの2FA認証をテスト自動化する(気合&パワー) @fukutomi 12/12 Flow Control Challenges in Mercari’s LINE Integration @Liu 12/13 多国籍メンバーで構成されたメルペイ決済基盤チームが言語の壁を突破するために取り組んだこと @abcdefuji 12/14 TnS Platform Team, past, present, and future @ntk 12/15 Merpay Frontend のこれまでとこれから: 2023年版 @tokuda109 12/16 品質要件が厳しいLLMアプリケーションのトライアル評価を通じて得た知見 @gucci 12/17 2023 GopherCon Review @tenlingp 12/18 (JA) Merpay Enabling Client チームが目指すこと (EN) What the Merpay Enabling Client Team aims for @masamichi 12/19 モダリティを考慮したiOSアプリのナビゲーションの再設計 @kenmaz 12/20 決済基盤の Observability を向上するための Datadog Dashboard の進化 @komatsu 12/21 AWS Transfer Family で SFTPサーバーを作ってみたら便利だった話 @myoshida 12/22 お手軽な検索API構築 その2 ~マルチコア・ベクトル・分散検索 @orfeon 12/23 メルコインにおけるGitHub Actions活用術 @iwata 12/24 Offsitesのワークショップでの4つの工夫 @pooh 12/25 メルカリEngineering Roadmapの作成とその必要性 @kimuras Merpay Advent Calendar 2023 の1日目は、 VPoE の @nu2 が執筆予定です。 ひとつでも気になる記事がある方は、この記事をブックマークしておくか、 エンジニア向け公式X(旧Twitter) をフォロー&チェックしてくださいね!
こんにちは。メルカリ Engineering Officeの yasu_shiwaku です。 またまたこの季節がやってきましたね!来週から12月ということで、Advent Calendarがはじまります。今年もメルカリとメルペイ・メルコインで2本のAdvent Calendarを実施します! ▶ Merpay Advent Calendar 2023 はこちら Mercari Advent Calendar とは? Advent Calendar の習慣にもとづいて、12月1日から25日までの期間毎日ブログ記事を投稿する、というブログ公開型イベントです。 メルカリグループのエンジニアがプロダクトや会社で利用している技術、興味のある技術分野やちょっとしたテクニックなど知見をアウトプットしていきます。このAdvent Calendarを通じてクリスマスまでの毎日を楽しく過ごしていただければと思っています。 2022年のMercari / Merpay / メルカリ Shops Advent Calendar Mercari Advent Calendar 2022 Merpay Advent Calendar 2022 メルカリShops [フライング]アドベントカレンダー2022 公開予定表 (こちらは、後日、各記事へのリンク集になります) Date Theme / Title Author 12/1 The Bitter Lesson about Engineers in a ChatGPT World @darren 12/2 How We Saved 75% of our Server Costs @pratik 12/3 How we reduced response latency by over 80% @rclarey 12/4 Performance monitoring in Mercari mobile apps @fp 12/5 The Spirit of Giving: A Year-End Roundup of Our Open Source Contributions @adbutterfield 12/6 強いエンジニア組織に必要な、6つの技術以外のこと – メルカリ編 — @thiroi 12/7 英語が苦手なエンジニアがメルカリに入ってどうなったか @otter 12/8 t9n, i18n, l10n, g11n ?! @wills 12/9 Gitブランチ戦略 Stacking手法のケーススタディ @osari.k 12/10 In search of a knowledge management silver bullet @rey 12/11 チームワークと効率向上のカギ!メルカリが成功する大人数iOS開発のための手法とは? @sae 12/12 The art of streamlining mobile app releases @fp 12/13 Leading a team of lead engineers @fp 12/14 Current Microservices Status, Challenges, and the Golden Path @ayman 12/15 BigQuery Unleashed: A Guide to Performance, Data Management and Cost Optimization @sathiya 12/16 Closing the visual testing gap on Android with screenshot tests @lukas 12/17 The new Mercari Master API @cafxx 12/18 ① The Frontend Infrastructure Monorepo @jon 12/18 ② Onboarding施策を成功させるポイント @aisaka 12/19 Leveraging LLMs in Production: Looking Back, Going Forward @andre 12/20 GCSのリソース最適化の取り組みで得た知見 @ayaneko 12/21 iOSDC2023で発表した「メルカリ10年間のiOS開発の歩み」のトークスクリプトを公開 @motokiee 12/22① Making of "Your Mercari History" @manoj 12/22② 言語モデルを用いたQuery Categorization ( EN ) @pakio 12/23① メルカリの中長期技術投資 プロジェクトRFS: 約2年の振り返り @mtsuka 12/23② Fine-Tuned CLIP: Better Listing Experience and 80% More Budget-Friendly @andy971022 12/24 Renovate Web E2E tests with Playwright Runner @jye 12/25 メルカリEngineering Roadmapの作成とその必要性 @kimuras Mercari Advent Calendar 2023 の1日目は、 Data Engineeringチームのdarren が執筆予定です。 ひとつでも気になる記事がある方は、この記事をブックマークしておくか、 エンジニア向け公式Twitter をフォロー&チェックしてくださいね!
はじめに こんにちは、mercari.go スタッフの hiroebe です。 11月1日にメルカリ主催の Go 勉強会 mercari.go #24 を YouTube でのオンライン配信にて開催しました。 今回は GopherCon 2023 に焦点を当てた特別回として、サンディエゴで開催された GopherCon 2023 に実際に現地参加したメルカリエンジニアが、セッション内容を要約して発表しました。この記事では、当日の各発表を簡単に紹介します。動画もアップロードされていますので、こちらもぜひご覧ください。 GopherCon 2023 Recap 1つめのセッションは nsega さんによる「GopherCon 2023 Recap」です。 発表資料: GopherCon 2023 Recap at mercari.go#24 このセッションでは、はじめに GopherCon の概要と今年の GopherCon 2023 の様子について紹介し、後半のパートでは GopherCon 2023 から「The Future of JSON」というセッションについて振り返りを行いました。 Go の encoding/json パッケージは、長年使われてきた中で機能の不足やインターフェースの欠陥、パフォーマンスの制約といった問題を抱えていることがわかっていて、これを解決するために新たなメジャーバージョンである encoding/json/v2 パッケージが提案されています。セッションでは、これまでに挙げられた問題点が encoding/json/v2 パッケージによってどのように解決されるかについて詳細に説明されていました。 json と jsontext の2つのパッケージを用意する話など、個人的にもとても興味深かったです。 またセッションの最後には、このような大きな変更を伴う開発をどのように進めていくか、という点についても触れられていました。オープンに議論をしながら合意形成をしたり、パフォーマンスに関してはベンチマークを取りながら進めるといった手法は、nsega さん自身も今後開発を行っていく上で参考にしたいと仰っていました。 Concurrent Data Structures and CPU Caching with Go 2つめのセッションは derrick さんによる「Concurrent Data Structures and CPU Caching with Go」です。 発表資料: Concurrent Data Structures and CPU Cache with Go セッションの前半は、GopherCon 2023 の中から「Building A Highly Concurrent Cache in Go」というセッションの振り返りを行いました。このセッションでは Reddit でのキャッシュの活用事例について話されていて、Redis でのキャッシュとは別にローカルなキャッシュを導入することでコスト削減に成功した事例や、キャッシュのための独自のデータ構造を作成した事例などが紹介されていました。データ構造はシンプルなものから始めること、それを変更する際には都度プロファイルやベンチマークをとることといったノウハウが詰まった発表でした。 セッションの後半では、前半のセッションで言及のあった Cache Line について掘り下げて解説を行いました。サードパーティの xsync.Map は標準パッケージの sync.Map と比べても高いパフォーマンスを見せていて、その理由は Cache Line を考慮したデータ構造にあるそうです。Cache Line を理解するための前提知識として CPU のキャッシュについてもわかりやすく説明されていて、個人的にもとても勉強になりました。 Recap: Automatically Instrument Your Go Source Code with Orchestrion 3つめのセッションは komatsu さんによる「Recap: Automatically Instrument Your Go Source Code with Orchestrion」です。 発表資料: Recap: Automatically Instrument Your Go Source Code with Orchestrion このセッションでは Datadog 社が開発している orchestrion という CLI ツールについて紹介されました。orchestrion は Datadog で APM を計測するための Go のコードを自動計装 (code instrumentation) するためのツールです。Go は Java でいうアノテーションや Python でいうデコレータのような構文を持ちませんが、一方で文法がシンプルで AST のパースが簡単という特徴があり、それを踏まえたアプローチになっているそうです。また AST の解析には標準パッケージの go/ast ではなく dave/dst を使っているそうで、その理由についても触れられていました。シンプルなツールであるため導入が簡単である一方、大規模なリポジトリに導入するにはまだいくつかの課題があると komatsu さんは考えているそうで、今後のさらなる開発に期待したいです。 GopherCon 2023 Overview 4つめのセッションは tenling さんによる「GopherCon 2023 Overview」です。 セッションの前半では、GopherCon 2023 で行われた CTF について紹介しました。GopherCon で CTF が行われたのは今年が初めてで、セキュリティやコードに関してだけでなく、以前の GopherCon で発表されたテーマに関する出題もあったそうです。このセッションでは、CTF で出題された中から tenling さんがお気に入りの問題を2つ紹介しています。CTF は来年も実施を予定しているそうなので、今回の発表で興味を持った方はぜひチェックしておきましょう。 セッションの後半では、GopherCon 2023 から「From Zero to Hero: Launch Your Own Game in 45 Minutes」というセッションについて紹介しました。 feed-the-gopher というゲームを開発した事例の紹介で、 Momento というサービスを利用することで素早い開発を実現しているとのことでした。また、ゲーム開発では Unity などを利用するのが一般的になっていますが、Go でゲーム開発をする人がもっと増えてほしいという思いもこのセッションには込められているそうです。 Navigating the Seas of Data: A Migration Journey 5つめのセッションは mann さんによる「Navigating the Seas of Data: A Migration Journey」です。 発表資料: GopherCon 2023 Bitly _ Migrating 80 billion records from MySQL to Bigtable このセッションでは、Bitly がセルフマネージドな MySQL から Google Cloud の Bigtable へマイグレーションを行った事例が紹介されました。Key-Value 形式の膨大なデータを持つ Bitly 社では、従来の MySQL を利用した仕組みにおいてスケーラビリティやバックアップに関する課題を抱えていたそうです。それらの課題を解決するために Bigtable へのマイグレーションが実施され、結果として高いスケーラビリティや強固なバックアップが実現されました。セッションではマイグレーションの手順について順を追って説明されていて、中でも古いレコードのバックフィルなどを行うマイグレーションスクリプトが Go で記述されているそうです。マイグレーションは手順だけ見るとシンプルですが、これを膨大なデータを抱えるプロダクションサービスで実際にやりきったという事例はとても参考になると思います。 GOOOPs – Talking about Go and OOPs 6つめのセッションは amit-kumar さんによる「GOOOPs – Talking about Go and OOPs」です。 このセッションでは Go と OOP (オブジェクト指向プログラミング) の関係について説明しました。開発者の多くは Go に触れる以前に C++ や Java といった他のオブジェクト指向のプログラミング言語を扱った経験があるかもしれませんが、それらの言語におけるオブジェクト指向の考え方をそのまま Go に適用するべきではありません。そのような誤った方法で Go に OOP が適用された状態をこのセッションでは GOOOP (= GO + OOP) と呼び、GOOOP を疑うべき兆候としてどのようなものがあるか、具体例とともに紹介されています。またセッションの後半では、OOP とセットで語られることの多い SOLID 原則についても紹介しました。SOLID の各原則が Go ではどのように実現されるかについて、1つずつ順番に説明されています。従来の OOP の考え方をそのまま適用するのではなく、その背景にある原則を正しく理解し Go らしい書き方で実現することが重要であると結論づけていて、個人的にもとても勉強になるセッションでした。 おわりに 今回は GopherCon 2023 の活動報告会として、実際に現地参加したエンジニアからセッションの振り返りの発表をお送りしました。GopherCon 2023 に参加できなかった方も、イベントの雰囲気を感じていただけたのではないでしょうか? ライブで視聴いただいた方も録画を観ていただけた方も本当にありがとうございました! 次回の開催もお楽しみに! イベント開催案内を受け取りたい方は、connpassグループのメンバーになってくださいね! メルカリconnpassグループページ
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 今回、より多くの方に知ってもらい役立ててもらうため、Merpay & Mercoin Tech Fest 2023の全セッションを書き起こした記事を用意しました。セッションがたくさんあるので、その記事リンクまとめを作成したのが本記事です。お役に立てば幸いです。 ▼Merpay & Mercoin Tech Fest 2023 書き起こし一覧 ※各記事にYoutubeのセッション動画が埋め込まれています。 .author_icon{width:50px; height:auto; margin:1px; border-radius:20px} .day1{ border: 2px solid #ff0211 !important} .day2{ border: 2px solid #4dc9ff !important} .day3{ border: 2px solid #00c1aa !important} Author Session Title Keynote Shunya Kimura How to Unleash Fintech Shunya Kimura , Keigo Watanabe , Noriaki Utsunomiya 1週間リリースを支えるAndroid自動テスト運用のその後 Kenta Takahashi , Shintaro Miyabe Merpay iOSのGroundUp Appへの移行 kenmaz Merpay iOSにおけるSwift Concurrency対応の挫折と今後 Takeshi Sato SwiftUIでビットコインの価格チャートを改善・再実装した話 andooown フロントエンドチームのスキルテスト評価システム改善の取り組み tokuda109 WYSIWYGウェブページビルダーを支える技術的マジックの裏側 Hal Amano , Arvin Huang , Ben Hsieh , Jas Chen メルカリのカスタマージャーニーにおける不正防止の取り組み codechaitu 日本におけるお客さま本人確認と今後の技術的課題 Tim Tosi , Manpreet Kaur , Christophe Labonne メルカリへのFIDO導入の経緯とこれからの展望、課題から得た学び koi , kokukuma , daichiro , hidey メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化 Peichong Cui 拡張性を備えたソフトウェア設計 Rupesh Agrawal 発行枚数100万枚を支えたメルカードGrowth施策の裏側 Kazuya Kawashima , Soichiro Kashima , Mikael メルカードの常時ポイント還元開発の裏側 keitaj メルペイ加盟店売上精算の仕組み Takumi Shibazaki GoによるSQLクエリテストの取り組み Yuki Mukasa 発生可能な取引の属性データを用いた素早い不正検知 Liu , Li メルペイMLにおける機械学習の品質保証とリスク管理 shuuk , Haruki Kaneko , Yuki Saito Merpay & MercoinにおけるLLM活用の取り組み Yuki Ishikawa , Daisuke Torigoe , Noriaki Utsunomiya , hmj BigQueryのデータ監視社内サービスを作った話 Hirobumi Takahashi 社内用GitHub Actionsのセキュリティガイドラインを作成した話 Toshiki Kawamura BigQueryのコンピューティングリソース管理の取り組み Go Kojima fake clock microservice -時刻をハックしてテストする方法- vvakame , Hiraku Nakano , Hiroyuki Tanaka メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み Masaki Iino , Takaaki Yuhara メルコインにおけるシステム間のデータ分離を実現するための通信アーキテクチャ Kohei Noda Building a Global environment at Merpay: India & Japan Robert Jerovsek , Keigo Andrade , Sumil Panicker なめらかなFintech QAを実現するためにテストケースフォーマットを標準化した話 Yuki Sakamoto , Masatoshi Sato メルコイン決済基盤の実践話 Junwei Liang メルコイン決済マイクロサービスのトランザクション管理を支える技術 Shota Suzuki Merpay Engineering Career Talk Keigo Watanabe , Osamu Tonomori , Katsuhiro Ogawa gRPC Federation を利用した巨大なBFFサービスに対するリアーキテクチャの試み goccy Enabling ProgramのEngineering Headをちょっとやってみている Masahiro Sano Merpay & Mercoin Tech Fest 2023 プレイリスト Merpay & Mercoin Tech Fest 2023 の各セッションごとの動画と、各DayごとのLiveアーカイブ動画をまとめたプレイリストです。気になる動画や、一気に視聴する場合などにお役立てください。 再生リスト: Merpay & Mercoin Tech Fest 2023 – YouTube
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 社内用GitHub Actionsのセキュリティガイドラインを作成した話 」の書き起こしです。 @goro:今回、「社内用GitHub Actionsのセキュリティガイドラインを作成した話」というタイトルで発表させていただきます。株式会社メルコインで、バックエンドエンジニアをしております。Toshiki Kawamuraと申します。よろしくお願いします。 私は株式会社メルコインに、2022年の6月に入社しました。メルコインでは主にビットコイン取引サービスの立ち上げに参画して、バックエンドエンジニアとして開発運用を担当しております。 今回発表の題材になった、GitHub Actionsのセキュリティガイドラインの作成などの取り組みも関わっております。 まず発表の最初として、今回テーマに置いているGitHub Actionsのセキュリティガイドラインについて説明させていただきます。 GitHub Actionsセキュリティガイドラインとは、社内でのGitHub Actionsの利用の広がりに合わせて、社内有志によって検討策定された。セキュリティのガイドラインになっております。 GitHub Actionsを使うにあたり、どういった点に留意すれば、最低限の安全性を確保できるか学習してもらいたい、定期的に本ドキュメントを見返してもらい、自分たちのリポジトリが安全な状態になっているかを点検する際に役立ててもらいたいという想いに基づいて作成されているガイドラインになります。 ガイドラインは、合計4人のチームで作成しました。 まずは株式会社メルカリのSolutions Teamに所属している@vvakameさん、株式会社メルカリのバックエンドエンジニアをしている Motonori Iwataさん、株式会社メルコインのエンジニアリングマネージャーをしている sadahさん、僕の4人の有志メンバーで、このガイドラインを作成していきました。 それでは、本発表の流れを事前に紹介します。まず最初にガイドラインの中身を一部紹介いたします。その後に、ガイドラインの社内での活用状況について紹介した後に、最後にガイドライン策定の裏話ができればと思います。 それでは発表に入っていきます。まずはガイドラインの中身を一部紹介します。 ガイドラインを策定する上で、まずはチーム目標を決めました。 まず一つ目に「常に達成したいこと」として決めたのは、「外部の攻撃者からの攻撃を防ぐこと」。二つ目に、「可能であれば考慮したいこと」として、「内部と同等の権限を持つ攻撃者からの攻撃を防ぐ」。この二つを大きな目標に置いて、ガイドラインを作成していきました。 ガイドラインの構成は3部になっています。 まずはどのような脅威があるのかを知ってもらうという意図を込めて、第1部では、脅威を知るというテーマで、GitHub Actionsを利用するにあたって、起こりうるセキュリティ上の脅威を紹介しました。 2部では、1部で紹介した脅威に対して、どのような対策が取れるのかを紹介しました。 最後の3部では、主に2部の内容をベースに、どのような項目を満たすと、実際にセキュリティの対策ができるのかがわかりやすくなるように、チェックリスト形式で行って、ほしい対策について、具体的な設定方法を含め、記載しました。このような内容でガイドラインは構成されています。 それでは1部から紹介していきます。 脅威として紹介したのは、「権限設定の不備を突く攻撃」になります。プルリクエストを契機に起動するトリガーは攻撃者が何かを仕掛ける余地が大きく、不注意にワークフローを構築すると、シークレットを外部に送信されて攻撃を受ける可能性があります。 補足情報として、GitHub Actionsのトリガーにはどのようなものがあるかを紹介していきたいと思います。 例えば、ワークフローのリポジトリで発生したイベントです。例えば、リポジトリのDefault Branchにプッシュが行われたときや、リリースが作成されたとき、あるいはIssueがオープンされたとき。 プルリクエストが作成されたときなどに、ワークフローを実行するように設定することが可能です。 他にも、GitHubの外部で発生し、GitHubでリポジトリディスパッチイベントを発生させるイベントですとか、時間指定での自動実行など、さまざまなトリガーがあります。 そのようなワークフローの権限設定において不備があると、例えばシークレットが外部に送信されるなどの危険性があります。 ここで、外部に送信される方法として考えられるものをいくつか記載しました。例えば、ビルドスクリプトに細工をする、依存関係にあるライブラリを悪意のあるものに差し替える、自動実行の仕組みに相乗りされる(例えばnpmのpreinstallやpostinstall)。 また、過去にも実際に人気のライブラリでローカルファイルをスキャンする事例がありました。このような方法でシークレットが外部に送信される危険性があります。 それ以外にも、権限設定の不備があると、攻撃が行われるような影響が考えられます。 例えば、攻撃者に悪意のあるActionsや、侵害されたActionsによってGitHub Actionsの計算リソースを不正に利用される可能性が考えられます。 他にも、侵害された または 悪意のあるActionsによって、リポジトリの自動ワークフローが中断される可能性もあります。他にもDeployment Keyやアクセストークンなどの、シークレットへの読み取りアクセスは攻撃者が他のリソースを侵害するために利用される可能性があります。以上が権限設定不備があった場合に、起こりうる事象の紹介です。 次に紹介したいのは、インジェクションによる攻撃です。一見安全に見えるワークフローにおいても、コードやコマンドインジェクションを引き起こす可能性があります。 事例を二つ紹介します。まず、事例の一つ目になります。スライドのコードを見てください。 このコードにはインジェクションの脆弱性があります。コメントを二重括弧で囲っている箇所がありますが、ここに1+1のようなものを入れると、Actionsは内部で二重括弧のあたりを補完するためにlodashを使っているため、Node.jsのコードが実行され、出力が2になります。 二つ目の事例です。ワークフローのインラインスクリプトに直接インジェクションを配置するシナリオも考えられます。また、ブランチ名やメールアドレスへのコマンドインジェクションも可能です。 ここで具体的に紹介するのは、こちらのコードです。 内部の式の二重括弧が評価され、結果の値に置き換えられるため、コマンドインジェクションに対して脆弱になる可能性があります。ここではプルリクエストのタイトルが二重括弧に囲まれています。 攻撃者が実際にどのようなことができるかというと、「a”;ls $ GITHUB_WORKSPACE*」というタイトルのPRを作成する可能性があります。これを利用して、ステートメントを中断し、ランナーでコマンドを実行できるようになっています。実行すると、lsコマンドが確認できます。 インジェクションが起こると、どのような影響があるかを紹介します。インジェクションをされると、攻撃者は任意のコマンドを実行できるため、外部のサーバーにシークレットを送信するHTTPリクエストを行うことが可能になります。 リポジトリへのアクセストークンを取得しても、ワークフローが完了すると失効するので、攻撃自体は簡単ではありません。しかし、攻撃者が自動化し、管理するサーバーにトークンを呼び出してコンマ数秒で攻撃を実行することが可能です。 その場合、GitHub APIを利用してリリースを含むリポジトリのコンテンツを変更するなどの影響も考えられます。 なので攻撃者は悪意のあるコンテンツをGitHub Context経由で追加できるので、潜在的に信頼できない入力として扱う必要があります。以上が第1部「GitHub Actionsでの脅威を知る」の紹介でした。 第2部は「対策を考える」です。 まず対策の一つとして紹介したいのは、「最小権限の原則に従う」ということです。最小権限の原則は、ソフトウェアがタスクを達成するために必要な最小限の権限セットで実行されるべきであるという原則です。 ワークフローで利用可能なシークレットの権限と、ワークフロートリガーの種類に基づいて自動的に提供される一時的なリポジトリトークンの両方に当てはまります。 この原則に従うと、GITHUB_TOKENの権限のデフォルト設定は、読み取りと書き込み権限から読み取り専用に変更した方がいいと思います。 実際にこの設定をやろうとすると、リポジトリのSettings > Actions > Generalから変更できるので、ぜひ変更してみてください。 また、GitHub Actionsの権限はジョブ単位で設定を行うことで、権限を最小化できますのでなるべく権限は細分化して設定することが推奨されます。 シークレットの利用についても、いくつか対策があります。例えば、Long=lived tokenを使用しない、Workload identity federationを用いたSecret Managerの利用を検討する、JSONなどの構造化データをシークレットにしないことがあげられます。 3つ目については、なぜかというと、GitHub Actionsは、全文をマスクデータとして扱ってくれますが、部分マスクはされないためです。 ワークフロー内で使用される全てのシークレットマスクをマスクするように登録することも、対策として考えられます。シークレットに保存されたアクセストークンの利用状況を観察することも必要です。 他にもスコープが最小限のクレデンシャルを使用する、登録されたシークレット監査およびローテーションする、シークレットへのアクセスについてレビューを要求する。こういった対策が考えられます。 次は、イベントトリガーの対策です。 利用すべきイベントトリガーとして、リポジトリへのwriteはできないように制限されているので、プルリクエストの処理にはpull_requestイベントを使った方がいいです。 少し制限を緩めたものとして、pull_request_targetがあります。Github Actionsのワークフロー自体は、pull_request_targetだと、Default Branchのものが使われます。ワークフローのyamlに直接記載する場合は、攻撃者によって上書きされることはありません。チェックアウトしたコードに含まれるComposite Actionを使う場合は注意が必要となります。 ここで、Composite Actionについて補足させてください。Composite ActionはカスタムActionの一つであって、使用することで、ワークフローの複数Stepを組み合わせて一つのActionsにできます。 例えば、複数のrunコマンドを一つのActionにまとめて、そのActionsを一つのStepとしてワークフローから呼び出して実行することが可能になってきます。 なのでpull_request_targetをイベントトリガーとして使う場合、Composite Actionは、攻撃者によって上書きされる可能性があるので、注意が必要です。 シークレットの内容を露出する際、可能な限り単位を狭くする方がいいです。Job単位よりStep単位の方がより良いと考えられます。Step間のファイルによるデータのやり取りは、全ステップから可視であると考えてください。 Jobは処理によって分けることも一つの対策になります。例えば、テスト/ビルド/デプロイはそれぞれJobを分けた方がいいです。これはなぜかというと、必要なGithub ActionsのPermissionやクラウドプロバイダーの権限を制御できるためです。 次に紹介したいのが、Dependabot / Renovateを利用したGithub Actionsでの更新になります。Actionsはバグの修正や新機能によって、頻繁に更新されます。Dependabot / RenovateでGitHub Actionsの依存関係を最新に保つことができるため、設定しておくとより良いと考えます。 次はサードパーティのActionsを利用する際の注意点です。サードパーティのActionsを利用する場合、基本的にFull Changeset Hashに固定するのがいいと考えています。 サードパーティのActionsの書き方は、四つあります。 まず一つ目がFull Changeset Hash。これは基本的には衝突が困難になっています。次にあるのがShort Changeset Hash。これも衝突がしにくいですが、脆弱となっています。次に、よく使われるTag / Releaseです。この場合、タグを後で変更されて意図しない変更が混入してしまう可能性があるので、注意が必要です。Branch Nameの場合意図しない変更が混入してしまう可能性もありますし、将来壊れる可能性があるので、なるべくFull Changeset Hashで指定するのがいいと考えています。 Full Changeset Hashで記入すると、このバージョンを使っているのかがいまいちわからないなっていうのがあるので、その場合はバージョンコメントを記載するのがわかりやすくておすすめです。 同じくサードパーティActionsを利用する際の注意点でもありますが、Actionsのソースコードをしっかり観察して、サードパーティのホストにシークレット送信するなどの疑わしいことがないか確認することが必要です。 ワークフロー内で利用しているサードパーティActionsのAction permissionsの設定をセキュリティ観点で見直すことも推奨されます。この設定に関しては同じくリポジトリのSettingsで可能になっています。不要なワークフローやJobは削除した方がいいです。不要なものは削除して、なるべく依存を減らすのが良いです。 先ほども触れたインジェクションについてですが、これを防ぐためには信頼されない式の入力値を中間環境変数に設定することが、対策として考えられます。 例ではこのようにenvに中間環境変数を入れていますが、この方式は、スクリプトの生成に影響するのではなく、メモリに保存されて変数として使用されます。このように、信頼されない式の入力値を中間環境変数に設定するのも有効です。 他にも、シェル変数をダブルクォートして単語の分割を避ける。これはシェルスクリプトの一般的な水槽事項でもあります。 GitHubのカスタムアクションやワークフローを書くときは、信頼できない入力に対して書き込み権限でコードを実行することがあることを考慮した方がいいです。外部Actionsとなりますが actionlist を使用することで対策できるので、導入を検討したり、GitHub Security Labの開発する CodeQL queries を利用したりすることも対策として考えられます。 それでも完全に攻撃を防ぐことは不可能と考えて、問題が発生したときに受ける影響を最小限に抑える必要があります。 例えば、プロダクション環境に影響を及ぼす(サービス停止など)ことが最悪のケースなので、対策が必要です。もう一つ、GitHub Action がPRを作成またはオーナーとして承認しないようにすることも対策の一つです。 最後に、第3部の「セルフチェックリスト」です。 セルフチェックリストは、定期的にチェックすることで、GitHub Actionsの安全な利用に繋げるという目的があり、ガイドラインで学習した内容が本チェックリストでカバーすることを目指して作成されています。 第2部の内容をベースに、講じてほしい具体的なセキュリティ対策を設定方法含め、チェックリスト形式で記載しています。 ここでは一例を紹介します。例えばCODEOWNERSの設定を見直すことが一つチェックリストにあります。CODEOWNERSというファイルが.githubディレクトリにあるのですが、そこで適切にコードのオーナーが設定されることが必要になってきます。 Protected Branchの設定で、Default BranchへのPull RequestがCODEOWNERSによる承認が必須になっていることも、チェックする必要があります。 続いて、ワークフロートリガーを見直すこと。コードプッシュをトリガーとする場合、pull_requestか、それが難しければ、pull_request_targetを使うことを考えた方がいいです。 on: psuhをpull_request用に使っていたら見直す必要があります。 このように、具体的な対策をチェックリスト形式で書いています。 さらに詳しい内容はブログに公開しておりまして、そちらを見ていただきますと、今回発表したガイドラインの内容が更に詳しくなっておりますので、ぜひご覧いただければありがたいです。 参照 社内用GitHub Actionsのセキュリティガイドラインを公開します 次は、ガイドラインが実際に社内でどのように活用できているかを紹介します。 一つ目の活用状況として紹介したいのが、Developer Documentationの追加です。これは主に、メルカリ、メルペイ、メルコインのバックエンドエンジニアがよく参照する社内プラットフォームの使い方がまとまった社内ポータルです。そこにGitHub Actionsのセキュリティガイドラインを掲載していただきました。 次はSecure Coding Guidelinesの掲載です。このガイドラインはSecurity Teamがメンテナンスする社内基準のセキュリティルールを満たすためのガイドラインです。ここにもGitHub Actionsのガイドラインを掲載しました。 他にも各チームでのガイドライン提供やサポートなどを行っており、プロジェクトメンバーに自チームに関するリポジトリに対して、今回作成したガイドラインの内容を適用させたり、他のチームがガイドラインを適用する際のサポートや質問を受け付けるような体制となりました。 最後に、「ガイドライン策定の裏話」をします。 まず、このガイドラインをどのように作ったかについて紹介します。まず最初に、作成する上で行ったことは、GitHub Actionsのセキュリティに関する文献記事をチームメンバーで読んでいくことです。記事には複数の記事がリンクされているので、それらも読んでいきました。 そこで得たインプットをもとにガイドガイドラインのアウトラインをまとめて、3部構成を作りました。参考文献の設定を試したりしながら、ガイドラインを変えていくフェーズに入り、その後に自分たちでガイドラインをレビューして、あとSecurity Teamにもレビューしていただきました。レビューをいただいた内容を修正して、英訳して公開しました。 ちょうど1年前ぐらいから始まったプロジェクトで、2022年の7月から9月の間にメンバーを招集して、アウトライン・執筆を開始していきました。その後、10月から12月の間にレビューを実施したり、リファクタリングをした後に、2023年に入ってから最終レビューが完了して、正式版を公開しました。4月から6月の間に、エンジニアリングブログでの社外公開なども行いました。 ガイドラインを作成していく中で、気をつけた点についても、4点ほど紹介させてください。 まず一つ目は「小さく始める、無理をしない」ということ。これはボランティアメンバーで、それぞれのメンバーが別のプロジェクトを持ちながら進めていったので、なるべく無理をしない形で、進めていきました。 二つ目が、「絶対完成させるという強い意志を持つ」。こういう有志の取り組みを長期的に継続していくのは難しいかなと思うのですが、でも絶対完成させるという強い思いをみんなで持って、完成させました。 三つ目が、「適切な量のフィードバックをもらえるように意識する」。これはちゃんと外部の意見を取り入れながらリファクタリングできるようにという名目でもありますし、大量にフィードバックが降ってくると修正も大変なので、適切な量になるようにコントロールしてもらいました。 四つ目が、「正式版を公開してから育てていく」。GitHub Actionsやセキュリティなどに関連する技術は、今後も日々アップデートしていくので、正式版を公開したから終わりではなく、今後も育てていくようにしていきたいです。 GitHub Actionsのセキュリティガイドラインは、今後も適切に更新していき、よりスムーズで安全な開発をサポートできるように努めていきたいと思っています。また更新した際には外部向けにも発信していこうと考えておりますので、ぜひご覧いただけるとありがたいです。 以上です。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 Keynote 」の書き起こしです。 @kimuras:メルカリFintech領域のCTOを担当しているKimuraです。本日はMerpay & Mercoin Tech Fest 2023をご視聴いただき、誠にありがとうございます。 メルペイが2017年に設立してから、2023年になって決済や与信、クレジットカード、暗号資産など、多くの金融サービスを提供してまいりました。今回は、多くの成功を支えてきた技術をふんだんにまとめ、Merpay & Mercoin Tech Fest 2023を実施することになりました。 また、これら金融サービスを伝える技術的な土台をいかして、これからもFintechサービスを成長させ、「世界をなめらかにする」というミッションを実現していくことを目指し、次世代のFintechサービスを作るためのアイディアやヒントになるような、気づきとなるものをご提供できたら幸いです。 私はKimuraと申します。メルペイ・メルコインのCTOを担当しています。 もともと機械学習領域を担当していましたが、2017年より株式会社メルカリに入社し、研究開発組織R4Dの立ち上げを行い、AIを中心とした幅広い研究領域のリサーチを担当しました。その後、AIと検索エンジン領域のエンジニア組織を設立してDirectorとしてメルカリのAI導入をリードしました。 2022年7月より、社内のプラットフォーム開発を統括するVP of Platform Engineeringを担当し、CTOとして4月から働いています。 まず、メルカリグループのFintech事業を振り返ります。 2023年2月にメルカリグループは10周年を迎え、「あらゆる価値を循環させ、あらゆる人の可能性を広げる」というミッションを新しくしました。 メルペイはフリマアプリ「メルカリ」での売る・買うの取引を通じて信用情報を可視化し、新しい信用の形を生み出して、それに基づいてお金を自由に使える世界を作ることを目指しています。 メルコインはモノ・お金だけではなくて、暗号資産、NFTなど、あらゆる価値をめぐらせて新しい経済を作ることを目指しています。世界中のモノやコト、人には見出されていない価値がたくさんあり、その価値を必要としている人もまた世界中で数多く存在していると思っております。 メルカリグループはテクノロジーの力で世界中の人々をつないで、有形・無形に限らずあらゆる価値が循環するエコシステムを作ることを通じてその人の可能性を広げる存在でありたいと考えています。 メルペイは2019年2月にサービスを開始しました。iD決済・コード決済といった決済領域から始まり、あと払いサービスであるメルペイスマート払いで、与信領域を本格的にスタートさせました。 その後、バーチャルカードやメルペイスマートマネー、メルカリの利用実績等で限度額が決まってアプリで利用と管理が完結できるメルカードをローンチするなど、サービスを拡充しました。 メルカードは提供開始から 約半年で発行枚数100万枚を突破 して、国内で今トップレベルとなっております。そして2023年3月からメルカリアプリ内でビットコインが売買できるようになりました。この開発を担うのがメルコインとなります。 金融機関からチャージした残高はもちろん、メルカリで不用品を売って得た売上金やポイントを活用して、1円という少額から安心して始めることができます。こちらも提供開始から 3ヶ月強で利用者数50万人を突破 しています。 これらのように2019年からサービスの提供を開始して、Fintech領域では1,571万人ものお客さまにご利用いただくまでに成長しました。 メルカリグループで構築する「循環型金融」ということで、ここからこれらのサービスを支える技術について触れていきたいなと思います。 多くのサービスを開発し、約1,500万人ものお客さまに金融サービスを提供してきた成長の背景には どのようなものがあるのかをお話しします。 金融サービスはセキュリティ的な要件が非常に高く、技術的には妥協が許されない領域です。 そしてメルペイの特徴でもある「なめらかな社会を実現する」ため、簡単で便利なUIを提供するという攻めの姿勢と、セキュリティを高めるための守りの姿勢は、基本的に相反する関係にあります。 UIを簡易的にすればするほど、セキュリティは甘くなってしまいますし、セキュリティを厳しくすればするほど、簡易なUIを提供することは難しくなってしまいます。 我々はこの攻めと守りのバランスを保つことで、大きな障害を避けつつも便利なUIを提供することでお客さまの支持をいただいてきたと考えています。 攻めと守りを実現するために、人材投資にもバランスを保ってきているのが、我々を支えてきた源泉だと考えています。 大きく組織を説明しますと、メルペイのエンジニア組織は大きく分けて、プロダクト開発をメインで行っているProduct Engineeringと、Foundationやプラットフォームの開発を行っているPlatform Engineeringの二つの組織があります。 メルペイは設立当初から現在までProduct EngineeringとPlatform Engineeringに対して、バランスよく人材投資を続けており、人数はおおむね同じ割合となっております。 なめらかなUI提供をするためにProduct Engineeringは重要ですし、堅牢なFoundation Platformを構築するPlatform Engineeringと同じ割合で投資することで、複雑なシステムであってもSecurityやAvailabilityを担保し続けているという背景があります。 Fintechの成長を支えてきたテクノロジー投資についても説明します。多くのFoundationへの投資の中でも、今回は不正対策、セキュリティ、リアーキテクチャ、独自の与信モデルについてご紹介したいなと思っております。 基本的に不正対策はルールベースのものもありますが、機械学習をメインに活用し、Vertex AI Pipelinesを導入してモデルのトレーニングやデプロイを共通化しています。また特徴量を共有化することによるコスト削減はFeature StoreとしてFEASTを導入しています。これにより保守性担保やコスト削減だけじゃなくて結果としてエンジニアがモデル開発の改善に、より時間を費やすことができるようになり、生産性向上や品質改善にもつながりました。 メルペイの不正対策に活用しているのが、グラフ理論というものです。節点と呼ばれるノードの集合と、辺と呼ばれるリンクの集合で構成されるグラフに関する数学の理論を活用しています。メルカリ・メルペイには非常に多種多様なデータがあります。お客さまのアカウントの情報や出品、決済、購入といった情報をグラフとして表現し、類似度を計算するといったことができます。 【書き起こし】グラフ理論と不正対策 つながりをデータから解き明かしたい – hmj 【Merpay Tech Fest 2022】 不正対策・不正検知については、今年もセッションを用意していますので別セッションで詳細をご覧ください。 【書き起こし】メルカリのカスタマージャーニーにおける不正防止の取り組み – codechaitu【Merpay & Mercoin Tech Fest 2023】 【書き起こし】発生可能な取引の属性データを用いた素早い不正検知 – Liu / Li【Merpay & Mercoin Tech Fest 2023】 続いて、セキュリティについてです。セキュリティでは3DセキュアやFIDO、パスキーの導入を行ってきました。 3Dセキュアの導入は不正利用を未然に防ぐための対策です。2021年12月に比べて、不正利用数は10分の1まで抑えることができました。図は1年前の状態を示しています。直近でもこの低水準の状態を継続できています。 本件に関しても、去年のセッションやブログで紹介しています。今年も進化した部分であると、2022年11月に、 FIDOアライアンスに加盟 して、メルカリの各種サービスにFIDO認証の実装を進めています。2023年3月にリリースをしたメルコインにFIDOあるいはパスキーを導入しています。 【書き起こし】Credit Card Payment Security: adding 3D Secure SDK for Merpay iOS – Mikael LE GOFF 【Merpay Tech Fest 2022】 【書き起こし】メルカリグループの認証基盤における理想と現状、今後の取り組み – kokukuma 【Merpay Tech Fest 2022】 約2年半かけて、iOS Androidアプリケーションでも同じく、スクラッチから作ったアプリケーションに移行するプロジェクトを進めました。 今はすでにこの新しいバージョンを全てお客さまに提供できておりまして、コードベースもモダンかつコンパクトな状態です。今後は生産性が改善によって上がり、よりよい機能をより早くお客さまに提供できるようになっています。 リアーキテクチャした背景として、メルカリのアプリリリースから約10年近くの月日が経っております。アプリのアーキテクチャの潮流やUI/UXのフレームワーク、OSが提供する機能など、何もかもが大きく変わっています。 またメルカリはこの間に大小さまざまな機能がリリースされており、コードベースも膨大になってビルドやメンテナンスに大きなコストがかかっていました。モダンなフレームワークの導入や新たなデザインシステムの採用などに取り組んできましたし、最終的には生産性の観点からAndroidでもコード量を約半分の程度に減らすことができたということで、大きなメリットを得ることができました。 ほかにもさまざまなチャレンジをしていますので、詳細は他セッションをご覧ください。 【書き起こし】Merpay iOSのGroundUp Appへの移行 – kenmaz【Merpay & Mercoin Tech Fest 2023】 【書き起こし】Merpay iOSにおけるSwift Concurrency対応の挫折と今後 – Takeshi Sato【Merpay & Mercoin Tech Fest 2023】 技術的な観点では、独自の与信モデルも欠かせません。メルペイでは包括信用購入あっせん業者の認定を日本で初めて取得し、勤続年数や年収など、一般的な属性情報だけじゃなく、メルカリが持っているデータ、あるいはメルカリの行動実績に基づいて、信用を判断することができます。独自与信モデルはメルペイスマート払いやメルペイスマートマネー、メルカードなどのサービスで活用されています。 機械学習は不正対策だけではなく、このような独自与信モデルも使っています。詳細は、こちらのセッションをご覧ください。ITエンジニアとITリスクマネジメントのメンバーが密にコミュニケーションをとり、AIの危険性やリスク管理にどのように対応するかを解説します。 【書き起こし】メルペイMLにおける機械学習の品質保証とリスク管理 – shuuk / Haruki Kaneko / Yuki Saito【Merpay & Mercoin Tech Fest 2023】 ここからは、これからの技術的な挑戦について簡単に説明します。 これまで説明したように、Fintech領域でおおむね土台となるサービスを実現してきました。「なめらかな社会を実現する」という意味では、大きな土台が出来上がりました。 大きく分けると、簡単で安全に利用できる決済システムや、メルカリでの行動に基づいたAI与信、簡単に本人確認ができるeKYCサービス、簡単に暗号資産を購入できるメルコイン、アプリで利用と管理が完結するクレジットカードサービスのメルカードなどがリリースされました。 しかし、これでFintechのテクノロジーが終わりではありません。今後もよりなめらかな世界を実現するためには、Fintechサービス外からでも活用できるようにプラットフォームの強化をしていく必要があります。 今後Fintechを解き放ち、より世界をなめらかにしていくためには、三つのポイントが重要だと考えています。一つ目はこれまで培ってきたFintechサービスを生かして、プラットフォームとしてFintech外でも活用されること。 Fintechは単体でも価値のあるものですが、同時にメルカリグループ内でも重要なプラットフォームになっています。今後はよりグループシナジーの強化につながるプラットフォームとしての機能強化や、APIの整備に力を入れる予定です。 二つ目はデータ基盤整備です。Fintech領域では、日々、膨大な決済情報が蓄積され、よりメルカリグループでのサービスのデータ連携を強化することで、お客さまにより価値が提供できると考えています。 しかし、データ量は増えていくと同時に、データをうまく活用するためにはデータの基盤の改善・変革が必要となってきます。情報のAccessibilityとMaintainabilityをより改善していき、安全なサービス開発、そしてグループ間でのデータ連携を実現していきたいです。 最後に、LLMの活用強化も重要です。これまでメルペイでは、不正検知やAI与信でLLMの活用を本格的に行ってきましたが、LLMの実用化によって、Fintech領域でのAIの活用はさらに進化を遂げると考えています。より安全かつ便利で、金融領域に詳しくないお客さまへの洗練されたサポートを実現し、よりなめらかな社会構築に貢献できるのではないかなと思っております。 グループシナジーの強化について簡単にご説明します。メルペイやメルコインでは、決済、与信、信用情報、暗号資産など会社にとって重要な機能や情報を持っています。 これらの機能や情報は、すでにメルカリグループ内で活用は進んでいます。しかし、より今後お客さまに便利でお得にサービスをご利用いただくためにも、メルカードのポイント還元であるロイヤルティプログラムでデータ活用をより促進していくためのデータ連携やAPI強化は重要になってきます。また、メルカリ内で行っているサービスなどにあわせた決算基盤を提供するとか、そういったことがグループ会社として今後重要になってきます。 メルカリではさまざまな新規事業も展開しておりまして、新規事業を実現する上でも、決済機能や与信機能、セキュリティ機能などを提供することによって、新規事業のサービス提供スピードがより向上して価値のあるサービス提供が可能になり、グループシナジーの強化につながると思っています。 また、具体的にはまだ進められていませんが、将来的にメルカリ外にも機能提供する基盤が整備されることによって、メルカリの金融サービスとしての価値向上や、世界の金融サービスの利便性向上にも貢献できるのではないかと考えています。 メルペイではメルカードをご利用いただいてるお客さまに、よりお得にサービスをご活用いただくためにポイント還元をするロイヤルティプログラムを提供しています。 これがデータ基盤にとても関わっており、現在もこのサービス自体は提供しています。提供を続けるには、日々お客さまの売買データを効率的に分析できるように基盤を整備していかなければいけません。 メルカリとのデータ連携を強化するためにも、中間データの整備やデータ構造自体の整備が今後重要になってきます。AIのためのトレーニングデータを作成し、包括的に管理する仕組みが重要になってきますし、特にLLMでは多くのテキスト情報とメタデータの付与が重要になるのでAIに特化したデータ構造や、データパイプラインの構築が今後重要になってきます。 同様にデータ利活用が進めば進むほど、データベースのインフラコストは増大します。 今後 AI活用が強化されている中で、世界中でもインフラコストの最適化は重要なトピックになっています。我々もサービス改善を目的として日々データの量は増加しているので、攻めと守りの姿勢を継続してインフラコスト最適化を進めていきたいです。 最後にLLM活用なんですけども、こちらもセッションが別にございますので、ぜひこちらで議論を見ていただけたら幸いです。 【書き起こし】Merpay & MercoinにおけるLLM活用の取り組み – Yuki Ishikawa / Daisuke Torigoe / Noriaki Utsunomiya / hmj【Merpay & Mercoin Tech Fest 2023】 今回のイベントは、「Unleash Fintech」というテーマで、これからも世の中を便利にしてなめらかな社会を作り、多様な価値をめぐる新しい経済を作り、そして人々の可能性をより解き放つために、テクノロジーの力でまだまだできることがあるという強い気持ちを持って開催させていただくことになりました。 我々がこれまで培ってきたテクノロジーを公開することで、少しでも世界のFintechの進化に貢献できたら、とても嬉しく思います。 そして、これからも技術に謙虚な反省を忘れず、時には大胆に、時には冷静に世の中をよくするために自信を持った技術を使っていきたいという気持ちがあります。 以上です。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 Merpay iOSのGroundUP Appへの移行 」の書き起こしです。 @kenmaz:今回は、「Merpay iOSのGroundUP Appへの移行」というタイトルで、iOSチームの@kenmazが発表します。 こちらが私の自己紹介です。 今回のメインテーマであるMercari iOSのGroundUP App(GU App)とは何かについて説明します。 GU Appは、メルカリ本体のコードをフルスクラッチで書き換え、さらにBazelによる高速・高信頼のビルド環境に置き換え、メルカリをイチから作り直すプロジェクトです。 メルカリの開発が始まってから10年以上経って、技術的負債がかなりたまってきている状態になったので、フルスクラッチで書き換えるのが本プロジェクトの目的です。 このプロジェクトではiOSではSwiftUI、AndoirdではJetpack Composeといった最新のUIフレームワーク、さらにDesign System v3.0という社内のUIライブラリを最新版に置き換えることが盛り込まれたプロジェクトです。 フルスクラッチで書き換えるプロジェクトなので、再構築期間中は新規機能開発を凍結し、フルスクラッチでのリライトに集中する流れで進みました。 参考記事 メルカリアプリのコードベースを置き換える GroundUP App プロジェクトの話 メルカリiOSアプリのBazelを使った高速・高信頼性ビルド メルカリアプリの上にはメルペイの機能が載っています。メルペイにおいてのGU Appへの移行について説明します。 メルカリ本体のコードと比べるとメルペイのコードは、比較的技術的負債が少ない状況でした。開発が開始してから、当時で2〜3年ほどしか経っておらず、比較的クリーンなUIKit + Design System 1.5を使っていました。そのため、メルペイのコードについては、フルスクラッチで書き換えるよりも、最小限の変更でそのままGU Appに載せ替える方針を決めました。 さらにGU Appの裏で、メルペイでは新規機能開発の必要性があり、メルペイ自体の開発を止めるわけにはいきませんでした。移行期間中でもメルペイの新規開発は極力止めずにそのまま載せ替えることを目的としました。 こちらがプロジェクト全体の概要です。上の段の「Production」が実際にお客さまに届けるアプリの状況で、下の段の「Development」が社内で開発しているコード群です。 GU Appのプロジェクト自体は2020年4月頃に始まりました。最初はメルカリのコア部分のみをSwiftUIで書き換え、アーキテクチャや全体の構成などを固める作業からスタートしました。 その後2021年10月に全ての準備が完了して、本格的にリライトのプロジェクトが開始されました。この段階は、メルカリ側の機能群の開発を凍結し、全ての開発メンバーはメルカリのリライトに注力する期間でした。この期間が2022年8月まで続くことになります。 一方メルペイについては裏で重要なプロジェクトが動いていたので、機能群自体は変更せず、メルカリ側とメルペイ側のコードを Integrationするため、 IntegrationLayerと呼ばれる中間Layerのみを書き換えることで、メルペイの機能群のコードを変更せずに新しいアプリと古いアプリ両方で同じメルペイのコードが動作するように対応する必要がありました。 そこで IntegrationLayerの開発にメルペイチームが参加しました。このGroundUP Appのプロジェクトが始まった同時期に、社内では重要なプロジェクトがいくつか進みました。 メルペイのトップ画面をリニューアルするプロジェクトや、メルカードというメルカリのクレジットカードを開発するプロジェクト、メルコインというビットコイン関係のプロジェクトなど、いろいろなプロジェクトが走っている中で行われたのがGU Appです。 このメルカリと Integrationの実装が完了し、2022年8月に、Phase1としてGroundUP Appがリリースされました。この時点で、メルカリ側は全てSwiftUIにリライトされ、メルペイ側は今まで通りUIKitで動いています。 その後、2022年10月にメルペイ側でSwift UIで書き換えられたものがリリースされ、残りのメルペイの機能やメルカードの機能はまだUIKitで作られていました。2022年11月にメルカードの機能、翌年にメルコインの機能がリリースされました。 フェース3は進行中ですが、今残っている古いUIKitで作られてる部分を最終的には全部書き換え、最終的には100%Swift UIのアプリにする動きが続いています。 それぞれのPhaseについて説明します。まずはPhase1のMerpay SDK GU App Integrationです。 Merpay自体はSDKという形で開発されていて、比較的メルカリと疎結合の状態で設計されていました。 これにはいろいろな背景がありますが、一つは、メルカリの機能はメルカリが担当し、メルペイの支払いや決済に関する機能はメルペイで開発を担当していて、会社自体がわかれていたのでリポジトリを分けて、設計も極力結合なものにした方がよいという考えで、このような構造になっています。 メルカリアプリとは別にメルペイアプリ単体のアプリを作る話もあがっていたので、かなり疎結合でポータビリティを持った設計になっていました。 参考記事: メルペイのスケーラビリティを支えるマルチモジュール開発 GU App Integrationは4つのステップにわかれています。 一つ目は、準備段階としてメルペイ関連機能のSDKへ集約することです。 Merpay SDKの中にはメルペイの必要な機能が入っていますが、いくつかの機能はメルカリ側に直接実装されているコードもあります。そこで、メルペイが管理すべきコードは一旦全部Merpay SDKに集約することにしました。例えば、本人確認機能や売上金の振り込み申請機能などはSDKに移しました。 これらはUIKit + ReactiveCocoaやObjective-Cで書かれていましたが、一旦メルペイのアーキテクチャに合わせてUIKit + MVVMに書き換えました。 これで全てのコードがMerpay SDKに入ったので、次はビルドの環境を設定変更します。旧メルカリアプリはCocoaPods/Carthage/git-submoduleを使ってビルドを行っていましたが、新しいメルカリアプリであるGU Appでは、全てBazelを使ってビルドを行うように変更されました。 したがって、Merpay SDKを含む全ての社内外のコードをBazelでビルドできるように設定する必要がありました。 merpay-ios-sdkやDesign System、Google Maps SDK、Lottie-iOS、CryptSwiftなど社内外のコードをBazelで全てインポートし、一つのメルカリアプリとしてまとめてビルドできるようにする設定変更が行われました。 次はコーディングの段階です。メルペイにはMerpayDependencyRegistryというDIコンテナのようなものがあります。これを用いることにより、メルカリ側で実装されている機能をメルペイ側に注入できます。 全ての依存関係がここに集約されているので、メルカリ側の実装をメルペイに注入する作業をひたすら行います。実際に注入したコードとしては、Feature Flagやイベントログなど、図にある通りです。 これでメルペイのコードは全てMercari GU Appの上でビルドできるようになったので、最後に画面遷移の実装を行います。 GU Appでは、基本的に全ての画面はSwift UIで作られていますが、画面遷移周りはすべてUIKitで実装されています。Wireframe Layerというものがあり、そこでSwiftUIの画面は一旦UIHostingControllerでUIKitのViewControllerとして変換され、それをUINavigationControllerが画面遷移を制御します。 メルペイの画面はすべてUIViewControllerで作られているので、DependencyRegistryを経由して、UIViewControllerをWireframeにそのまま渡します。あとはWireframe内部で細かい画面遷移の実装を行います。 以上で統合完了です。この段階で1年ぐらいかけて行われてきたGU Appのアプリがリリースされました。メルカリアプリは全てSwiftUIで書き換えられていますが、メルペイの機能が集約されている「支払い」タブに関してはまだUIKitのままの状態です。 しかし、更なる最適化の作業が残っています。 まずはGitリポジトリ統合です。GU Appが始まる前は、mercari-iosリポジトリでメルカリのコードが管理され、merpay-ios-sdk、mercari-jp-ios-coreは別リポジトリとして管理されていました。 GU Appでは、メルカリ側のコードはmercari-groundup-iosという新たなリポジトリで管理されています。メルコインのコードもすべて同じリポジトリに実装されています。しかし、メルペイの機能やメルカリのいくつか残りの機能、たとえばメルカリのToday Extensionの機能やメルペイでしか使用していないDesign Systemのコードは、依然として別のリポジトリで管理されており、Bazelによって都度インポートされる構成になっています。 しかし、この構成には開発効率の観点から二つの問題があります。 一つはリポジトリが分かれているのでメルペイの機能の開発を直接行えないという問題です。メルペイの機能を開発する際は、まずMerpay SDKのリポジトリをチェックアウトして、ソースコードを編集・プッシュして、GU Appに戻って、Bazelでリポジトリをインポートし直してビルド・動作確認、という非常に煩雑なデバッグプロセスが必要です。 また、GU Appのビルドインフラを活用できないという問題もありました。GU Appとメルペイのモジュールはそれぞれ別のビルドインフラ上でCIが実行されます。GU AppはBazelでビルドが行われているのでユニットテストも非常に高速にできます。一方、メルペイモジュール単体のビルドにはBazelは使用していないので、その恩恵を受けることができません。 Gitレポリポジトリ結合では、すべてのコードを単一のGU Appのリポジトリに移動することによって、上記の問題を解決します。 なおDesign System1.5はメルペイでしか使われてない古いUIライブラリなので、これは例外としてこのまま別リポジトリとして、コードフリーズした状態でインポートすることにします。 リポジトリ統合にはいくつか方法がありますが、一番単純なのは、ファイルコピーです。一番簡単ですが、Gitの履歴が消えるという問題がありました。 なるべく履歴を壊さずにソースコードをGU Appのリポジトリに移動する手段として、Subtree Mergingというリポジトリの結合方法があります。これによって履歴は保持されますが、リポジトリ全体をマージしてしまうので、この2〜3年間で蓄積された不要なデータまでマージされてしまいます。リポジトリのサイズが増えることで、CIの時間に影響を与えてしまう問題があります。 そこで、もう一つの解決策としてgit-subtreeコマンドを使って、リポジトリを部分的に結合する方法をとりました。必要最小限のコードのみをピックアップして結合し、かつ履歴を保持することが可能になります。必要なコードをピックアップする必要があるので少々作業が煩雑になってしまいますが、これによってリポジトリの肥大化を抑えつつレポジトリ統合を行うことができます。 参照 Subtree Merging: https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_subtree_merge git-subtree: https://git.kernel.org/pub/scm/git/git.git/plain/contrib/subtree/git-subtree.txt リポジトリに全てのファイルを移動できた後は、Bazelビルドに合わせた最適化を行います。ソースコードのレイアウトの変更や、画像アセットを最適にして無駄なデータを含めないようにすること、Bazelのビルドとビルドターゲットとするために、それぞれのモジュールをBazelのモジュールとして定義する作業などが行われました。 また移行期間中に古いコードに変更が入るとコンフリクトが発生するので、コードフリーズ宣言を行ってコードの変更を禁止することで、コンフリクトを防ぎました。 間違いで変更してしまうこともあり得るので、変更を検知するためのモニタリングの仕組みなども入れ、リポジトリ統合を進めました。 このようにおよそ2ヶ月半ぐらいかけて、26モジュールを段階的に移行し、Gitレポジトリ統合が完了しました。 もう一つの問題は、いくつかのメルカリの機能のモジュールがMerpay SDKに直接依存している点です。これによって、テストバンドルのキャッシュが肥大化してしまい、最終的にCIの実行時間やキャッシュストレージの使用量が増加してしまうことがわかりました。 この問題を解決するために、Merpay SDKのDIコンテナのインターフェースのみを抽出し、別のモジュールとして分離する設計の変更を行いました。 これはモジュールの相関関係を表す図です。「MK Feature modules」がメルカリの各機能を実装したモジュールです。いくつかのメルカリの機能はメルペイの機能に依存しているので、それらはMerpay SDKの中の「MerpayCoreKit」モジュールに依存する必要があります。 ただ、MerpayCoreKit自体はさらに、Protocol Buffersのモジュールや、Design System1.5のモジュールなどの、メルカリの機能にとっては不要なモジュールにも依存しています。それらのモジュールはサイズが大きいので、メルカリの機能モジュールをビルドしてテストしようとすると、依存関係にある全てのモジュールがビルドされ、Bazelのキャッシュとして残り続けて、最終的にCIインフラのストレージの使用量の増加を引き起こしてしまう問題がありました。 そこで設計を変更して、MerpayCoreKitが提供していたコードのインターフェース部分だけをプロトコルとして切り出し、「MerpaySDKInterface」という別のモジュールとして切り出し、メルカリの機能モジュールは軽量なインターフェースモジュールのみに依存する形式に変更しました。 これによってモジュールごとのテストバンドルのキャッシュサイズが300MBから150MBまで削減され、ストレージの使用量の問題も解決されました。 またMerpay SDKの最小限の機能のみをメルカリ側に整理・公開する設計にしたので、SDKの債務の明確化が行われ、SOLID原則に従ったSDKの設計にも貢献できたという副産物もありました。 参照: Single Responsibility Principle in SOLID 以上で、Integrationのプロジェクト自体は完了しました。GU Appリリース後、Phase2として、次はメルペイの新規開発画面をShiftUI+GUアーキテクチャで開発するプロジェクトが始まりました。 ここで、メルカリアプリ自体のアーキテクチャの変遷について振り返っていきたいと思います。 旧メルカリアプリでは、10年の間に様々な内部的なアーキテクチャの変遷がありました。最初は純粋なMVC、そこからMVVM+ReactiveCocoa、さらにMicro View Controller + Stateアーキテクチャに変遷しました。しかも全てが変遷していたわけではなく、部分的には古いMVCが残っている状況でした。 一方メルペイは独自のシンプルなMVVM Without 3rd party libsというシンプルなアーキテクチャを採用していました。このように、GU Appの前はいろいろなアーキテクチャが一つのアプリの中に共存している状態でした。 参考資料 Mercari iOSにおける きらやばArchitectureとAutomation Mercari iOSクライアント Re-Architectureのその後 / After Re-Architecture of Mercari iOS client Introducing ViewModel Inputs/Outputs: a modern approach to MVVM architecture GU Appでは、それが一新され共通アーキテクチャが策定されました。SwiftUIをベースとし、Reduxや TCA などからインスパイアされた単方向データフローの独自のアーキテクチャです。 メルカリおよびメルコインの機能は全てこのGUアーキテクチャに基づいて開発されています。メルペイもこの共通アーキテクチャに統合する方針を決定しました。 ちょうどメルペイのトップ画面のリニューアルする新規開発プロジェクトが別で計画されていたので、そこでGUアーキテクチャを試験的に先行導入することにしました。 Phase2の開発が完了しました。この段階でメルペイのトップ画面に関しては100%SwiftUIが達成できました。 メルペイのトップ画面以外の既存画面に関しては、未だにUIKitのままです。Phase3では、既存画面をすべてSwiftUIに書き換えます。これは現在進行中です。 ここで、なぜ最初に技術的負債が比較的少ないメルペイのコードを書き直す決断をしたのか、そのモチベーションについてお話します。 技術的負債負債が比較的少ないといえども、初期のコードは2018年に作られたものです。当然UIKitベースのコードなので、GUで刷新された基盤機能の恩恵は受けられせん。 SwiftUI自体ははもちろん導入できなくはないのですが、メルカリの機能で使用されているDesign System3.0を使用するには、GUアーキテクチャへの移行も必要になります。 アクセシビリティについてもGUアーキテクチャはかなり手厚くサポートされていて、新規イベントログ基盤もGUアーキテクチャにより最適化されたものになっていたなどの事情がありました。これらの事情によって、メルペイ側の既存コードも段階的にGUアーキテクチャに移植するのが良いという決断になりました。 とはいえ、メルペイの既存機能がかなりの数があるので、まず現状の仕様整理から始めました。まず、移植作業の計画を立てます。大量のメルペイの既存画面の仕様を整理・リストアップし、優先度を決めて移植作業を少しずつ始める計画を立てようと考えました。 大量の既存コード・仕様書はありましたが、ここで既存コードと仕様書の対応関係が不明瞭であったり、対応する仕様書が見つからなかったりといった問題が発生しました。仕様書によっては同じ画面に対して別の呼び方がされていることもあり、特に非日本語話者にとってはその理解が非常に困難な状況でした。 そこで既存の仕様を整理する前に、一旦全てのメルペイの画面を一意に特定する「Merpay Screen ID」を導入することにしました。 例えばここにあるように、”MP-BNK-001” はメルペイの銀行接続の1番目の画面を示します。このような採番作業を全ての画面に対して実施しました。 Screen IDをソースコード、仕様書、Figma上で横断的に記載することで、それぞれの関係を明確化しました。これによって、認識の齟齬を解消できる上、非日本語話者でも理解しやすくなりました。これは社内の開発ガイドラインにも組み込まれているので、この辺の整理が今後も進んでいくと思います。 これを導入したことによって、スクリーンに関して仕様書を探したいときにScreen IDで検索すればそれに関連する仕様書が全て出てきます。 またFigmaでUIレイアウトを確認したいときも、Figmaの検索ボックスにScreen IDを入れれば、正式なレイアウトを確認できます。 ソースコード中にこのようにScreen IDを埋め込んでおけば、ソースコードと仕様書の関係、その画面に関する実装についても発見できます。 このように、事前の準備をした上で計画を立て、現在絶賛移植作業中です。全体の77%は古いコードのままなので、今後数年かけて移植する予定です。 こちらが現在移植中の銀行接続画面の例です。 GU App Integrationの開発プロジェクトを進めることで、メルペイ自体の機能開発を止めることなく、GU AppのIntegrationが完了しました。メルペイのコードを変更することなくそのまま新しいGU Appのコードベースに移植することに成功しました。 またBazelのメリットを最大限に生かす構成に変更しました。さらにメルペイの既存画面をShiftUIで移行するにあたり、いろいろと基盤を整備しました。 以上です。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるEngineeringを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 Enabling ProgramのEngineering Headをちょっとやってみている 」の書き起こしです。 @kazegusuri:それでは「Enabling ProgramのEngineering Headをちょっとやってみている」というタイトルで@kazegusuriが発表します。 まずは自己紹介です。@kazegusuriという名前で、社内でも社外でも活動しています。メルカリに入社したのは約8年前で、当時はSREとして入社しました。そこから1年ほど経って、旧ソウゾウと呼ばれている会社に移動して、ID & Payment Platformチームに所属しました。 これは、現在のメルペイの基礎になったIDと、決済の仕組みを作っていたチームです。さらにまた1年経って2018年にメルペイができると同時にチームごと異動して、それを機にアーキテクトとして仕事をすることになりました。 現在もアーキテクトの仕事自体は続けていますが、今年の4月からEnabling ProgramのEngineering Headを兼務することになりました。今回はEngineering Headの仕事について紹介します。 今日話すことは三つあります。まずはProgram体制の話と、所属しているEnabling Programの説明をした後に、Engineering Headについて説明をし、自分がEnabling ProgramのEngineering Headとして何をしているかを説明します。 Program体制とは、メルペイでの開発組織の体制のことです。2023年1月からスタートしました。 Program体制は、役割に応じて大きく三つのグループにわかれます。一つ目がJourney、二つ目がFoundation、もう一つがEnablingです。 Journeyはその中に三つのプログラムが存在していて、Foundationは二つのプログラムが存在します。自分が所属しているEnabling Programは一つです。 続いて、それぞれの役割について説明します。Journeyはお客さま体験を改善するいわゆるプロダクト開発を行い、お客さまの機能を提供する組織として活動しています。 Foundationの役割は、Journeyがプロダクト開発をするにあたって共通基盤を提供する組織です。Enabling Programは、Journey、Foundationの開発を支援する組織です。 Program体制はメルペイにおける組織であって、つまりメルカリ・メルコインにおいては開発体制が異なります。 グループ全体のプロジェクト開発に対して、インフラを提供しているのが、Microservices Platformです。 次に、Engineering Headの役割について説明します。各プログラムには、Engineering HeadとProduct Headがいます。 ただし、Enabling Programには現状Product Headがいないので、Engineering Headが、Product Headの役割も兼ねている状態です。彼らはいわゆる会社で言うとCTOとCPOのようなものです。技術的な意思決定をする人やプロダクトに対する意思決定をする人というイメージです。 Enabling Program・Product Headには、People Management的な役割がないので、組織には彼らとは別にManagerを置いています。 Enabling Programに所属しているチームは、この七つです。 Backend Architectは、バックエンドの開発を支援したり、アーキテクチャを考えたりするチーム。Client Architectには、モバイルやフロントエンドに携わる人が在籍し、各プログラムのクライアント開発を支援します。Engineering Productivityは、バックエンドの開発の生産性を上げるためのチームです。 SREは、会社全体の信頼性を向上させるために、いろいろな仕組みを考えています。Data PlatformとData Managementは、会社のマイクロサービスにおける各種データやプロダクトで得られたデータを収集して、それらをプロダクト開発に生かせるようにする目的で活動しています。QA Optimizationは、各チームのQAをより良い最適化を行うために活動しています。 Enabling Programを構成するチームは、多岐にわたります。では、Enabling ProgramのEngineering Headは、何を期待されているのでしょうか。 例えば、トップダウンで、Engineering Headとして今後の戦略を考えて、各チームにその戦略を遂行するように適用していく。もしくは、各チームがボトムアップでやりたいことを考えて、それに対して意思決定をすることが考えられます。 ただし、現状自分がまだEngineering Headになってから3ヶ月であることや、Enabling Programに所属しているチームの技術エリアがすごく広いので、戦略を立てたり、意思決定をすることは、正しい精度ですることが難しいと思います。 さらに、このProgram体制ができる前から、これらのチームは存在していました。当時から各チームは自分たちが何をすべきかを考え、自分たちの責任で遂行していくことがすでにできていた自立したチームでした。今回Program体制になったからといって、短期的にいきなりその方向性を変える必要はないと、個人的には思います。 では、自分がなぜ今回Engineering Headになりたいだろうと思ったのか、目的を説明します。 Engineering課題を解決するときのプロセスをこの会社として決めたいという理由がありました。メルペイでArchitectチームとして5年以上活動した中で、いろいろなEngineering課題があって、解決するためのいろいろなプロセスをとりました。 プロセスはタイミングや課題の内容に応じて変わります。 例えば今回の課題を解決するために、いろいろな開発チームに対策・対応をお願いしないといけないとき、どうやって対応を依頼をするのか。会社全体が大きくなった今、どうやって対応するのかを考えることは難しいです。 また、Engineering課題が決まったとしても、プロダクトとの優先度をどうやって決めるのか、そのプロセスが決まっていた方がやりやすいと感じていました。 これは、Enablingチーム全員の共通の課題です。そこで、この辺りをまずは解決したいなと思いました。 さらに、裏目標として「テックカンパニーを目指したい」ということがあります。 会社としては元々「グローバルテックカンパニーを目指しています」と公言していますが、個人的にもテックカンパニーをずっと目指しています。 Enabling Programで作っている技術はよくできていて、社内でもまだ知らない人にもっとアプローチしていきたいですし、社外にももっと自慢した方がいいと思います。 現在ある仕組み・技術をもっと発展させるために、技術に対する投資をする必要があります。そのようなサイクルを回すためにはまずは、Enablingチームに所属しているチームが、どれだけ会社にとって有用性があるのかを伝えていく必要があると思います。 個人ではなく、Enabling全体として伝えていきたいなと思って、Engineering Headをやりたいと思いました。 次に、実際にEngineering Headになってやっていることを三つ説明します。 一つ目は、課題の可視化。二つ目が、会社としての課題に設定する。三つ目が成果報告。それぞれ説明していきます。 まず一つ目の「課題の可視化」についてです。プロジェクトロードマップを作っています。この目的は、Enablingプログラムのやっていることや成果を他のチームの人たちが理解できる状態にするためです。 「プロジェクトロードマップ」という名前通り、プロジェクト単位でそのプロジェクトのロードマップを作成しています。JIRAを使って可視化していこうと思っているのですが、まだやりきれていないところです。 プロジェクトとは、中長期的な施策のことを言います。メルカリでは、全体的にOKRという考え方を、短期的な目標設定と成果を計測するために使っています。 今のOKRの使い方は、短期的な目標には使いやすい一方、中長期目標には使い勝手が悪い状態です。そのため、代わりにプロジェクトという考え方を用いています。 この考え方はメルカリ・メルペイ全体で使われており、同じプロジェクトという考え方をEnabling Programでも使っていこうと思います。 次に、プロジェクトの種類です。これは、Enabling Programの中でのプロジェクトの種類を指しており、通常プロジェクトと重要プロジェクトの大きく二つに分けて考えています。 通常プロジェクトの定義は、達成することで他のチームにインパクトがあること。これを達成すると、影響がある人たち、つまりプロダクトを開発している全ての人たちに対して、行っていることやその影響を知ってもらいたいという目的があります。 重要プロジェクトの定義は、達成することで会社レベルの目標にインパクトが出るものです。カンパニーのOKRや重要な目的に対して影響があるということです。周知したい人は、VPや他のProduct/Engineering Headです。 二つ目「会社としての課題に設定する」については、Merpay Engineering Projectsを実施しています。 これはメルペイでの重要なEngineering課題です。元々メルペイでは、この会社レベルで、重要な指標としてEngineering OKRがありました。しかし、やはりOKRであると短期的な目標になってしまいがちです。一方、重要なEngineering課題は中長期的なものが多く、会社としてもプロジェクトという形をとっています。 Merpay Engineering Projectsという会社レベルのプロジェクトは、Enablingの重要プロジェクトから取り入れてもらっています。Enablingの重要プロジェクトをEngineeringプロジェクトとして採用してもらうことによって、担当のVPがアサインされて、サポートが得られます。 大きな意思決定が必要な場合や、他のプログラムの優先順位の変更が必要な場合、VPレベルで説明してもらうことが可能です。 Engineering Projectsは、2週間に1回、各プロジェクトの進捗や課題を報告して、ブロッカーを洗い出しています。場合によっては、VPなどに対して対応を求めやすい状態です。 三つ目「成果報告」についてですが、成果発表会を行っています。これは、Enabling各チームの代表者が発表してもらっていて、3ヶ月に1回、成果を発表してもらっています。 今までは各チームでOKRを設定していていましたが、OKRの成果を他のチームに知らせる機会がほとんどありませんでした。 それを改善するために、成果発表会という形でEnablingチームがやっていることを発表したいと思いました。発表会には、エンジニアだけじゃなくてPMなど、開発に関わる広い範囲の人を招待しています。 実際に前クォーターの成果発表会を開いたときは、100名もの方に参加いただきました。Enabling Programが何をしているのか、みなさんが興味を持ってくださったおかげです。 これまで自分がEnablingのEngineering Headになって、プロセスを改善するためにいろいろなことをしてきました。でも、まだ改善することが多いです。 例えば、Engineering課題が会社レベルで設置されたとしても、プロダクトの優先順位をどうするのかという問題や、出した成果をもっと投資してでも伸ばしていくべきなのか、それともすでに成果が出ているからStayでいいのかという説明をしなければなりません。 今後としては、引き続きこれらの改善をしていくと同時に、すでに行ってきたことを継続していくことも重要だと考えています。 発表は以上です。ご清聴、ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、Productやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 Merpay Engineering Career Talk 」の書き起こしです。 @keigow:今回のセッションは、「Merpay Engineering Career Talk」というタイトルでディスカッションを進めていきます。 @keigow:メルペイVP of Engineeringの@keigowと申します。私は、2016年にメルカリグループに入った後に、2018年のメルペイ立ち上げのタイミングから3年、メルペイに所属してました。2年ほどグループ会社のソウゾウという会社で新規事業の立ち上げに取り組んでいたんですけれども、この4月にメルペイに戻りました。 @osamingo:皆さんこんにちは、@osamingoです。@keigowさんと同じく、2016年8月にメルカリの子会社のソウゾウに入社しました。そのときのメンターは@keigowさんで、個人的には感慨深いです。 元々はバックエンドエンジニアとして入社し、プロジェクト開発に従事しました。2018年頃にメルペイへ異動し、バックエンドエンジニアをしていたのですが、約1年半後にエンジニアリングマネージャー(以下、EM)になりました。最初は、コード決済や加盟店管理/審査、加盟店精算周りに携わっていたのですが、現在は、Fintech ArchitectやEngineering Productivityという社内のデベロッパー向けのサービス開発のEMをやっています。本日はよろしくお願いします。 @fivestar:@fivestarです。本名はKatsuhiro Ogawaと申します。メルカリには2018年1月に入社し、6年目になります。最初はコーポレートエンジニアリングという、社内の評価システムや社内向けのプロダクトを開発する部門の立ち上げにジョインして、そこから1年半ぐらいメルカリ側で開発をしていまして、そのときはバックエンドアーキテクトということで、バックエンド寄りの部分も担当していました。 そこから2019年にメルペイに転籍し、ずっと与信部門に所属しています。そこでメルペイのあと払いやメルペイスマートマネーといった与信系サービスの開発を行っています。 エンジニアではありますが、組織上Engineering Headという役割を賜っていまして、チームのエンジニアリングに関する意思決定の取りまとめもしています。過去にはマネージャーや、スタートアップのCTOをしていた時期もあり、エンジニアとしてのキャリアをまた再構築している状況なので、少しでも参考になればいいなと思っております。 @keigow:では、早速ディスカッションの方に入っていきます。 @fivestar:@keigowさんがVPになったのはいつでしたっけ? @keigow:正式には今年の7月ですが、メルペイに戻ってきたのが4月なので、そこから徐々に似たような役割をしていました。 @fivestar:僕がメルペイに入って1年経たないくらいから一時期、@keigowさんにマネジメントしてもらったことがありましたが、メルペイに戻ってきたと思ったらいきなりVPになったじゃないですか。きっかけが気になりますね。 @keigow:もともとソウゾウでHead of Engineeringという形でエンジニアリング組織を見ていました。ちょうど今年の4月のタイミングでメルカリShopsの事業がメルカリ本体と事業統合し、組織が変わるタイミングで、これからどうしようか迷っていました。 その中でメルペイに戻ってきてVPの役割を担当しないかという打診がありました。メルペイ自体はすごい大きな組織で難しさもよくわかっていたので悩みましたが、こういう機会はなかなかないと思っていて、チャレンジしないのはもったいないという気持ちが最終的には勝ちました。 @fivestar:元々VPはキャリアの選択肢として考えていましたか? @keigow:元々ポジションにこだわりはありませんでした。自分のスキルが一番会社に貢献できる場所ってどこなんだろうと、ずっと考えていました。一番好きなのはプロダクト開発だったので、VPやCTOになりたいとは考えていませんでした。 でも、最初マネージャーをやったときは、マネージャーでいっぱいいっぱいでしたし、人が増えていく中で、中間管理の人が必要だと思ったタイミングで挑戦しようかなと思いました。 ただ、VPになりたいという気持ちもそこまでなくて、常に当時の上長には「たまに現場に戻りたいって思うんですよね」という話はずっとしていました。でも行動していく中で少しずつ考え方がアップデートされていきました。その結果としてVPにチャレンジをしたいと思うようになりました。。 @fivestar:どのタイミングで、マネジメントの方向に行こうと決心したのですか? @keigow:これというタイミングはなかったです。最初はプレイングマネージャーだったので、コードも書きつつマネジメントしていました。また、プロダクトマネージャーの時期も挟んだことでコードから離れてしまい、それが続いて今に至ります。そのときの状況に応じて最適だと思う選択肢を選んできました。 次に、@osamingoさんからの質問です。 @osamingo:@fivestarさんは、Credit Designという与信やあと払いを管理しているチームに異動されてからも、こだわりをもって業務をされていると思います。組織が大きくなり、サービスがリリースされていくという変化が激しい中でも、永く所属されています。この中で、エンジニアリングの責任の深さや広さはどう変化し、またどう対応してきましたか。 @fivestar:もともと前のチームでバックエンドのアーキテクトという立場で、複数のサービスを組み合わせて全体のアーキテクチャを見ていましたし、自分の一番関心のある領域は、ドメインモデルやアーキテクチャでした。そのような設計を取りまとめるという役割を考えて、ずっとキャリアを歩んできています。 だから、僕が来たときと比べると、与信サービス事業はめちゃくちゃ拡大しているのですが、キャリア的な考えで言うと、もともとメルペイにきたときからある程度広く見ていけるようにという意識はもっています。その中で、僕は20代の頃はコードを書きたいと思っていたのですが、年齢を重ねるごとに、設計をきちんとして良いプロダクトを生み出し、課題解決をやっていきたいという思いがあります。 Credit Designの与信事業にすごく興味があったので、異動の希望を出して今に至ります。でも、最初はチームの中で信頼されることが大事だと思うので、最初は本当に小さいマイクロサービスの開発チームに入って積み上げていって、大きなマイクロサービスのテックリードをやったり、あとはメルペイ立ち上げからいろいろな課題があってその解決にオーナーシップをもって取り組むことを意識しています。 確かに広さ・深さは実質的に変化していますが、現場の第一線で、際限なくいろいろな課題を解決したいという思いがあったので、マネジメントではなく現場側の役割でやらせてもらっています。 @osamingo:特にメルペイだと、自分が作ったサービスに触れる喜びはかなり強いと思うんですよね。全体を設計することに対するメンタルやモチベーションについてはいかがですか? @fivestar:チームのマネージャーとコミュニケーションをしていく中で、「もっとパフォーマンス発揮の仕方として、周りをうまく活用して」と言われたことで、少しずつ意識の変化が起こりました。 それから、今後LLMによってコードを書かなくていい世の中になるかもしれませんし、コードを書いていればお金がもらえる世界じゃなくなるかもしれません。それよりは、課題の本質に触れる方を自分の仕事にしていった方が、食いっぱぐれるリスクが少ないかなという打算的な部分もありました。 @osamingo:昔からそういう意識はあって、今このタイミングでもともと持っていたものが発揮されたイメージですかね。 @fivestar:与信事業はかなり課題が複雑で、お客さまの体験という点でいろいろな接点があります。 例えばあと払いサービスを使うところから返済して、そのお金を回収しなきゃいけなかったり、単体でひとつの事業としてPLを持つくらい複雑な事業です。法要件も複雑で、割賦販売法や貸金業法などの理解も含めて難しいドメインですが、難しい方が自分としてはチャレンジのしがいがあります。複雑なものを紐解いたときは嬉しいです。 メルペイの面白いところは、強い人が集まっていることです。特に与信チームは強いメンバーが多くて、会社からの期待値が常に高いんです。いろいろなサービスをどんどんアプリとして、事業を引っ張るプロダクト開発チームなので、会社からの期待値も含めてやればやるほど成果が出ます。そこで責任を持てて、しかも現場の中で必要に応じたマネジメントをしながら、組織を引っ張る立場にいられるのは、自分が昔から目指していた形の一つだったのでやりがいを感じます。 @osamingo:リスペクトできるメンバーと働けるのは、明文化できない福利厚生ですよね。 @fivestar:@osahimgoさんはこの会社に入ってからマネージャーになりましたよね。ICに戻りたいという葛藤はありましたか? @osamingo:ありましたよ(笑) 「Go Bold」という会社のバリューがありますから、「自分がBoldに行けるところはどこなんだろう」ということを常に探っているタイミングで、ICに戻るという選択肢を考えたこともあります。でも今のところはマネージャー業が楽しいので続けています。 @fivestar:どういうところが楽しいでしょうか? @osamingo:EMになったきっかけとして、メルカリグループに入社して2年半くらい経ったときに、自分のパフォーマンスを最大化させるときに「自分はこのままでいいんだろうか」とモヤモヤしていた時期が半年ほどありました。 当時、メルペイがリリース準備でいろいろ頑張っているタイミングでした。そのときに会社で開催されていた「Engineering Manager Philosophy Talk」のイベントに参加し、自分の気持ちが明確になりました。そのイベントは、外部の講師を招いてEngineering Managerの哲学や経験について語っていただくというものでした。そこで、タイミングよくEMに登用されました。 もともとコード決済や加盟店審査、加盟店管理などのプロダクトサイドを長く担当していて、例えば、NTTドコモさんとd払いで連携する場面や国の省庁と連携して何かをやる場面に立ち会うことが多々ありました。 それもすごく楽しかったのですが、EMの活動として、プラットフォームサイドにもチャレンジをしたいという気持ちがあって、今はArchitectやEngineering Productivityという裏方寄りのところを担当しています。 今の領域はプロダクトマネージャーの人がいなくて、エンジニアが自発的に動き、かつEMも動きもあるという、動き方やEMへの期待値が違うため、エリアによってかなり求められるマネジメントスキルが違います。そのギャップが楽しいです。 @keigow:今視聴者さんから質問が来ていますが、「キャリアを築いていく中で現場との距離から焦燥感が発生したときの向き合い方を知りたい」とのことです。 やっぱり、EMになって、自分がコードを書かないことで知識が遅れていくんじゃないかと思うこともあるのかと思いますが、どうでしたか。 @osamingo:そういう考えは、ありました。 一線で書いてないと、特にエンジニアの知識量、エッジなテックに対しての対応能力が著しく下がるし、コードを書くスピードは3分の1にまで落ちるという現象が早めに来てしまって。「俺はエンジニアとして死んでしまったんじゃないだろうか」という焦燥感に苛まれることは僕もありました。 そのとき何をやったかというと、1on1でメンバーから教えてもらうということです。マネージャーからメンバーに聞いた方が「こいつはまだテクノロジーに対してちゃんと関心を持ってるんだな」というアピールもできますし、現場から離れて焦燥感はあるのですが、チームで仕事しています。メンバーとのコミュニケーションという中で、僕はそこを埋めてきたところはあります。 @keigow:@fivestarさんにも聞きたいのですが、マネジメントではないですが、Engineering Headという立場で、コードを書く時間が減ってきているという話があったと思うのですが、似たような課題感や焦燥感はありましたか? @fivestar:正直あるのですが、押さえておかなければいけない部分はある程度押さえていると思います。また、与信領域の全てを押さえておくというよりは、ある程度責任の移譲は必要だし、必要な意思決定を自分がしていく一方で頼ることも大切だと思います。 僕の場合、周りにいるのはテックリードなど、同じような役割の人たちなので、役割分担して自分が全部抱えないようにしています。 @keigow:最後、個人的に僕が聞きたかった質問なんですけれど、@fivestarさんは組織にもかなり興味を持っていると思います。実際、マネージャーという職種には興味を持っていますか? @fivestar:1年前ぐらいまでは全然考えていなかったのですが、今のロールはいずれ他のチームメンバーにtake overしていかなきゃいけないと思います。そうなったときに、次に自分に求められるのがマネジメントの可能性もあると思っています。マネージャーは、選択肢として持ってもいいかなと思っています。自分がやりたいと思ったときは、改めて相談させてください(笑) @keigow:まだまだ聞きたいこと・話したいことがたくさんあるかと思うのですが、時間が来てしまったので、本日はこれでおしまいにしたい思っております。 ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 SwiftUIでビットコインの価格チャートを改善・再実装した話 」の書き起こしです。 @andooown:「SwiftUIでビットコインの価格チャートを改善・再実装した話」というタイトルで発表します。 まずは簡単な自己紹介です。株式会社メルコインのクライアントチームで、iOSエンジニアをしている、Yoshikazu Andoと申します。GitHubやSNSでは、@andooownというIDで活動しています。2019年に新卒で株式会社MIXIに入り、ウォレットサービスのiOSアプリの開発を行っていました。 その後、2021年にメルカリグループにジョインして、ビットコイン取引サービスの立ち上げに参加し、引き続きiOSアプリ開発者として、設計やグループ内の連携も含めて担当しています。 では、改めてSwiftUIでビットコインの価格チャートを改善・再実装した話をします。 まずは、メルカリのビットコイン取引機能について説明します。ビットコイン取引は、ありがたいことに、サービス開始から3ヶ月強で口座開設数が50万人を突破しました。引き続き伸ばしていきたいと考えています。 右の画像がサービスのトップ画面です。ビットコイン取引は、メルカリアプリの機能のひとつであり、メルカリアプリにSDKとして実装されています。これによって疎結合にしつつ、グループ共通の基盤機能やコンポーネントを利用して開発されています。 アプリ内の主な動線は、マイページ。口座開設や普段の利用も、マイページからご利用いただけます。ビットコイン取引機能も含めて、メルカリアプリはSwiftUIを基本として開発されています。SwiftUIも含めたアプリ全体のリライトの話は、メルカンに掲載されておりますのでぜひご覧ください。 参考記事: メルカリの事業とエコシステムをいかにサステナブルなものにするか?かつてない大型プロジェクト「GroundUp App」の道程 また、パスワードレスの認証システムであるFIDOを使用しているので、セキュアにビットコイン取引が行えることも特徴です。こちらはメルカリサービスで最初に採用されています。 本題のビットコインの価格チャートについてです。 チャートはサービスのトップ画面にあり、一番お客さまの目に入る画面となります。チャートには、ビットコインの価格の推移を表示しており、バックエンドから配信された価格のデータをもとに点の間を補完して描画しています。また、画面を開いている間は、一定間隔でデータが更新されます。お客さまはチャートの下のボタンから閲覧する期間を変更できます。 チャートはタップでき、それによって実際の価格や時刻が表示されたり、見た目が変わったりします。 タップされている位置より右側のラインの色はグレーになり、グラデーションの塗りつぶしもなくなります。タップ後には、線の太さや補間の方法が変化し、その間はアニメーションによって連続的になっています。 初期の段階では、このチャートの実装にOSSのChartsライブラリを利用していました。おそらく一番有名な danielgindi/Charts ライブラリで、Appleプラットフォームでチャートやグラフを実装したことがある方ならご存知なのではないでしょうか? こちらの画像はGitHubのREADMEから持ってきたものですが、このようなシンプルなチャートであれば、簡単に実装できます。 グラデーションでFillする機能もあり、こちらのサービスのチャートの要件にマッチしています。また、去年のWWDCで発表されたApple公式のSwift ChartsですがこちらはiOS 16から利用可能となっており、サービスの要件にマッチしていないため、今回は採用を見送りました。 OSSのChartsは、UIKitで作られており、メルカリアプリはSwiftUIを基本として開発されています。そのため、今回はUIViewRepresentableでラップした状態でサービスに組み込みました。 また、タップしている間に表示される価格や日時のコンポーネントはSwiftUIで実装しています。ChartViewと併せてVStackに入れ、タップされてる位置などを同期する必要があるので、Stateを引きまわして実装しています。 この実装にはいくつかの課題がありました。 まず感じていたのは、Chartsライブラリの制約によって、無理やり感のある実装設計になっていたことです。例えば、サービスとして実現したインタラクションがありましたが、そのためには、ライブラリ側で用意されているデリケートメソッドだけでは足りず、自前でUIGestureRecognizerを追加していました。 また、タップした位置の左右で色を変えたり、塗りつぶしの有無を変えたりという要件がありましたが、標準の機能ではこれを実現できませんでした。悩んだ上で、二つのChartViewを生成し、それぞれタップした左側用の設定・右側用の設定で描画し、それらをクロップした上で、ZStackで重ねる方法をとっていました。 ChartsのChartViewはかなり高機能で、そのようなViewを二つ生成しているので、無駄が多かったと思います。 この部分は後になってライブラリのRendererなどをオーバーライドして自作することで、一つのChartViewで実装できるようになりましたが、それによってメンテナンスコストが上がり、どちらにしても課題が残る状態となっていました。 次の課題として、データフローが複雑になっていることがありました。 UIViewRepresentableを使った実装ではあるあるだと思いますが、StateはSwiftUI側にあり、initializerでUIViewに渡します。その上で、タップイベント等はUIKit側から発生します。チャートの上にある価格表示部分はSwiftUIであり、座標をUIKit側と同期する必要があるため、SwiftUIのStateにも反映します。 UIKit、ChartViewも高機能であるため少なからずStateは持っており、SwiftUI側にも、もちろんStateがあります。これによって、Stateやライフサイクルの同期がうまくいかないことによるバグも発生していました。 例えば、「指を離しているのに線が残る」というもので、これはChartViewのバグにより想定しているデリケートメソッドが呼ばれず、Stateがずれてしまうということが原因でした。 この話に関連して、Chartsライブラリにも課題を感じていました。実装当時、Chartsライブラリは頻繁にメンテナンスされているとは言えず、バグ修正のPRはあったものの、1年半放置されている状況でした。そのため初期のChartの実装では、ブランチのライブラリを利用していました。 発表に際して、改めて状況を確認すると、最近新しいメジャーバージョンがリリースされていて、今後は多少活発になることが予測されます。 最大の課題は、ここまでの制約によってやりたいことができないということです。初期段階では、デザイナーさんなどがいろいろな表現の案を提案してくれていましたが、制約によって「かなり無理やりなことをしないと無理そう」と断ることが度々ありました。 チャートはサービスのトップ画面にあり、一番最初に目に入る機能のため、ここにはこだわりたい気持ちがありました。しかし、他のタスクや今後のメンテナンスを考えると、断らざるを得ない状況でした。 あるときPMが、「チャートは取引所サービスの顔」と言っていることがありましたが、その通りだと思いますし、もどかしい思いをしていました。アニメーションもこうして断念した表現の一つであり、初期の実装では、アニメーションなしで見た目が切り替わっていました。 「チャートはサービスの顔だが、不完全燃焼」という状態ですが、このままリリースするのは勿体ないということで、チーム内で合意を取って、チャートをフルスクラッチで実装し直すことになりました。 我々のサービスは、暗号資産交換業ということもあって、スペックや仕様については細かく文書化されているものの、チャートの部分については最低限守るべきスペックのみを定め、iOS・Androidのプラットフォームごとにできる表現をとことん突き詰めることも、このときに同意しました。この認識をチームで共有できたことで、この後が進めやすくなったので非常によかったです。 リライトしていくにあたり、まずは設計方針を決めました。チャートのコンポーネントは二層で構成し、汎用的な部分とサービストップのビットコイン価格チャート固有のドメインを含む部分とで分けることにしました。 汎用的な部分については、X方向に位置、Y方向にビットコイン価格を取る、グラフにおいて汎用的に使うであろう数値と座標の変換ロジックや、チャートのサイズの管理などを含みます。 トップ画面のドメイン固有のレイヤーに関しては、この時点では、どの程度サービスで再利用できるかがわからなかったこともあり、非常に多くのものを含んでいます。 価格の点の間を補完するロジック、画面仕様に合わせて、各個のコンポーネントをレイアウトするロジック、実際にチャートのラインや、グラデーションを構成描画する部分も、ドメイン固有のレイヤーに含まれます。 レイアウトの描画に関しても、SwiftUIのView・Shapeで構成する方針を立てました。これとは反対に、公式のSwift ChartsのようにChartContentというprotocolと専用のResult buildersを作ってデータモデルを構成し、それをもとに内部で描画をする方法もあります。 しかし、この場合は、SwiftUIに用意された豊富なレイアウト方法や、既存の資産を使うことができないため、表現の幅を制限しないためにも、View・Shapeを使うことにしました。これらの決定は後ほど活きてくることになります。 この方針をもとに、2週間ほどでPoCを作成しました。 作ったものについて説明します。リライト後、左の赤枠の範囲のViewは、ViewBuilderを使って通常のViewのように右のコードのように記述できるようになりました。 コードは実際のものを簡略化していますが、構成は同じで、汎用的な座標計算などをしてくれるContainer ViewであるLineChartの中に、SwiftUIの LayoutコンポーネントであるVStackなどを使ってチャート構成要素をレイアウトしています。 では、具体的に見ていきます。先ほどのコードで一番外側を囲っていたのがこのLineChartです。 これ自体もSwiftUIのViewであり、initializerでChartの点の配列と実際の表示要素を返すViewBuilderのクロージャを受け取ります。 そして、受け取ったクロージャに対してChartContextというオブジェクトを渡してViewを生成します。 bodyを見るとわかるように、LineChartは渡されたクロージャーから生成できるView以外に表示要素は持ちません。 そしてChartContextは、チャートの作成に必要な情報を持っています。右側のコードのように、実際はLineChartからさまざまなものをinitializerで渡して作成されています。 entriesは引き続きチャートの点のデータの配列。sizeやtransformerについてはこの後説明いたします。LineChartはこのチャートの作成に必要な情報を管理することが責務です。 ChartContextが持つsizeプロパティは、チャート部分の大きさを表しています。 ここでいうチャート部分とは、右の画像の赤の実線の範囲です。先ほどの通り、LineChart自体は赤の点線の範囲になりますが、チャートとして数値に関連した座標系を持つ範囲は実践の範囲ですので、その部分の大きさがsizeとして保持されています。 これは座標や数値の計算、各コンポーネントをレイアウトに利用するため、Contextに保持されています。 そのsizeですが、LineChartの中でどのように取得されているかというと、このようなmarkAsChartContent()というカスタムModifierが利用されています。 ViewのbackgroundにGeometryReaderを挿入して、サイズを取得するSwiftUIではおなじみの実装です。取得したサイズはpreferenceに記録されます。 LineChart側では、左側のように、preferenceを読み取り、privateな@Stateとして保持し、それをContextに渡しています。 実際の場面では、右側のコードで赤く囲まれたところのように、LineChartのViewBuilderの中で、座標系の範囲に相当するViewにModifierがつけられています。赤枠の上のMarkerViewはタップ時に価格や時刻を表示するコンポーネントなので、座標系は持ちません。 Contextの最後はMatrixTransformerオブジェクトです。これは左下のように、チャートの数値データと画面上の座標を相互変換する機能を持っています。これも各コンポーネントをレイアウト・描画するときに必要になります。 MatrixTransformerも右の画像のようにサイズを用いて作成されます。これによって、数値と座標の相互変換ができます。 実際のChartViewでは、これらの情報が詰まったContextを使ってViewを作ります。 このコードはタップ時に表示される縦の点線の例ですが、Contextのtransformerを使ってタップされているデータから、実際の画面上のX座標を取得してレイアウトされています。価格のラインやグラデーションなども同様にContextを利用して作成されています。 もう一つこのコードからわかるのは、タップされているデータであるselectedEntryが、LineChartの外で管理されていることです。LineChartは、数値・座標の管理のみが責務です。現時点では、触って数値を見れるという機能が、今後実装されるチャートでも同じかわからないため、このような設計になっています。 ここまでは、初期の実装にあったものをただSwiftUIでリライトしただけです。発表タイトルの再実装のみが回収されました。 ここから時間を取って改善を始めました。ただ再実装しただけであれば、開発面で運用コストが減ったかもしれませんが、プロダクトとして良くなった点はありません。 今まで制約によってできなかったけど、やりたい表現を実現するために、右のスクリーンショットのようなデモアプリを作成し、手元の端末で触れる形でPMやデザイナーも含めて配布しました。デモアプリではチャートに関連するパラメータをUIから操作できるようになっていて、タップしているときといないときの線の太さ、チャートをなめらかにするための数値処理、点の間の補間方法など、さまざまなものがあります。 アニメーションもこの段階で実装し、アニメーションの長さなども調整できるようになっていました。このデモアプリがあることによって、今までは「もっと線を丸い感じで」「なめらかにしたい」など、言語化しにくかった表現が、具体的なパラメータとして共有できるようになり、改善のPDCAが加速しました。 後半では、「デザイナーさんが気に入ったパラメータ」「PMさんが気に入ったパラメータ」のように、各々が気に入ったものをプリセットとして登録して、呼び出す機能も実装しました。最終的にはチームで画面共有をしながら、お客さまに届ける際のパラメータを決定しました。 デモの実装においては、SwiftUIでリライトしたことで、宣言的UIになったことや、アーキテクチャがSingle Source of Truthになっていることが存分に活きました。大量のパラメータを1ヶ所で管理し、各コンポーネントはパラメータに応じた振る舞いを記述するのみでよくなります。 UIKitなどの命令的なUIでは、パラメータが多い場合、パラメータ自体とパラメータを利用するView、パラメータを設定するためのViewの同期を取って更新するのが難しいと思います。 また、ViewBuilderの恩恵によってViewの構造を変化させるのも容易なため、一つのViewに全てを実装するのではなく、「補間方法に応じたViewを用意する」などもやりやすかったです。 リライトしたことの別の大きな恩恵は、アニメーションが簡単に実装できたことです。シェイプ自身がAnimatable protocolに準拠しており、その仕組みのおかげで実装できました。アニメーションは、UIKitの仕組みの場合は簡単には実装できなかったと思います。 アニメーション自体は初期からアイディアはあったものの、ライブラリの制約によって断念したため、改善フェーズで実装できて本当に良かったです。 アニメーションの実装方法に少しだけ触れておきます。左は、チャート上のラインを構成するコンポーネントで、SwiftUIのシェイプになっています。Animatable protocolでは、animatableDataプロパティを通じて、アニメーションにおいて連続的に変化する値を設定します。 ここでは、通常時は0、チャートをタップしたときに1となるような数値をanimatableDataとしています。これによって、アニメーション発生時はSwiftUIによって、animatableDataが0から1の間で0.1、0.2といったように、連続的に設定された状態でViewが描画され、アニメーションが実現されます。 チャートでは、滑らかなラインから詳細な価格がわかるラインへとアニメーションさせたいので、animatableDataデータの値に合わせて、二つの価格推移データの間を取る値を計算し、補間処理についてもその強度をanimatableDataを基に計算することで、アニメーションを実現しました。 改善を終えてみた感想です。やはりSwiftUIの特徴を生かしてチームでPDCAを回し、実際にプロダクトをより良いものにできたことは非常によかったと感じています。 デモ準備したりと工数はかかってしまうものの、共通の動くものを見ながら議論・意思決定するのはやはり迅速で、かつ同じものを見ているため、認識のずれも少なかったと思います。 これによって、リモートワークの環境でも、言語化しにくいUIの部分を改善できました。そして、ありきたりですが、リライトを通じてSwiftUIの理解はかなり深まったと感じています。 普段の画面開発や趣味の小さな実装では、なかなか深い理解が難しいことも多いですが、製品レベルでチャートのようなチャレンジングな課題に取り組むと、理解が早く深いものになるなと改めて感じました。 一方で、汎用的な設計を目指しましたが、それがどこまで通用するのかは未知数だとも思っています。OSSのChartsにも言えますが、Alamofireのように、通信データに関するものや、UI系でもAuto LayoutのためのSnapKitのようなユーティリティ系とは異なり、それ自身がUIコンポーネントを提供するタイプのものは、汎用するのが難しいなと改めて感じました。表現はサービスによって十人十色であり、ライブラリを使った表現が最適なサービスばかりではないからです。これはライブラリを利用する側にも作る側にも当てはまる話だと思います。 社内レベルのコンポーネントだとしても、年月を経て、最初は小さかったものが次第に高機能になり、逆に要件を満たしづらくなることもよくあることかと思います。 そして最後に製品のクオリティのために早くサービスをリリースしたいであろう立ち上げ時期に時間を取らせてくれた、また一緒に改善に臨んでくれたチームに感謝したいと思います。今回の進め方で都度チームで合意をとっていたのが良かったなと個人的には思っていますが、裏を返せば、合意をしてくれたチームのおかげです。本当にありがとうございました。 今後は、どこかの時点でパフォーマンスチューニングをしたいと考えています。もちろん、リリース時点で実機でカクつかないことを確認していますが、チャートtの補間部分やViewの構造など、最適化の余地はたくさんあると思っています。どこかでProfileを取りながら進めていきたいと考えています。 また、デモや動画など、動くものを使った議論の効率の良さを改めて目の当たりにしたので、これは継続したい思っています。 忙しくなってくると、「進捗がわかるものを出してください」と言われているわけではないので、自発的なスクリーンキャプチャーの共有などはおろそかにしがちです。 それによって実装が全て終わった後で、認識齟齬があって手戻りしてしまうことは、あるあるではないでしょうか?今後は、「今こんな感じです」と共有する気持ちを忘れずにいきたいと思います。 発表は以上になります。メルコインのクライアントチームでは、日々和気あいあいとプロダクトの開発に取り組んでいます。ご興味がありましたらぜひご連絡ください。 Software Engineer, iOS – Mercoin また、今回ご紹介したチャートはOSSで公開をしています。 https://github.com/mercari/swiftui-chart ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 BigQueryのコンピューティングリソース管理の取り組み 」の書き起こしです。 @gouki:「BigQueryのコンピューティングリソース管理の取り組み」にと題して発表します。 株式会社メルペイ ソフトエンジニアのGo Kojimaです。よろしくお願いします。私は2年前にメルペイにジョインし、当初は機械学習システムの基盤開発に携わりました。その後、現在も所属しているデータマネジメントチームに異動し、主に今回発表するBigQueryコンピューティングリソースの最適化を担当しております。 メルカリ・メルペイではデータ管理データ分析の基盤となるデータウェアハウスとして、Google社が提供するBigQueryを利用しております。 本発表ではBigQueryを利用するにあたって必要となるコンピューティングリソース管理の取り組みについてお話しします。内容としてはこちらの通り、初めにBigQueryとその課金モデルについて触れ、管理に当たっての課題をお話した上で、その解決に向けた取り組み内容をご紹介し、最後に今後予定している取り組みについてもご紹介いたします。 BigQueryはGoogleが提供するデータウェアハウスサービスです。サーバーレスアーキテクチャを採用しており、利用者としてもサーバーインスタンスのサイズや台数等を管理する必要のないサービスです。 対象のデータが大量にあったとしても、ほとんどの場合、数秒もしくは数分程度の実行時間で結果を返してくれます。ただし、クエリやデータによっては数時間以上かかるようなケースもあって、この後お話しする課題にも繋がってくるというような問題になります。 参照記事: https://cloud.google.com/bigquery/docs/introduction?hl=ja こちらの表がBigQueryの課金モデルをざっくりと表現したもので、BigQueryは大きくクエリ処理とデータ保存に使われるストレージに対して課金がなされます。ストレージについては保存領域ごとのデータ量で課金される方式となっていますが、本日はこちらの処理側の方を中心にお話ししますので、ストレージ側の詳細は割愛します。 処理側は、オンデマンド型と定額型の二つのモデルにわかれています。オンデマンド型の場合、処理データ量に基づいて課金されるモデルになっています。月単位で1TBまでは無料で使えます。 ただし、オンデマンド型の場合は、一度に利用できるSLOTは2000までという制限があります。SLOTという概念についてはこの後すぐに説明しますが、クエリ処理に使われる仮想CPUの単位をお考えください。この制限があるので、より多くの計算リソースが必要な場合は、定額型を利用することになります。 定額型の場合、特定の期間の間、仮想CPUを利用する権利を予約購入して利用するモデルになっています。 通常月単位や年単位で購入しますが、これらを超えて必要なったときのみ、秒単位で利用仮想CPUを増加させて利用するFlex Slotsという方法もあります。Flex Slotsは通常BigQueryを実行する前後で、Flex Slotsの追加とキャンセルの処理を事前にプログラムとして自動実行するような使い方になります。必要な間だけFlex Slotsによる仮想CPUを追加して使っていくという形になります。 すでにSLOTとはBigQueryがクエリを処理するときの仮想CPUのことであるとご説明しましたが、特に定額型の課金モデルで利用する場合に、運用上非常に重要な要素となります。 一定の期間、一定数のSLOTの利用料金を支払う方式となっていますので、全く使わない場合でも、その分の料金を支払う必要があります。実際にクエリを実行する際にどれほどのSLOTを利用するのかは、利用者側で指定することができず、BigQueryが実行を進めながら判断して余剰SLOTがあれば利用して実行する仕組みになっています。 余剰SLOTが不足しているような場合は、その時点で使える分だけのSLOTを使って実行が継続され、SLOTが十分にある場合と比較して、実行時間が遅くなる形です。 このような仕組みになっているので消費SLOTを利用者側でコントロールすることは完全にはできません。よって、非常に難しいのですが、無駄にならず、かつ、許容できる実行時間でクエリ処理が完了できる程度のSLOT数になるように予約しておく必要があります。 不足した場合に備える手段としてFLEX SLOTや自動スケールの機能もあるのですが、その場合のSLOTの単価は通常のものに比べて高くなっていますので、それも踏まえてSLOT予約量を調整する必要があります。 またFLEX SLOTの場合は、先ほども簡単に触れました通り、通常はプログラムの中で利用する用なので、その中で無駄遣いが発生しないように慎重に準備しておく必要があります。 予約購入したSLOTはそのまま利用できるようにはなってません。SLOTには、Commitment、Reservation、Assignの概念があり、予約購入した状態ですと、Commitmentとして購入したSLOTが存在するしているという状態になります。 SLOTはGoogle CloudのOrganization単位で購入利用できるようになっているのですが、一つ以上のグループにSLOTを振り分けて利用する形式になっております。この振り分けの単位がReservationです。 一つのグループにはOrganizationのプロジェクトを一つ以上割り当てることができ、グループ内の数のプロジェクトで、グループに割り当てられたSLOTを利用することになります。このReservationに対するプロジェクト割り当てのことを、Assignと呼んでいます。 こちらはGoogleのマニュアルにあるSLOTの利用の例の図になっており、Commitment Reservation Assignの関係を示しています。この例では、まず、トータルのCommitmentとしてSLOTとして1000SLOT分保持してる状態で、Reservationのグループとしてds、elt、biの三つを作成して、それぞれSLOTを割り当てています。この例では保持しているSLOT全てを割り当て切った状態になっています。 例えばdsプロジェクトで、実行プロジェクトとしてBigQueryで、クエリを実行します。とdsグループに割り当てられた500SLOTの中からSLOTが割り当てられて実行されます。 なお、この図の中に両方向に矢印が書いてあるマークが意味するところとして、JOB実行の際にReservationに割り当てられているSLOTでは不足しているというような場合に、他のReservationで利用していないSLOTがあれば、それを利用することができることを表現しています。 このとき利用される余剰SLOTのことをアイドルSLOTと呼ぶのですが、このアイドルSLOTの利用を設定上停止することもできます。 ただし設定できるのは、他のReservationのアイドルSLOTを利用しないという設定で、反対方向にある他のReservationにアイドルSLOTを使わせないという設定ができません。 Reservationが二、三個程度の数しかないようなケースであれば、アイドルSLOTを優先的に利用するReservation以外のReservationで、アイドルSLOTを使わないという設定をすればいいわけですが、Reservation数がそれ以上に多い場合は、アイドルSLOTを融通し合うように設定しておいた方が、CommitmentのSLOTを使い切りやすくなります。 ここから我々のBigQuery SLOTの管理について、課題とその解決策をご紹介いたします。 まず我々のBigQuery環境ですが、定額のSLOT Commitmentを予約購入するモデルで利用しております。規模としては、データセット数にすると1500超、JOB数にすると1日あたり30万件超、ユーザー数であれば1日あたり700人超程度です。 BigQueryはSQLクエリさえかければ、大量データに対しても、数分程度の実行時間で結果が返ってくる非常に便利なデータウェアハウスです。利用者も非常に多くてQueryも多数使われており、利用者に対して、特に使い方の制限もしていないので、ほぼコミットしているSLOTの上限まで利用されています。 それにより実行時間が遅くなってしまったり、タイムアウトしてしまうというような問題も発生しております。 この問題に関して、SLOTの追加のCommitmentを購入することで、この問題に対処することもできるのですが、無限にSLOTを購入し続けることもできないのでそれ以外の対策が必要でした。 対策として、三つの柱を立てました。 最終的にSLOT消費削減のために施策を進めていたいきたいのですが、その前の準備段階として状況把握と管理効率化を進めました。SLOTの管理者だけでなく利用者の方々自らSLOTの利用状況や自分の状況を把握し、今どうなっているのか、SLOT量が増えているのか・減っているのかを認識できるように準備を進めました。 目的や優先度が異なるJOBが一つのReservationに混在していると、優先度の高いJOBのためのSLOTを優先度が低い所が食いつぶしてしまって、優先度が高い所のために十分なSLOTと配分できないという状況があります。 これを解消するために、目的や優先度を見定めてReservationを整理する作業も実施しました。順にこの三つについてご紹介いたします。 一つ目のSLOTの状況把握ですが、まずその状況を定義することから始めました。SLOTが枯渇すると、同じクエリでもそうでない場合と比べて実行時間が延びてしまう、いわゆる重い状態になるので、統一的に表現できるように試行錯誤し、データ処理量あたりの実行時間、一定SLOTを消費するのにかかる時間を、SLOT状況を表すメトリクスとして採用しました。 また、タイムアウト発生を避けたいので、その有無もSLOT状況を表すメトリクスとして採用しました。メトリクスについて、過去に緊急的にSLOT Commitmentを追加した前後で、どのようにそれらのメトリクスが変化したのかを分析した上で、Reservationごとにスレッショルドを定めて、そのスレッショルドに収まるメトリクスになることを各Reservationのキャパシティの要件として定めることとしました。 なお、相当の初期状況についてBigQueryの機能としてモニタリング用のWeb UIも提供されているのですが、我々が定義したキャパシティ要件メトリクスのような、より詳細な情報を得たい場合は、Web UIでは不可能なので、そういった場合に備えてBigQueryの機能として、特別なViewが提供されております。ここで紹介したようなメトリクスもそのViewを利用してモニタリングしています。 そのViewは、具体的には、JOB単位でJOBの詳細に関する情報が得られるJOBS_BY_ORGANIZATION view、各JOBの1秒ごとのタイムスライス単位で情報が得られるJOBS_TIMELINE_BY_ORGANIZATION viewが提供されています。これらを活用することで、Web UIでは得られないJOBごとの詳細な情報を得ることもできます。 こちらは、それらのViewの利用例のクエリになります。画面左側の部分でJOBS_BY_ORGANIZATIONからJOB終了時間を秒単位にならしたエラージョブズを取得して、画面右上側の部分でJOBS_TIMELINE_BY_ORGANIZATIONから行間隔でJOB数および平均SLOT消費を取得し、時刻とReservationグループ単位で、その二つをジョインしています。 こちらのクエリを実行しますと、このような結果が得られます。JOB単位の情報とタイムスライスごとの情報を組み合わせることで秒単位でJOBとSLOTの推移を確認できます。 今ご紹介したViewを活用してSLOT管理者および利用者向けにこのようなダッシュボードを作成し、社内公開して随時状況を把握できるようにしております。 また定期的にキャパシティ要件の状態をチェックして、違反の状態を検知したらすぐにSlackで通知する仕組みも用意して、タイムリーに状態を把握して、必要に応じて対策を打てる形にしております。状況把握については以上になります。 次に管理効率化のためのReservation整理について紹介します。課題として、一つのReservationに大きく2種類にわかれるJOBが同居してしまっているという状況がありました一つはAd-hocな分析用、もう一つはシステム開発用途です。 Ad-hocなものは使われ方としては比較的処理時間は短めで、素早く結果を得て活用するというタイプ。システム開発用途とはシステムが必要とするデータを整備するパイプラインを開発するための用途で結果を直接業務に活用するというよりかは本番用の動作検証という側面が大きいものになります。 このような使い方の違いから、Ad-hoc側はSLOT消費が比較的少ないものが大量に頻度で実行されるという傾向があって、システム開発用途ではバッチ処理系のSLOT消費の大きい少量のJOBが実行されるという傾向がありました。 そのため、要件としてもAd-hocでは長時間の実行が控えてSLOT消費を抑えるようにして、その他の通常のJOBに影響が出ないようにししばらくデータが得られるようにしたいという意見があり、システム開発用途では逆に実行が長時間になってしまったとしても安定的にデータ処理部を運用したいという要件があって、共存させたままだと非常に管理しづらいという問題がありました。 対策として元のReservationに所属しているプロジェクトごとにJOBの傾向を見定めた上で、新たにもう一つ別のReservationを作成して、JOB傾向に合わせてプロジェクトを振り分け直すことをしました。 これによってSLOTの配分がしやすくなったことに加えて、Ad-hocについてはReservation内の一定のSLOT消費以上、実行が続いている長時間JOBを強制停止するという仕組みを導入することも可能となりました。 一緒のままだとシステム開発用途のバッチ処理などを停止することになってしまっていましたけれども、Reservationを分離することによってそれも可能となって、優先度の高いJOBが長時間JOBにSLOT消費を奪われずに効率的に実行できるように改善することができました。 Reservationは元々、BigQueryのマニュアル上にも目的や優先度が聞かれたものを集めて構成するのが良いとされており、それによってSLOT管理をより効率的に行えるようになるメリットがあることについてご紹介しました。 最後に、SLOT削減に向けた取り組みについてご紹介いたします。不要なSLOT消費を削減するためには管理者だけではできることが限られており、実際に利用者の方々にご協力いただく必要があります。 そこで、先ほどご紹介した、JOBS_BY_ORGANIZATION、やJOBS_TIMELINE_BY_ORGANIZATIONを活用してSLOT消費が大きいテーブル作成JOBで、そのテーブルへのアクセスは全くないというものを探し出して、JOBの作成者に対してメンション付きでSlackで通知しています。 これらのViewやその他関連するテーブルに対して、クエリ実行し結果をもとに、JOBに対する操作を行うとか、あるいは結果データを使って通知を行うという処理自体は、いろいろな使い道が考えられるため、汎用的に利用できるように、SQLと通知内容をテンプレートで定義すれば、通知処理が行えるフレームワークを独自に開発し、これをBigQueryのJOB間に関連する通知の仕組みとして整備しました。 こちらは現段階では定量的な効果検証までできていないのですが、すでにSLOT消費の大きな情報を作成した方々には、見直しをしていただいていたり、アクセスのないJOBについては適時停止していただいたりしています。 これ以外のその他の取り組みについて、こちらにリストしております。 テーブルを特定のカラムの値をもとに分化するPartition filter requirement機能がBigQueryにはあるのですが、こちらはWHERE句で特定の値に絞り込んで実行することで、実行時間とSLOT消費を抑えられます。その絞り込みを行っていない場合は、クエリの実行自体を許可しないように強制する機能があり、この機能をオンにしています。もちろん実際に適用する際には、既存の定期JOBなどにも影響がありますので、その対策は必要です。 次はBI Engineです。こちらはBigQueryの機能として提供されているEメモリのキャッシュ機能として、実行プロジェクトごとにキャッシュサイズを設定して、キャッシュできます。 データセットを保持しているプロジェクトに対する設定をするのではなくて、実行プロジェクトの設定になります。キャッシュを利用したい対象のテーブル郡に対するクエリを実行するプロジェクトに対してキャッシュを設定する必要があります。 キャッシュ定義としてはメモリサイズの他にキャッシュを優先するテーブルを列挙するというようなことができるようになってます。 続いて、中間テーブルの作成活用となります。複数種類のJOBの間で共通的に実行している部分テーブルを中間テーブルとして定期的に作成しておくことで、こちらの自分の実行を効率化することができます。 メルカリ、メルペイではこうした中間テーブル作成するためのOSSのdbtを使った中間テーブルを作成を運用しております。 次はダッシュボードになります。複数のダッシュボードのソリューションを利用していますが、利用者はこれらを活用することで個別に分析用にSQLクエリを作成することなく、分析作業を行うことができます。SQLを直接利用する場合に比べて効率的なクエリになりやすく即座にビジュアライズすることもでき、SLOT消費の削減にもつながります。 最後に、今後の課題を述べます。BigQueryは最初にご紹介した料金体系から新たな料金体系に変更が予定されており、これまでよりもSLOTの単価が上がります。一方でAuto scaling SLOTと呼ばれる新たな機能で、SLOTが不足した場合のみ利用されるように事前に定義しておくことが可能になってます。 Auto scaling SLOTは単価が通常のSLOTより高めなものを使った分だけ課金されるというモデルになっていて、通常のCommitmentとAuto scaling SLOTが最適なるように設定していくことが重要になります。どのReservationにどれだけのAuto scaling SLOTを設定するのかが重要です。 また、BI Engineについてですが、こちらも設定したキャッシュメモリの量の分だけ課金されます。ただ、クエリ実行時にキャッシュヒットした場合はSLOT消費をしないので、SLOT割当とBI Engine用のメモリ量を最適に設定することが重要となります。こちらも利用しながら最適な設定を見定める予定です。 以上、メルカリ、メルペイにおけるBigQueryのSLOT管理について、課題と対策、今後の取り組みについてご紹介しました。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 拡張性を備えたソフトウェア設計 」の書き起こしです。 @Rupesh:こんにちは。今日は、「拡張性を備えたソフトウェア設計」というトピックで、マーケティング担当者向けのエンゲージメントプラットフォームというシステムのケーススタディを交えて紹介します。 私の名前は@Rupeshです。ソフトウェアプロダクトの開発を専門としており、ITインフラ管理などのドメインでソフトウェアプロダクトを構築した経験があります。2021年にバックエンドエンジニアとして入社しました。それ以降、CRMシステムの開発を担当しました。お客さまへさまざまなキャンペーンを展開しているプラットフォームです。 ではエキサイティングなトピックに行きたいと思います。ソフトウェアの拡張性とは、ソフトウェアを構成可能でスケーラブルにするものです。ソフトウェアの変更や新機能を、大規模なリファクタリングなしに構築可能にします。 ConfigurabilityとScalabilityの拡張性の概念の、密接な関係性を考えてみましょう。 Configurabilityはソフトウェアでアトリビュートの構成をしていきます。Configurabilityを活用することによって、ソフトウェアの寿命を長くすることができます。 Scalabilityに関しては、ソフトウェアの機能でリソースを使いながら、リクエストのボリュームを処理します。ソフトウェアのScalabilityとは、ソフトウェアのExtensibilityともつながります。 参照元: https://en.wikipedia.org/wiki/Extensibility なぜこの拡張性が必要なのでしょうか? ターゲットユーザーは多様です。全てのユーザーをソフトウェアのライフタイムで把握できるわけではありません。数十年に渡るときもあります。ソフトウェアの製品に関しては、開発を開始する時点で全てのユースケースを把握できるわけではありません。 次に、プロダクトをサードパーティと連携していかなければいけません。ソフトウェアの開発や拡張性に対しては重要です。それにあたって、どのような道をたどっていくべきでしょうか。 ソリューションとプロダクト/プラットフォームの違いは、スライドをご覧ください。 ソフトウェアソリューションは、特定の問題のために構築されています。その要件は、開発の初期段階で収集され決まります。 一方、プロダクト/プラットフォームは、長いランタイムに向けて作られ、要件は継続的に整備されます。ソリューションは、要件に合わせたオーダーメイドで問題に非常にタイトにフィットします。しかし、プロダクト/プラットフォームには成長の余地があります。 またソリューションの場合、拡張性は重視されません。与えられた時間やリソースの中で問題を解決することに主眼が置かれます。しかしプロダクトの場合、拡張性は避けて通れません。 ソリューションは、時間とリソースがプロジェクトの決定要因である場合に最適です。しかしプロダクトの場合、プロダクトロードマップのビジョンが明確であれば、プロダクトを出発点として選択するのがベストです。 ソリューションは通常短命です。しかしプロダクト/プラットフォームの場合、時間とともに進化し続けます。これらが、両者の違いです。 では、どのように開発するのでしょうか。 ソフトウェアプロダクトを開発する最も基本のステップがこちらです。 まずは、モジュールの定義です。このスライドでは、特にモジュールという用語を使っていますが、コンポーネントとも言います。まず最初にすることは、モジュールやマイクロサービスを定義することです。 これらのマイクロサービスを定義した上で、何をすべきかの責任を定義します。各モジュール、エンティティを定義し、関係を定義します。 エンティティの中で、ビジネスエンティティのカプセル化をします。そこでエンティティを定義し、関係の提言をします。これはビジネス要件に基づいた形でプロダクトを設計をしていきます。 次がインターフェースの定義です。コンポジットタイプを使います。コンポジットタイプを使う理由は、柔軟性を担保できるからです。要求に応じてインターフェースを変えなくても属性を追加できるからです。 次に、ボリュームの予測です。こちらもプロダクトを考えた場合に複雑になります。サービス間やモジュール間のコミュニケーションにとって、このボリュームの正確な予測は重要となってきます。 これらのソフトウェアプロダクトの理解をもとに、エンゲージメントプラットフォームのケーススタディをしてみましょう。 エンゲージメントプラットフォームは、お客さまとのコミュニケーションを提供し、お客さまの成長と維持につながるソフトウェアで、成長ニーズに応えるために構想された社内プラットフォームです。 ソフトウェアの開発に際しては、非常にシンプルなユースケースから始めています。まず登録したお客さまにクーポンというリワードを与えたいという単純なユースケースから始めました。 ユースケースとしては非常にシンプルなもので実現できましたが、ここでプロダクトとして構築をしたのは当社のPMが「進化し続けるニーズに対応できる単一のプラットフォームとして開発する」というビジョンを持っていたからです。そのため、将来的な拡張にも対応できるようなコード設計になっています。 エンゲージメントプラットフォームがどのように機能するかというランタイムも入れたハイレベルな図です。最初はキャンペーンの提供を始めています。これはマーケティング担当者が実行します。 このキャンペーンモジュールを使います。ここでのお客さまにクーポンというリワードを紐づけたら、お客さまに何らかの方法でお知らせします。 このキャンペーンの構成が終わりましたら、どのようにこのキャンペーンのランタイムがお客さまへのリワードと通知の配信を扱っているのかを見ていきます。 左下が、Mercari Appです。例として、メルカリに新しく登録したお客さまにリワードを与えるようなキャンペーンをマーケティング担当者が構成したとしましょう。 フローはお客さまがアプリに登録したときにトリガーされます。アプリへの登録イベントがセグメントモジュールに通知され、セグメントモジュールの方でこれらのイベントを七つのカテゴリーに分けていきます。 キャンペーンは、セグメントの定義がされています。プラットフォームに登録をしているお客さま全てにリワードを与えなければいけないという定義になっていますので、お客さまが登録されたときに、キャンペーンが走り、その後通知がお客さまに対して送られます。 Distribution Hubがモジュールとして、報酬・通知を担当するモジュールに通知を行います。 報酬とはポイントまたはクーポンでも構いません。通知を送るための三つのモジュールが、報酬の送信と通知のユーザースクリーンへの送信を扱っています。このようにイベントのジャーニーが、アプリへリアルタイムで行われています。 どのようなことをプラットフォームの中で検討・考慮したのかについてです。 これらのモジュールは疎結合になっています。これは大変重要です。これらのモジュールが密に結合していると、一つのモジュールに対する変更が他のモジュールの変更にも影響してしまいます。 もう一つは、エンティティモデリングです。さまざまな可能性のあるシナリオというのを検討・考慮しています。全てのエンティティは、いろいろなユースケースへ将来的に対応できるように考慮しています。 さらにもう一つ、全ての設計の中で、リクエストとレスポンスにおいてコンポジットオブジェクトを公開するように設計をしています。 また、それぞれのサービスのスコープを定義し、境界がしっかりあって重複しないように設計しています。 サービスの変更をする人は、変更の範囲を把握して、新しい要件が出たときには、この要件をサービスに応じて分けて、より早く簡単に開発できるようにしていきます。 次に、サービス間のコミュニケーションの戦略も定義していきます。これらの検討の裏側のアイディアは、新しい要件が出てきたときにできるだけ開発がしやすくなるようにすることです。 次にデータモデルを見ていきます。最初のステップは、ソリューションを構成しているさまざまなエンティティを見ていくことです。エンゲージメントプラットフォームには四つのエンティティがあります。 お客さまとのコミュニケーションとして、新規登録のキャンペーンやお客さまのオンボーディングキャンペーンなどが含まれていて、これらのキャンペーンエンティティは、マーケティング担当者がキャンペーンを定義するときに使います。どのセグメントのお客さまとコミュニケーションをとるのか、どういうリワードや通知を提供するのかが含まれます。 次のエンティティがセグメントです。セグメントとは、お客さまのセグメントの定義です。シンプルなユースケースとしては、メルカリというプラットフォームに出品しているお客さま、それ以外に購入だけしているお客さまなどがあります。もっと複雑なユースケースとしては、24時間以内に5つの商品を出品しているお客さま、あるいは、24時間以内に出品と売却をしているお客さまなどもあります。 こういったセグメントを重要なエンティティとしたインセンティブというエンティティがあります。インセンティブの中には、リワードの考え方が含まれております。ほとんどのキャンペーンは、何かしらのリワードが関わっています。これらのリワードは、ポイントやクーポンです。あるいは将来的に他のリワードが出るかもしれません。 最後が通知です。通知のエンティティには、お客さまに対してコミュニケーションするチャネルが含まれています。リワード関連のコミュニケーションであれば、通知エンティティを通じてお客さまに対して通知が行われます。通知オンリーのキャンペーンは、マーケティング担当者がお客さまとコミュニケーションをしたいときに使われます。 それでは細かいデータモデルを見ていきます。こちらのスライドでは、エンティティの関係性を示しています。 キャンペーンがメインのエンティティで、一対多の関係をセグメントとして持っています。それぞれのキャンペーンは、一つあれば複数のお客さまのセグメントにターゲットを絞ることができます。それぞれのセグメントはどのようなお客さまの行動に対してインセンティブを提供するのか、あるいは通知するのかを提供します。そのため、セグメントごとに複数のインセンティブや通知が関わることもあります。 このスライドで重要なポイントは、インセンティブの通知の間には直接的な関係はないことです。これらはセグメントと独立した形で関連されています。それぞれのキャンペーンは複数のセグメントを持つことができます。 ここで仮説としてお客さまのオンボーディングキャンペーンを例にとってみたいと思います。オンボーディングキャンペーンは、キャンペーンの仕様で、キャンペーンとしてプラットフォーム上でいろいろなアクティビティをするように動機づけようとするものです。 このキャンペーンでは、登録時に1000ポイントを与えます。そして、お客さまが登録するとできるだけ出品してもらいたいと思います。 もう一つのセグメントとして、出品者向けのクーポンと出品の行動を関連付けるものもあります。商品を出品するとクーポンが与えられて、もう一つ、販売することによって購入時に使用できるクーポンが得られます。 これらは、異なる通知の仕組みとも連動しています。リワードを渡していますので、お客さまに対して通知をしていく必要があります。 それでは、キャンペーンがどのようにリアルタイムで動いてるのかをビジュアルで見ていきます。 これはキャンペーンを可視化したもので、キャンペーンのエンティティがあり、それに関連したセグメントが示されています。 今回は簡単にするため、三つのセグメントを示しています。これらのセグメントはシリーズにわかれています。最初のセグメントは、アプリに登録をしているお客さまです。二つ目は、アプリに登録し出品をしているお客さまです。三つ目はアプリに登録して、出品した商品を販売しているお客さまです。 リワードと通知がどのように送られるのか。あるセグメントに入ったときにリワードと通知がどのように送られるのかを見ていきます。最初のセグメントで登録をすると1000ポイントが渡されます。プライベートメッセージあるいはプッシュ通知で通知が行われます。 登録後は、キャンペーンのコミュニケーションとして出品をするとリワードが与えられます。お客さまの次のステップとしては出品をすることになります。出品をするとまたクーポンが与えられます。 出品したものが売れると、さらに購入時に使用できるクーポンを受け取ります。そうすると、プラットフォーム上でのお買い物が起こりえるわけです。これがキャンペーンの一連の流れとなっています。 次に、イベント処理の戦略についてです。これは、拡張性あるいは信頼性などにも役立ちます。 全てのイベントは非同期な形で処理をすることに決めました。これは私たちが判断したことです。UIが関わっておらず、お客さまがアクションを取ったときには、通知チャネルのどれかを使って通知をする必要があるからです。 次に行ったのは、イベントの冪等性を決めることです。つまりリトライやリカバリーをできるようにすることです。イベントが起きたときに、インフラの問題で重複する可能性があります。そのため、イベントをシステムが受け取ったときに、新しいイベントなのかそれとも過去に受け取ったイベントなのかを区別して把握できるようにする必要があるからです。 続いて、ログについてです。イベントのサービスに入って出てくるときにログを取る必要があります。イベントでインシデントが起きたときに、インシデントの境界を明確にし、追跡が可能なように担当しているサービスを明確にする必要があります。 そして、同期のコールをするときはキャンペーンの設定だけです。これは、マーケティング担当者がユーザーインターフェースとやり取りをしている場所だからです。 それがエンハンスメントではどのように役立つのかを見ていきます。 こういった小さな機能の強化が簡単にできます。元々はクーポン配布用に作ったのですが、同じようにポイントも配布できるようになっています。 お客さまがリワードを受けている回数ですとか、お客さまが受け取ってくる最大のポイントをもとに機能強化を簡単にできるようになっています。 それでは、プラットフォーム上で行った主な機能強化についてお話しします。 元々このプラットフォームはリアルタイムの処理に対応することになっていたのですが、バッチでの配布もサポートするようになりました。お客さまが過去に行った行動に対しても、リワードを与えたかったからです。元々この製品はこういったことには対応していませんでしたが、最初の調査後、変更が必要なモジュールはセグメンテーションモジュールだけで、他のモジュールは影響を受けないことがわかりました。そのため、セグメンテーションモジュールでSQLクエリを確認する対応をとっています。 これをやっている中で大きな問題としてあったのが、イベントのバーストです。リアルタイムと比べると、これが実行されたときにイベントがバーストしてしまって、これによってフローコントロールやイベント優先順位などの新しい課題が生まれました。 プラットフォーム上で、大きな変更としてサポートしたのが通知だけの配布です。元々のシステムの設計としては、お客さまにリワードを与えて通知を与えることです。データモデルの中では、意図的にこの通知とリワードの間には関係は持たせませんでした。リワードはセグメントの中のオプションとすることで、簡単に対応できました。 この要件は元々バッチフローで要求されていたものだったのですが、のちのちにリアルタイムのキャンペーンに対しても追加の変更なく扱えるようになりました。 次に、ソフトウェアを本番で実行するとどうなるのかをお話しします。 プラットフォームを本番環境で実行する場合には、こういった項目をチェックする必要があります。 まずは後方互換性を担保することです。一つの変更点が、過去にサポートされていたユースケースを壊すことがあるからです。長期的に実施されているキャンペーンもあれば、後方互換性がない変更をしてしまうと古いキャンペーンが実行できず、Failしてしまいます。 次にしっかりとしたマーケティング担当者向けのドキュメントが必要です。自分自身で簡単にオンボーディングできるドキュメントが必要です。製品は大変幅広いお客さまのセグメントがあり、必ずしも直接やり取りができるわけではありません。マーケティング担当者が使いやすいインターフェースがあり、しっかりとしたドキュメントがあることによってオンボーディングが簡単になります。 セキュリティとお客さまのセグメント間でのデータアクセスの管理も同じ理由で大変重要です。幅広い多様なお客さまのセグメントがあると、それぞれのお客さまごとに実行範囲があるかと思いますので、しっかりとしたアクセスコントロールを持っていることが大変重要です。 最後に、モニタリングと継続性も重要です。一つの不具合が複数のビジネスオファリングに影響する可能性があるからです。こういったプラットフォームも本番で実行するためには、堅牢な信頼のできるモニタリングが必要です。不具合が起きたときにビジネスの継続性をしっかりと担保する必要があります。 皆さんに役立つ、エキサイティングな内容であればと思っております。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 BigQueryのデータ監視の社内サービスを作った話 」の書き起こしです。 @hyrrot:株式会社メルペイ Data Management Team、Data Managerの髙橋です。「BigQueryのデータ監視の社内サービスを作った話」と題し、発表します。 自己紹介をします。髙橋宏文と申します。2022年より、メルペイでData Managerとして、メルカリグループのアナリストの皆さまに最強のデータ分析環境を享受していただくため、日々奮闘しております。 メルカリグループでは、データウェアハウスとしてGoogle BigQueryを利用しています。データウェアハウスに関わる主要なチームとして、二つのチーム「Data Platform Team」「Data Management Team」があります。 Data Platform Teamは、サービスデータベースやログからBigQueryにデータを届けるパイプラインの開発と運用を担当し、Data Management Teamは、データの利用者が安全に安心して簡単にデータを活用できるような仕組みやプロセス構築サポートを行います。 今回はData Management Teamの成果にフォーカスしてお話しします。 Data Management Teamは、データ利用者のデータ活用を促進するため、BigQueryのデータを整え、データ利用者に届ける仕組みを運用しています。 例えば、生テーブルを中間テーブルに変換するために、dbtを用いています。dbtの定期実行のための基盤として、Cloud Buildをはじめとした、GCPのマネージドサービスやArgo Workflowsなどを利用しています。 ある日、社内の複数チームから別々のリクエストをもらいました。どちらのリクエストも具体的な要件は異なりましたが、「BigQuery内のテーブル内のデータが正しくないときに通知が欲しい」というものでした。 一方のチームでは、「BigQueryのテーブル内のデータを用いて、顧客企業に対する経費精算を行っているが、テーブルのデータがクエリの前提条件を満たしていないときに、それを検出したい」、もう一方のチームでは、「BigQueryテーブルのデータを用いて、お客さまに対してポイントの付与オペレーションを行っている。テーブルがポイントの誤付与が発生したことを示すようなデータを含む場合、それを検出したい」という要求がありました。 このような要求に簡単に応えるサービスは、社内にはまだありませんでした。 リクエストをもらった2チームの依頼に応えるため、また、今後他のチームから同様の依頼を受けたときのために、全社で利用できるBigQueryデータの監視システムを作ることにしました。このようなシステムは、「BigQuery内のデータが正しくないときに通知が欲しい」という要求に応えるものとなるでしょう。ここで言うデータの正しさとは、監視対象のデータに依存するものとなります。 ここでは、データのドメイン条件を熟知しているそれぞれのチームに、データが正しいとみなされる場合に0行の結果を返し、正しくないとみなされる場合に、1行以上の任意の結果を返すクエリを作ってもらいます。 監視システムはそのクエリを実行し、1行以上の結果が返ってきた場合、およびクエリの実行に失敗した場合にチームに通知するようにします。このような仕様を持つ監視システムを作り、それにQueryMon(クエリもん)という名前をつけ、社内に展開することにしました。 QueryMonの最初のバージョン1.0を、Argo Workflows上に実装しました。まず、クエリ実行のプロセスを管理するWorkflowTemplateを用意します。このプロセスは、パラメータとしてService Account名、実行するクエリ、通知先となるSlackチャンネル名などを受け取り、指定されたService Accountにimpersonateしてから、クエリを実行します。 その結果が1行以上、あるいはクエリの実行に失敗した場合に、Slackチャンネルにメッセージを送信します。CronWorkflowは、WorkflowTemplateのパラメータの実際の値を持ち、また指定された時間にプロセスを実行する役割があります。 このシステムはシンプルですが、いくつか問題点があります。 まずは、何らかの原因で監視が行われるべきタイミングで、実際行われなかったという場合に、それを知ることができない点です。データに問題があった場合、チームが問題を見逃してしまうリスクに繋がります。 次に、監視設定の変更に対して、QueryMon管理者のレビューを必要としていた点です。監視設定は、Argo Workflowsのリソースとして表現され、このリソースは社内のC/ICDシステムを経由して、変更するように設定されており、それがQueryMon管理者のレビューと承認を必要としていました。 QueryMonとその管理者は、データのドメイン知識に関与しないので、この監視設定変更の権限をチームに委譲するのが望ましいです。 また、Argo Workflowsを運用するチームが私たちとは別のチームであったため、トラブルシューティング時のコミュニケーションコストが上がる点も厄介でした。 それらの問題を解決するバージョン2.0を開発することにしました。 GCPのCloud Scheduler、Cloud Pub/Sub、Cloud Functions、Datadogを利用して実装しました。チームはそれぞれ独立したGCPプロジェクトを持ち、その中にチーム名、クエリ名、クエリ、サービスアカウント名、BigQueryの実行プロジェクト、タイムアウト時間の情報をJSON形式として、QueryMonのPub/SubトピックにpublishするCloud Schedulerのジョブを用意します。 チームが所有するプロジェクト内のリソースは、チーム内のメンバーのみの承認で変更できるようになっています。QueryMonは、そのPub/SubトピックがトリガーとなっているCloud Functions関数を持っています。 この関数は、トピックにpublishされた情報に含まれるService Accountにimpersonateし、クエリを実行します。さらに、クエリの実行結果をメトリクスとしてDatadogに送信します。 Datadogは、クエリ結果の行数が1行以上である場合、失敗した場合、および開始結果が一定時間存在しない場合に、Slackにメッセージを通知するように設定しています。 このシステムでは、Cloud Schedulerのジョブが、Pub/Subトピックにメッセージをpublishする必要があります。元々Cloud Schedulerは、Pub/Subトピックにpublishするジョブをサポートしていますが、このシステムのように、SchedulerのジョブとPub/Subトピックが別のプロジェクトにある場合は利用できないようになっています。 今回は、SchedulerからPub/Subの publish HTTPS API を呼び出すことで、この問題を解決しています。 Pub/Subトピックのpublish APIは、publishするデータをBASE64エンコードしたものを、パラメータとして受け取ります。 Cloud SchedulerのUIで、このような設定を直接管理するのは困難であるため、Terraformを利用して管理することにしました。 具体的には、図の赤文字で記載されたように、Terraformの関数を利用し、BASE64エンコードされたJSON形式のデータ構造を作成します。これにより、Terraformリソースのコードを通じ、人間にとってわかりやすい形で監視設定を確認できます。 次に、Datadogにmonitorを設定します。monitorは、QueryMonから送られてきたmetricの条件が成立したときに、Slackにメッセージを送るように設定します。 例えば、1行以上データが返ってきたときは、querymon.monitor_result.returned_row_countというmetricの値が0より大きくなります。スライドに記載のDatadogクエリを用いて、メッセージを送信する条件を指定できます。 Datadogクエリに、クエリ名とチーム名を条件に加えることで、特定のチームとクエリだけを選択的に通知の対象とします。また、クエリの実行に失敗したことを検出するために別のmetricを用意しており、上記と似た方法でmonitorを設定しています。 さらに、このmonitorの評価と対象となるmetricが、一定時間存在しない場合にalertを発生させることで、監視が行われていないことを検知できるようにしています。 Ver.2.0は1.0と比べて、複数の点が改善されました。DatadogのAlert Conditionの機能を活用し、監視が行われなかったことを検出できるようになったという点。監視設定をチーム内所有のCloud Schedulerに持つことにしたことで、チームが監視の設定を自分たちで変更できるようになったという点。DatadogがサポートするSlack以外の通知先も設定できるようになったという点。別チームの管理であった、Argo Workflowsを利用しなくなり、トラブルシューティング時のコミュニケーションコストが軽減された点です。 一方で、未解決の問題も残っています。一つは、チームが所有していないService Accountを利用し、任意のクエリを実行できてしまう点です。 QueryMon2.0は、Pub/Subトピックから渡されたデータに含まれるService Accountの権限を使ってクエリを実行します。あるチームが自分たちの責任範囲外のService Accountを用いることを拒否できません。 これにより、セキュリティレベルの高いデータを漏えいするリスクを軽減するために、いくつかの対策を行っています。 まずはPub/Subトピックのpublish権限を事前に申請されたチームのService Accountのみが持つことにしていること。次に、QueryMonがテーブルのデータそのものを扱わないことです。 監視に必要な情報は、クエリが成功したか、成功した場合に返ってきた行数は何行であるかのみです。 BigQueryのquery API をmaxResultsパラメータに0を指定して呼び出すと、クエリの成功失敗と結果の行数を返し、データそのものを返さない挙動となります。これは前述の仕様に合っており都合がよく、そのようにしています。 今回は、BigQueryのデータが正しくないことを検出したいという複数の要件を叶えるため、BigQueryのデータを監視する仕組みを作り、社内に展開した話をしました。同様の課題を持つ皆さまにとって参考となりましたら、嬉しく思います。 本日はありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 メルコインにおけるシステム間のデータ分離を実現するための通信アーキテクチャ 」の書き起こしです。 @pobo380:皆さん、こんにちは。このセッションでは、「メルコインにおけるシステム間のデータ分離を実現するための通信アーキテクチャ」についてお話しさせていただきたいと思います。Fintech ArchitectのKohei Nodaと申します。 最初に少し自己紹介をさせてください。改めて、名前はKohei Nodaといいます。経歴としては、2014年にMIXI入社した後、クライアントエンジニア・バックエンドエンジニア・エンジニアリングマネージャーなど、さまざまなポジションでゲーム開発を行ってきました。 その後、昨年の4月に転職してメルコインに入社し、Architectというポジションで仕事をしてきました。今年の1月からメルペイとメルコインとのアーキテクチャが、合流してFintech Architectという形になって、今はFintech Architectチームで仕事をしています。 早速ですが今日お話しすることをお伝えしたいと思います。一つ目が、メルコインにおける、システム間のデータ分離がどういうものかという話で、二つ目が、開発者体験を損なわずにデータ分離をどのように実現したかという話をしたいと思います。そして、最後にまとめをお話できたらなと思います。 まずメルコインのシステム間のデータ分離はどういうものなのかをご説明します。 メルコインにおけるデータ分離とは、メルコインのシステムとメルカリ/メルペイのシステム間で、それぞれが持つお客さまのデータを容易に紐付けられないようにすることです。 例えばメルコインでは暗号資産を取り扱う業務をしていますので、メルコイン側のシステムでは、お客さまの暗号資産情報を預かる一方、メルカリ/メルペイのシステムではお客さまの住所や氏名などの個人情報をお預かりしています。 もしこれらの情報に同時アクセスできる人がいると、その人はどこの誰がどれだけの暗号資産を持つのかという情報が得られることになります。この情報には価値があり、それを誰かに売る、何かに悪用するなどの可能性が考えられます。 そのため、メルコインのサービスを提供するにあたって、仮に内部の従業員だったとしても、メルコインとメルカリ/メルペイのシステムの間でデータの紐付けができない状態を担保したいという要求がありました。 データ分離を実現するための基本的な仕組みとして、そもそもシステムの分離があります。この図であるように、メルコインとメルカリ/メルペイのシステムはそういう分離されて作られていて、メルコインの従業員はメルコインのお客さまのデータ、メルカリ/メルペイの従業員はメルカリ/メルペイのお客さまデータにしかアクセスできないということが、システムの分類によって実現されています。 この図では、メルカリ/メルペイの従業員がメルコインのお客さまデータにアクセスできないことを示しています。逆もまた然りで、メルコインの従業員がメルカリ/メルペイのお客さまデータにアクセスできません。 ですが、このシステムの分類だけだと、ここでもしメルコインにインシデントが発生したとしてお客さまのデータが流出してしまったと仮定すると、メルカリ/メルペイのアクセス権しか持たない従業員だったとしても、メルカリ/メルペイのお客さまデータと、メルコインのお客さまデータを同時にアクセスして紐付けすることが可能になってしまいます。 さらに悪いケースとして、メルコインだけでなく、メルカリ/メルペイのお客さまデータも同時に流出したとすると、その両方のデータにアクセスできる人は、データの紐付けができ悪用できる状況になります。 このような問題を解決するために、UserIDの分離を行うことになりました。メルコインのシステムとメルカリ/メルペイのシステムで、同じお客さまに対して異なるIDを振り、それぞれのシステムで保存する仕組みです。 同じお客さまでも、異なるIDが振り分けられているので、もし両方のデータが流出したとしてもデータの紐付けが不可能になります。 このように、UserIDの分類をすることで、データの紐付けが流出したとしても、インシデントが起きたことを考えたとしても、紐付けができなくなります。 一方で、メルコインのシステムは、メルカリ/メルペイのシステムに依存し、実際メルコインのサービスとしてもメルカリアプリの中でビットコインの購入や売却ができるようになっているので、どうしてもメルカリ/メルペイのシステムと連携する必要があります。 しかし、メルコインのシステムとメルカリ/メルペイのシステムで異なるIDを使っているとどのお客さまがどのUserIDなのかがわからないので、通信をしても連携ができません。 そこで、通信の際には、お客さまを特定できるIDに変換してから、システム間の通信を行う必要があります。そのために、今回のメルコイン・メルカリ/メルペイのシステム間の連携では、このように内部用IDと外部用IDを用意しました。 単純に考えると、メルコインとメルカリ/メルペイのそれぞれにお客さまのUserIDがあり、交互に変換すれば良いんではないかと思われます。 しかし、例えばメルコインからメルカリ/メルペイに通信を送ることを考えたときに、メルコインの中で通信を送ろうとしたときにメルカリ/メルペイのIDに変換してから送るとすると、メルコインの中にメルカリ/メルペイのID変換を行う権限がないといけません。それをメルコインのサービスの中で付与すると、メルコイン側がメルカリ/メルペイのIDを知っている状況と変わりません。IDの変換権限を持ったサービスやそこにアクセスできる従業員は、実際にはメルコインのお客さまデータとメルカリ/メルペイのデータを紐付けることができるようになってしまいます。 そこで通信用に外部用IDを導入して、2種類のIDを使って変換する仕組みにしています。 それぞれIDを呼び分けているのですが、以降の説明では、メルコインの内部で使う通常のお客さまのIDをMercoin UserID、通信用のものをMercoin PPIDとします。同様に、メルカリ/メルペイのシステムの内部のIDはメルカリ/メルペイUserID、通信用のIDは、メルカリ/メルペイのPPIDとします。 PPIDの詳細については、IDPチームの方が書いたエンジニアリングブログを読んでみてください。 参考記事: Applying OAuth 2.0 and OIDC to first-party services 先ほどの説明で4種類のIDが登場しましたが、メルコインからメルカリへの通信のケースを考えると、このような変換ステップが必要になります。 一つ目はメルコイン側のサービスで、Mercoin UserIDをMercoin PPIDに変換してリクエストを送るというステップになります。次にメルカリ/メルペイのサービスが、リクエストを受け取ったら、リクエストに含まれるメルコインのPPIDをMercari UserIDに変換し、リクエストの処理を行います。 処理をしてレスポンスが生成されたら、レスポンスに含まれるMercari UserIDをメルコインに返すためMercoin PPIDに変換してレスポンスを返す必要があります。最後にレスポンスを受け取ったメルコイン側のサービスはMercoin PPIDをメルコイン内部のUserIDに変換して、レスを受け取ったレスポンスを処理するステップです。 UserIDの分離によってユーザーのデータプライバシーやデータを悪用される可能性を減らせる一方で、4種類のIDが存在するとID体系が複雑で、かつID変換を行った通信もすごく通信のステップ変換のステップも多くてややこしくなります。 今回のシステム連携ではさまざまなシステム連携が必要で、いくつものシステム間の通信を行う箇所がありました。これらのID変換を各マイクロサービスで実装するとするとコストがとても大きくなります。 そこで、システム間で異なるUserIDを用いることでユーザーのデータを守りたい。その一方で、開発者の体験も損なわないようにしたいという要求がありました。これらを同時に満たすアーキテクチャを作りたいという状況でした。 ここからは、そのような要求を満たすアーキテクチャをどう作ったかという話をしたいと思います。 目指した開発者体験を先にお話しすると、メルカリグループでは全面的にマイクロサービスを採用しています。そのため、システム間の通信メルカリ/メルペイとメルコインとのシステム間の通信もマイクロサービス同士の通信になります。 このマイクロサービス同士の通信が、内部マイクロサービスと通信するときと全く同じようにID変換を意識せずに、自分たちのUserIDだけ意識して開発すれば、外部の通信のときには自動的に外部IDに変換されて相手に到達するし、逆にAPIを呼び出される側になったとしても、自分のマイクロサービスに届くときには内部UserIDになって届いているという状況を目指しました。 それをどういうふうに実現したか。メルカリグループでは、基本的にはマイクロサービスの通信はProtocol BuffersというIDLで定義されています。そのため、マイクロサービス間でAPI通信を行うためのリクエストとレスポンスは全てProtobufメッセージとして定義されていることになります。 このメッセージの定義を利用して、通信時にメッセージに含まれているUserIDが、自動的に通信経路上で、開発者が意識することなく適切に変換されているをやることで開発者がID変換を意識する必要がない状態を作ることができました。 具体的なProtobufメッセージに含まれるIDの変換なんですけれども、Goの実装例も書いてあるんですが、イメージとしてはProtobufのあるメッセージとID変換の向きがUserIDからPPIDなのか、PPIDからUserIDなのかに従って、ID変換の呼び分けを行います。 メッセージの中に含まれるIDを全て変換して値を置き換えることが、メソッドを呼び出したときに行われるイメージです。 どのフィールドにあった値が含まれるかを知らなければならないのですが、どのフィールドに値が含まれるかという情報は、CustomOptionというProtocol Buffersの仕組みを使って、protoファイルの定義の中でアノテーションを行います。 これが、実際にプロファイルに対してアノテーションを行うときのイメージです。 例えばGetUserRequestというユーザー情報を取り出すリクエストがあったとして、引数にUserIDがあるときには、フィールドに対してID変換を有効にする、アノテーションをつけます。またレスポンスも同様に、レスポンスに含まれるUserIDにアノテーションをつけます。 そのためのCustomOptionの定義はこのような内容になります。 ここまでで説明したProtobufメッセージに含まれるIDの変換の機会を、通信経路上の二つの箇所で行いました。 一つは呼び出し側(Caller)でのID変換はgRPC Client Interceptorで、呼び出される側(Callee)でのID変換はGatewayというサービスを使って行いました。 通信経路全体としてはこのような形になります。 Caller側のID変換は、マイクロサービスに含まれるgRPC Client Interceptorで行います。そのinterceptorがIDを変換して、Gatewayを経由して、相手のマイクロサービスにリクエストを送ります。 そのGatewayでもう一度ID変換が行われて、Calleeのマイクロサービスに届きます。メルカリとメルコインのシステムを例に出していますが、逆向きの通信についても同様の経路です。 通信系の上の二つのID変換について説明する前に、図の中に出てきたID Providerについて説明します。 これはUserIDとPPIDのマッピングを持っているサービスで、メルカリ内のID ProviderのIDPのチームが管理しているサービスで、UserIDとPPIIDを相互に変換するAPIを提供しています。gRPC Interceptorでの変換とGatewayでの変換で、ID Providerと通信をして、IDマッピングを手に入れて変換することになります。 CallerのID変換ですが、これは先ほど説明したようにgRPC Client Interceptorで行います。呼び出し側のCaller側のマイクロサービスの中で変換を行います。 gRPC Client Interceptorは、gRPCのクライアントからAPIを呼び出すときに、いろいろな操作ができます。 そのできる操作の一つにリクエストレスポンスを変更することがあります。gRPC Client Interceptorの中で、メッセージに含まれているIDを取り出し、変換し、Gatewayに送信しています これはAPI呼び出しのたびに何かする必要はなくて、gRPCのClientをセットアップするときにInterceptorを挟むという設定をしておけば、自動的にInterceptorが呼び出されます。 このinterceptorでは、リクエスト送信時にCallerのUserIDからCallerのPPIDに変換して、Gatawayから戻ってきたレスポンスに対してCallerのPPIDからCallerのユーザーに変換するという処理が行われます。 CalleeのID変換は、Gatewayで行われます。Gatewayはすでにメルカリ内で多く利用されているサービスで、外部のインターネット(例:お客さまからの使っているアプリ)からくるリクエストの入口となるサービスです。いわゆる、API Gatewayに近い実装です。これが一番手前にあり、内部のマイクロサービスにルーティングを行います。 Gatewayの中で、Callerから渡ってきたgRPCの呼び出しのメッセージに対してID変換を行います。リクエストを受信したときには、CallerのPPIDでくるので、CalleeのUserIDに変換して、マイクロサービスにルーティングを行い、メッセージを渡します。 自分たちのマイクロサービスからレスポンスが返ってきたら、そこにはCalleeのUserIDが含まれているので、それをCallerのPPIDに変換します。 gRPCにはServer Interceptorがあって、Client Interceptorと同じように、Callee側のマイクロサービスでもリクエストレスポンスの変更が可能です。なぜここで、Callee MSではなく、GatewayでID変換を行っているのかという話をすると、CallerのPPIDからCalleeのUserIDの変換は、各マイクロサービスではなく、限られたコンポーネントで行いたいという要求がありました。 呼び出される側は、いろいろなところから呼び出されるので、相手のPPIDが送られてきます。その際、受け手のマイクロサービスは、任意の相手のPPIDが送られてくる可能性があるので、このIDを自分のUserIDに変換するという権限を持つ必要があります。 これはかなり強い権限であり、相手のPPIDを自分のUserIDに変換できるということは、もし相手のPPIDとユーザーデータに自分がアクセスできる状態になったときに、自分の持っているデータとその相手のデータの紐付けが可能になるという権限になります。 なのでここは各マイクロサービスに権限を渡すのではなくてGatewayという限られたサービスだけに権限を渡して変換を行うという選択をしました。 もう一つの観点としてCalleeのマイクロサービスにServer Interceptorを導入しなきゃいけないという、手間もなくなるというメリットもありました。 ID変換と通信フローのおさらいです。このように、Caller側のマイクロサービスからgRPC Client Interceptorにメッセージがあって、ID変換が行われ、Callee側のGatewayにメッセージがわたり、そこでまたID変換流れ、Calleeのマイクロサービスは内部のUserIDだけでリクエストを処理する場合と、レスポンスを生成して、Gatewayに返し、ID変換が行われ、gRPC InterceptorでID変換行われ、また呼び出し元のCallerのマイクロサービスにレスポンスが返ってくることになります。 Gatewayと、gRPC Client Interceptorによる変換で、このような開発者体験が得られました。開発者がやらなければいけないこととしては、Caller側は、gRPC Client Interceptorを、導入するだけですね。一度だけセットアップすれば良いです。 また、通信に使うProtobufのメッセージに含まれる、UserID、そのフィールドに対してアノテーションを付与すること。この二つを行うだけで、開発者はID変換というのを意識することなく、UserIDだけ扱って、内部通信と同じようにシステムを超えた、API呼び出しが可能になりました。 ここまで通常の同期通信のケースを考えましたが、実際にはシステムをまたいで非同期通信をしたいケースもありました。 ここでいう非同期通信は、メッセージキューを使う通信です。また、メルカリグループでは、ほとんどのサービスで、Cloud Pub/Subを利用しています。Cloud Pub/Subを経由した通信でも、開発者がID変更を意識することなく開発できるようにしたい状況でした。 そこで、Cloud Pub/Subのトピックに加えて、Pub/Sub Pusherというサービスが出てきます。 Pub/Sub Pusher自体はID変換のためだけに存在しているものではなく、Cloud Pub/SubのトピックからPull SubscriptionでメッセージをPullして、それをgRPCリクエストに変換し、メッセージを受け取りたいSubscriberに対してgRPCリクエストを送る機能を持ったコンポーネントです。 これは元々Pull Subscriptionを実装するというテーマがあるので、他のマイクロサービスの通信と同じように、Cloud Pub/Subを使いたいという要望が要求があって、作られたものになります。これはサブスクライブするトピックと、gRPCリクエストを送る先をKubernetesのmanifestとして記述すると、カスタムリソースになっていてカスタムコントローラーとして実装されていて、裏で実際にその処理をしてくれるものです。 これに拡張を行って、今回のシステム連携のために、ID変換機能をまずこのPubSub Pusherに追加しました。PubSub Pusherの中でPublisher側のUserIDから、SubscriberのPPIDへ変換しています。 同期呼び出しの場合は、Publisher PPIDに変換する形でしたが、ここではSubscriberのPPIDに変換しています。 Pub/Sub Pusherが行うのは、通常は内部の通信なのでこれをGatewayに対してリクエストを送ることをしています。 あとはGatewayは同期的なAPI呼び出しと同じように、gRPCに変換されているので、リクエスト受信時とレスポンスの送信時に、同じ変換を行えばいいことになります。 これで非同期通信に関しても、開発者ID変換を意識しないという体験が得られました。開発者が行うことは、Pub/Sub Pusherの設定ファイルを記述して、ID変換とGatewayへのPushを有効にすることだけです。 最後に、まとめです。 改めてですが、メルコインではシステム間でUserIDを分離することで、データの紐付けを不可能にして、高いレベルでのデータプライバシー保護を実現することができました。 一方で、ID変換という複雑な作業は、通信経路上で透過的にID変換を行うアーキテクチャを導入することで、効率的な開発ができるようになりました。マイクロサービスの開発者は実装時にID変換を意識する必要がありません。 なぜこれを実現できたかというと、マイクロサービスといえどほとんどがGoで実装されていて、gRPCを使って、通信しているProtobufでメッセージが提起されている状況だったからこそだと思います。 最後に、残っている課題を紹介して終わろうかと思います。 一つは、メルカリの中では一部Goでない実装があり、その場合は今回のようなID変換に対応できないという課題があります。 もし解決しようとすると、よりマイクロサービスにInterceptして入れるのではなく、例えば通信経路上のプロキシなどを経由して、呼び出し側も変換することが考えられます。 不具合調査時のTraceabilityは、お客さまに問題が起きて、メルカリのユーザーデータと実際見る行為のお客さまのデータを紐付けて調査しなければならないとき、それができない仕組みになっているので、かなり調査がやりづらいという状態です。 最後の一つはUserID以外のデータの紐付けです。 例えばメルカリでの購入履歴をメルコインでも共有していて、同じデータをそれぞれのDBに保存し、それぞれにユニークIDが保存されていると、UserIDでなくても紐付けが可能になってしまっています。現状の解決策はないんですけど、これをどう防ぐかを考えています。 発表は以上です。ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 メルコイン決済基盤の実践話 」の書き起こしです。 @foghost:皆さん、こんにちは。これからのセッションは、2023年3月にリリースされたメルカリアプリでのビットコインの取引の裏側にある、「メルコインの決済基盤の実践話」を紹介します。 まず、簡単に自己紹介します。私はJunwei Liangと申します。社内では、@foghstとも呼ばれています。 2016年11月にメルカリに入社し、メルペイの立ち上げ時期から決済基盤の開発に関わってきました。現在はEngineering HeadとしてValue Circulation Platformチームでメルカリグループ全体の各事業を支えるためのビジネス基盤の開発・運用をしています。 私たちのチームでは、「プロダクトチームにとってベストチョイスとなる基盤をプロダクトとして提供する」ことをビジョンとして掲げています。 具体的には、本日紹介する決済基盤や加盟店管理、KYC、カスタマーサポートなどの基盤をプロダクトチーム向けに提供しています。 そして本日のセッションの内容は、このようになります。最初に軽く全体の概要を紹介し、三つのドメインについてそれぞれ話します。 こちらは、決済基盤の概要です。ご覧のように、中は独立した二つの決済基盤にわかれています。右側は、メルペイの決済基盤です。メルカリのフリマアプリやメルカリShops、メルペイの各種決済手段に対応するための決済機能を提供しています。左側は、メルコインの暗号資産取引サービス向けの決済基盤です。 なぜ二つにわかれているかというと、メルコインの暗号資産取引の事業には、最初はセキュリティとITリスク観点での要件から、システムのインフラから開発運用を全部既存のシステムと切り離すという判断があったからです。 そのため、既存の決済基盤から機能を提供できなくなり、メルコイン専用の決済基盤を再構築しました。メルコインの決済基盤は、赤色の決済処理・台帳管理・帳簿管理という三つのドメインで構成されています。 私たちが提供している決済基盤における決済の定義は、「さまざまな決済取引において参加者たちのお財布を操作して、価値の移転・交換を行う」こととしています。 メルコインにおいては「暗号資産取引においてお客さまの取引口座、暗号資産口座などの財布を操作して、価値の移転・交換を行う」ことを決済と言います。 中でも最も基本となるのが、お客さまが持っている口座や口座の中で管理される価値の変動などの管理です。これを私たちは「台帳管理」というドメインで整理しています。 メルコインのお客さまが持っている口座の種別はこのようになっています。まずメルコインのお客さまは、基本メルペイを利用しているお客さまなので、メルペイ側の口座としてはメルカリのポイント口座またはメルペイの資金の口座を持っている状態です。 メルコインのサービスを利用し始めると、メルコインの法定通貨を扱う取引口座として暗号通貨ビットコイン(以下、BTC)を扱う暗号資産口座が作られます。ちなみにここのBTC口座は、あくまでもシステムの中の口座の話で、ブロックチェーン上のウォレットではないです。 これらの口座を操作するときに、価値の変動を記帳します。方法は二種類あります。 一つは、単式です。例えば、お客さまがメルコインでメルカリのポイント1000円と、メルコインの取引口座の残高1000円を利用してBTCを2000円分を購入するというユースケースがあげられます。 この場合、決済処理のところからそれぞれメルカリのポイントを引いて、または台帳サービスから1000円を引いて、最後にまとめて2000円のBTC付与を台帳サービスに記帳します。 この記帳方法では、取引におけるお金の移動については、移動元の口座と移動先の口座でそれぞれ単独で操作・記帳しています。 また、単独のため、ある口座のお金がどこから入った・出たなどの追跡はできないようになっています。先ほどの例では、2000円分の内訳は追跡できません。 もう一つの記帳方法は、私たちは複式と読んでいます。台帳に連携する際に、移動先と移動元をセットで操作・記帳します。 例えば、取引口座の1000円を引いて、コインBTC1000円を付与した場合、先ほどと違って、1000円の取引口座の残高消費と1000円のBTC口座の付与は一つの記帳処理として台帳に連携され、台帳で二つの口座を同時に操作・記帳することになります。 取引におけるお金の動きについては、移動先・移動元の口座は必ずセットで操作され、台帳に記帳されます。お金の出入りについて、移動先・移動元を追跡できます。 メルコインの台帳サービスでは、複式記帳を採用しています。例えば先ほどの例で言うと、取引口座の1000円を引いてBTC1000円分を購入した場合は、上流から台帳に記帳のリクエストを投げ、台帳システムのTransaction Layerでインプットを受け取り、そこで指定された口座を扱ってそして該当する金額分の価値の交換処理を行います。 価値の交換によって口座の内容が変動するのですが、変動ログなどを保存するため、口座の裏側にログやスナップショットなどの細かいデータが作られています。 複式記帳法については、一つ課題があります。 メルコインの台帳システムで管理してない口座を操作する時に、メルカリポイントだとメルペイの決済基盤で管理されてますので、メルコインの台帳システムでは、口座としては置いていません。 複式記帳する際に口座がないので、本当は実現できないのですが、記帳の実態がない内部口座を設けて今処理してます。 例えばメルカリポイントであればメルカリポイントの預かり金口座を、メルペイの残高であれば、メルペイの残高の預り口座を用意しています。そして、メルコイン自身でお客さまにBTCを付与するキャンペーンがあるときは、費用負担の口座も作っています。 また、複式を採用すると、口座の種別が2倍になる可能性もあるので、口座を増やすときに、随時開発が必要になる、生産性が低い仕組みになってしまいます。 そこで私たちが行ったのが、Configurable Value Accountの仕組みの導入です。基本全ての口座のデフォルトの動きが一緒なんですけど、それぞれの口座の特性によって特殊な動きが発生するときに、それを属性として定義・コントロールします。 すると、新しい口座が作られるときに既存の口座で提供している動きであれば、Configを書けば、あんまり実装コストをかけずに、機能を提供できます。 次に、決済処理について説明します。お客さまが持っている、内部もしくは外部の口座を操作して価値交換を行うところを決済処理と定義しています。 そしてシステムを跨いでも決済処理をするので、複数のサービスを跨いだ際の整合性担保も、重要な役割です。 機能としては、このように、メルコインでは価値交換という形で決済のスキームを抽象化して、提供しています。メルペイでは決済の取引に参加しているお客さまの種別や口座種別、サポートするアクションによって、決済APIを分けて対応しました。 メルコインでは、もう一段階抽象度を上げて、相手同士で持っている口座が価値交換という形で決済処理できるよう機能を提供しています。 メルコインでの取引は基本、お客さま自身が持っている口座間になるので、相手はお客さまです。そしてお客さまが持っている各種口座からお客さまのある口座に価値を交換してあげることを、この価値交換APIを通して実行できます。 サポートする処理としては、上流側で即時で確定したい場合は、即時確定モードを使ったり、条件をクリアした後に確定処理をしたいというニーズであれば、仮処理してから確定sよりを行う2 Phaseの処理もできるように機能設計しています。 BTC購入のユースケースを例に説明します。お客さまに提示している価格などの条件を使って、実際の取引の約定処理をするのが上流の暗号資産取引を担当するサービスです。約定処理の中で決済処理を担当するサービスにお客さまが持っている取引口座やメルカリポイント口座を表記させるという依頼を、APIを通して依頼を投げてきます。 上流側で約定を確定したタイミングで、ここで定義している確定処理を呼べば、取引口座やメルカリポイント口座から押さえた残高を確定し、最終的にお客さまの暗号資産口座にBTCを付与します。 続いて、BTC売却を例にお話しします。先ほどとは逆に、お客さまが持っているBTC口座からBTCを消費し、上流側の取引が約定確定したら、確定処理を行って、最終的にBTCが消費され、お客さまの取引口座に該当する金額分の売上残高が付与されます。 もう一つのトピックとしては、複数のサービスをまたいで決済処理を行うので、分散型のトランザクションをハンドリングする必要があります。これについては既存のメルペイでも同じ課題がありました。メルコインでは、この課題について新しい取り組みをしてきました。 参考記事 マイクロサービスにおける決済トランザクション管理 メルコイン決済基盤における分散トランザクション管理 メルコインの決済サービスの開発と一緒に、社内の他のチームでも汎用的に使えるワークフローのSDKを開発しました。SDKを使えば、通常のプログラミングと同じ体験でワークフローの関数を定義すれば、ワークフローのロジックを組み立てることができます。 そして、一つの決済処理を複数のActivityに分解して、ロールバックが必要なエラーが発生したら、右側の補償処理をActivityとして定義すれば、自動的に実行し、最終的に決済処理の結果整合性を担保する仕組みです。こちらの詳細について別のセッションでチームメンバー(@susho)から詳しく紹介してくれます。 参考記事: メルコイン決済マイクロサービスのトランザクション管理を支える技術 もう一つのトピックは、メルコインではマイクロサービスを跨いだ整合性担保をProcessing Tracerという仕組みを使って担保しています。 この仕組みを使うと、各マイクロサービスで今まで独自でバッチなど実装している処理が全部共通の仕組みでイベントベースで処理されます。 また、突合する結果もProcessing Tracerに報告が求められるので、報告のレポート がProcessing Tracerにシングルソースとして集められます。 そうすると、例えば会計帳簿のところで仕分けする時に、後で手戻りがないように、一つの処理の会計データに対してその処理の突合が終わっているかどうか確認した上で処理できます。 最後に帳簿管理のドメインについても説明します。具体的には、会計および法定帳簿の管理の話です。 帳簿と台帳との定義の違いは、独自で定義している部分もありますが、一応どちらも取引におけるお金の変動・流れを記録するためのものです。 台帳と私たちが呼んでいるのが、プロダクトサイド向けにお客さまが持っている口座の価値の増減や移動の管理を行っているものです。それ以外の目的で、お金の移動・流れを記録するものを帳簿と定義してます。 具体的には、会計処理するための帳簿が会計帳簿、法定要件を守るための帳簿を法定帳簿と定義しています。 最初に、会計帳簿連携の話をします。メルペイでは、社内に共通の会計サービスがあるので、会計要件が発生するときに、各マイクロサービスから必要に応じて必要な会計イベントを定義して、会計サービスに連携しています。 またメルペイの台帳サービスは単式記帳を採用しているので、片側しか取れてないので会計連携にするためにデータが不足しています。 既存のメルペイの手法にはこれらの課題を感じています。 一つは、各マイクロサービスについて必要に応じて会計連携すると、システムや会計のドメイン知識が必要なので、特に決済基盤で一番コアな決済サービスでは、たくさん決済種別があって、決済種別によって予定会計連携のデータ群の整形が間違っています。すると、会計や運用のコストが高くなります。 また、メルペイの台帳システムは単式記帳を採用しているので、台帳のLayerから会計の連携を全て行うことは現状不可能です。 台帳と会計帳簿はどちらも上流側の決済取引によって発生したお金の動きなので、そこのリコンサイル観点でも細かく実施したいですが、まだ台帳と会計帳簿の連携は今バラバラで、特に記録する時間が各マイクロサービスを処理時刻になってずれることもあるので、正確にはリコンサイルができない状態にはなっています。 それを考慮した上で、メルコインの会計帳簿の連携の仕組みははこのようになっています。 複式記帳を採用した台帳サービスをメルコインは作っているので、取引で発生しているお金の移動元と移動先が台帳サービスの中でも取れている状態です。それを使って、会計仕訳に必要なデータを連携できるようになります。 帳簿サービスは、会計帳簿を行っているところです。会計帳簿という新しい会計のイベントを集めて仕分け処理を行い、会計に欲しい仕分け帳簿などのデータを作るコンポーネントも開発しました。 メルコインが採用している会計連携の仕組みの特徴としては、台帳のサービスのレイヤーのみ会計データの連携をするので、それ以外のマイクロサービスが会計連携の責務は考えなくても良く、開発運用コストは軽くなります。 基本確定された台帳データを使って会計帳簿にデータを連携するので、台帳と会計帳簿のリコンサイルの仕組みも簡単に作れます。 最後に、法定帳簿についても軽く紹介します。法定帳簿は、暗号資産交換業における法定要件を満たすための帳簿データの集計と管理が求められるものです。 「顧客・自己注文伝票」「顧客・自己感情元帳」「分別管理表」などの法定帳簿を集計する必要があります。これらの帳簿を作成するために、同じく帳簿のドメインとして、帳簿サービスの中で、法定帳簿を管理する機能を作っています。 データソースとしては、上流側の暗号資産取引サービスから必要な取引のドメインイベントを集めたり、台帳サービスから提供しているAPIを使って、お客さまが持っている各種口座の変動データを参照しながら、この辺が必要になる法定帳簿の集計を日次で行っています。 最後に、まとめです。本日は、メルコインの決済基盤について紹介しました。 ハイライトとして、複式の記帳手法を採用した新しいの台帳サービスの開発、そしてより汎用的に利用できる価値交換の決済機能を提供する決済サービスの開発、整合性を担保をするために、ワークフローのSDKやProcessing Tracerの新しい仕組みの取り組みも行いました。 最後に、会計および法定帳簿の管理をするための帳簿サービスの開発も、プロダクトサイドで行いました。 これからのチャレンジとしては、メルコインで、実践した経験を生かして、メルペイ側の決済基盤もこれから進化させていきます。また組織横断で、台帳帳簿の決済については共通化できそうなドメインコンポーネントも見えているので、共通化できるシステム設計にもこれから挑戦していきたいです。 以上で本日のセッションを終わりにします。ご清聴ありがとうございました。