Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み 」の書き起こしです。 @m-iino:本セッションでは、「メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み」についてお話しします。 まずは、プレゼンターの紹介です。私はIinoと申します。2019年5月にメルチャリに参画し、インフラとバックエンド担当。2020年2月からメルペイSREチームに参加。2021年からメルコインSREのテックリードとして、メルコイン事業の立ち上げを担当しています。 @yuhara:このプレゼンの後半を担当する、Yuharaといいます。2021年からメルコインのSREチームでネットワークやインフラ周りを中心に立ち上げを担当しました。よろしくお願いいたします。 @m-iino:本セッションでは、前半と後半に分けてお話しします。前半は、メルコインに求められるセキュリティとコンプライアンスへの取り組みについて説明します。後半は、インフラの全体像と信頼性のあるサービスをリリースするための取り組みについてお話ししていきます。 それではまず、セキュリティとコンプライアンスへの取り組みについてお話しします。 メルコインとは、メルカリアプリ内でビットコインの売買ができるサービスを提供する会社です。2023年3月9日より、暗号資産交換業を開始しました。本セッション内では、メルカリアプリ内の暗号資産取引サービスを「メルコイン」としてお話しします。 そんなメルコインのインフラに求められるものとは、何でしょう。暗号資産取引所システムは、金融取引を取り扱うため、セキュリティとコンプライアンスが非常に重要な要素となります。 セキュリティについては、暗号資産取引所は、サイバー攻撃や不正アクセス、ハッキング等のリスクを抱えています。そのため、強固な情報セキュリティを有することが必要です。 コンプライアンスについては、暗号資産取引は各国での法律や規制に基づいて運用管理されているため、各国の法律や金融監督当局の規制を遵守する必要があります。 これらのセキュリティとコンプライアンスを適切に管理し、コード化することで、お客さまデータの保護と取引所の信頼性を維持することが可能です。 メルコインのセキュリティ規程や要件は、メルカリやメルペイとは異なります。 暗号資産ビジネスの特性上、さまざまなサイバー攻撃への対策を行う必要があります。また、国の規定が急に変更される場合は、即座に対応しなければなりません。そのため、メルコインは、メルカリ・メルペイとインフラを分離することで、守るべきポイントを減らし、急な規制変更にも耐えられるよう、コンパクトにすることを目指しました。 暗号資産取引所システムのセキュリティとインシデント管理には、高い水準が求められます。理想はその水準を全てのカンパニーで満たすことですが、すぐの実現は容易ではありません。例えば、インフラを分離せずメルコインをメルカリ・メルペイのインフラと同居させた場合、メルカリ・メルペイのシステム管理体制や運用に大きな影響を及ぼします。 メルカリ・メルペイで発生したインシデントをメルコインに伝播させないためでもあり、逆に攻撃される可能性が高い暗号資産取引所システムへの攻撃をメルカリ・メルペイに波及させないためでもあります。 将来的には、全てのカンパニーでメルコインと同等のセキュリティコンプライアンス基準を満たす予定です。 プロダクション環境における具体的な分離例を説明します。まず、Google Workspaceがメルコインとメルカリ・メルペイで分離されています。既存のmercari.comに対して、mercoin.comというGoogle Workspaceを用意しました。 GCP Organizationも、それぞれのWorkspaceに存在しています。しかし、Billing Accountは、共通のものを使用しています。これはメルカリがGoogleと交わした契約条件などをメルコインにも適用するためです。 複数のGCP Organizationで共通のBilling Accountを使うために、GCPのMulti Billingを使用しています。この機能は、最大で五つのOrganizationに適用することが可能です。数が限られているため、よく検討し、慎重に適用する必要があります。 開発者が誤った設定をすることで、原因が生じる可能性があります。開発者が意識せずとも、セキュリティが保証されるべきです。そして、新たにmicroservicesを追加してもセキュリティを保つべきです。そのため、メルコイン全体でSecure by defaultを目指すことになりました。 メ゙ルコインでは、メルカリグループが積み上げてきたセキュリティ機能や設計を受け継ぎつつ、1から作れる強みを生かして、初めからセキュアな状態を作り、維持することを目標としています。また、セキュリティ設定を後から追加していくのではなく、初めから使える設定を最小限にすることで、開発者が意識せずとも危険な設計をしてしまうことを防いでいます。必要に応じて部分的に例外を許可するようにしています。 GCPの Organization Security Policy をGCP Organization全体にかけることで、サービスが増え、新たにGCPプロジェクトを作成しても、初めから危険な設定ができないようになっています。 プロジェクト発足時からセキュリティチームと協力して、全てのOrganization Security Policyを一つずつ検討し、Organizationレベルでポリシーを適用しています。検討の際には、Googleが提供している Google Cloud Security Foundations guide や CIS Benchmark の推奨事項も参考にしながら、ポリシーを作成しました。 ここで採用しているポリシーの一例を紹介します。SSH keyをGCEのMetadataに埋め込んで使うことを防止し、ブートローダーやOSの改ざんも防いでいます。GCEのデフォルトサービスアカウントへのエディター権限の付与も制限しています。また、GCSのパブリック公開も制限しています。 IAMに関しても、最小権限を設定したカスタムブラウザロールを用意し、各チームに合わせた、GCPフォルダレベルで各チームにロールを増やしています。例えば、プロダクション全体を見るSREチームには、広い範囲で最小権限を有効にし、microservicesチームには、担当するmicroservicesを束ねるチーム用のGCPフォルダーに対して最小権限を付与しています。 オペレーションなどで権限昇格が必要な際には、「Carrier」という社内製の権限昇格ツールを使って一時的な権限昇格を行います。Carrierについては、セッションの後半でも説明します。 また、Security PolicyでカバーできないものはPRCの項目に追加し、新規サービスのリリース時など、定期的にチェックを行っています。 セキュリティとコンプライアンスの観点からメルコインのインフラに対して、メルコインのチームがオーナーシップを持つ必要があります。 メルカリグループでは、Mercari SRE、Merpay SRE、Mercoin SREと、それぞれのプロダクトごとにSREチームが存在します。 それぞれのSREチームが担当するプロダクトを安定的に動かすために、インフラの開発運用や、microservicesのサポートを行います。プロダクトごとのSREとは別に、インフラ基盤の開発・運用をするPlatformチームがいます。インフラ全体のオーナーは彼らが担っています。 メルコインSREと比較するために、まずはメルペイにおけるSREについて説明します。メルペイでは、SREが開発チームのサポートをしつつ、メルペイが共通で使うシステムの開発管理を行っています。Platformチームはインフラコンポーネントの開発をしつつ、インフラ全体のオーナーでもあります。 一方でメルコインでは、SREの基本的な役割は、メルカリ・メルペイと同じですが、インフラ全体のオーナーをSREが担っています。 Platformチームにはインフラコンポーネントの開発・運用を委託する形で承認をSREが行っています。こうすることで、メルコイン組織に所属する人がメルコインのシステムを管理する体制を実現しています。 メルコインでは、バックアップを含むお客さまデータやサーバーリソースを全て日本国内に置いています。 日本国内で取り扱うことで、日本の法令と規制の遵守が容易になります。また、お客さまデータの保護指針が明確になり、管理とセキュリティ対策が容易になります。 そのため、GCPのリージョンを東京と大阪に制限しています。ただ、GCPがグローバルでのみ提供している機能は、リージョンの指定はしていません。 Organization Security PolicyのresourceLocationsをGCP Organization全体にかけることでサービスが増え、新たにGCPプロジェクトを作成しても、初めから国外でのリソース作成ができないようになっています。 ただし、必要に応じて、プロジェクト単位で他のリージョンへのリソース作成を許可することも可能です。ポリシーの管理はSREが行っているため、例外を設定するには、システム上でSREの許可が必要です。 メルコインは、お客さまの安全と信頼を確保するために独自のインフラを構築しました。これはメルカリグループから分離されており、メルコインのチームがインフラの管理を行っています。システムは日本国内で運用されており、安全な取引環境を提供しています。さらに、開発者が特別な注意を払わなくても、システムの設計主体が安全性を確保するようになっています。 @yuhara:ここからは、メルコインのインフラの全体像と信頼性のあるサービスをリリースするための取り組みについてお話しします。 まずはメルコインのアーキテクチャについてです。全てのmicroservicesはGCPを利用しており、共通のGKEクラスターの中で動いています。 microservicesはレイヤーアーキテクチャとなっており、インターネットからのリクエストを受け付けるゲートウェイサービスと、認証をつかさどるAuth Tokenサービス、各バックエンドサービスの手前に置かれるBFFとしての役割を持つAPIサービスやビジネスロジックをつかさどる各種バックエンドサービスという形で、レイヤーを構成しています。 各microservicesのワークロードは共通のGKEで動いていますが、そのサービスが利用するデータベースなどは、microservicesごとに個別のプロジェクトにわかれており、サービスオーナーであるバックエンドエンジニアチームで管理しています。 microservicesはそれぞれのプロジェクトにわかれていますが、ネットワークの側面でいうと、Shared VPCの構成をとることで、VPCに所属するリソース、GKEやGCEなどのリソースは、プロジェクトがわかれていても、共通のVPCの中で通信することができます。 またShared VPCのホストプロジェクトが、ネットワークのハブとしての位置づけになるので、そのホストプロジェクトをネットワーク管理者が管理することで、例えばVPC Firewallで、Shared VPC内の通信を制御したり、Cloud NATによって外部向けの通信をコントロールしたり、あるいはVPC内のプライベートドメインをCloud DNSで管理することができるようになっています。 メルコインでは、Secure by Defaultのポリシーに沿って、VPC FirewallでDefault Deny構成としており、必要な通信を管理者が許可する運用を行っています。 あとメルコインではGKEクラスターは用途に応じていくつかのクラスターにわかれており、コンシューマー向けのサービスに関わるアプリケーション用のクラスターと、それ以外のクラスター、例えばGitHub Actionsのself-hosted runnerを自前で管理しているので、そのためのクラスターや、社内の運用ツール用のクラスターなど、クラスターが複数にわかれています。 クラスター間で通信が必要なケースでも、Shared VPCによって、VPC内で通信が収まります。 またメルコインでは、メルカリのOrganizationとは完全に分離された独立したOrganizationとVPCの構成になっていますが、メルコインからメルカリ側のサービスと連携するケースがあります。 例えば、メルカリのユーザーIDとメルコインのユーザーIDをマッピングするために、メルカリのユーザーIDをメルコインから取得するケースです。このようなケースでは、VPCがわかれているため、一般的にはインターネットにサービスエンドポイントを公開して、インターネット経由でアクセスするか、異なるVPCをVPCピアリングでネットワークを接続する方法などが考えられます。 いずれの方法にしても、ネットワークを繋げるための設計が煩雑なため、メルカリグループとしては、異なるカンパニー間のVPCを簡単に接続する仕組みとして、Private Service Connect(PSC)を採用しています。 Private Service Connectでは、対象となるサービスをService Attachmentを使って公開したいプロジェクト(今回の例では、メルカリ側から見たメルコインの対象プロジェクト)に絞って限定公開することで、指定したプロジェクトからのみの接続を許可し、セキュアにアクセスすることが可能になります。 VPCピアリングなどは不要で、簡単にメルカリ側のサービスとの連携を実現できます。 続いて、メルコインGKEクラスターに関わる設計の一部を紹介します。メルコインのGKEクラスターはプライベートクラスターとなっています。 プライベートクラスターは、外部IPアドレスを持たない、つまりVPC内の内部IPアドレスのみを持つNodeの構成となっています。またKubernetesのAPIサーバーは、VPCの内部IPアドレスで提供されるので、Nodeや同じVPC内にいるホストからは、このプライベートエンドポイントに対して、ネットワークに閉じた形で通信できます。 またメンテナンスやオペレーションのためにインターネット上からKubernetesのAPIサーバーにアクセスするケースでは、パブリック向けのエンドポイントを特定のIPアドレスに限定して許可する形で運用を行っています。 あとはNodeが外部IPアドレスを持たないため、外向けの通信はCloud NATを経由する形になっています。 その他のメルコインのGKEで使っている機能の一例として、一つ目に、Network Policyがあります。全てのmicroservicesが一つの共通クラスターの中で、マルチテナントになっているため、microservicesネームスペースへの通信を制御するために、Network Policyを有効にしていて、デフォルトでは全てをdenyする設定としています。必要なmicroservicesのみのアクセスを許可するために、Network Policyをアップデートしていくホワイトリスト方式の運用を行っています。 続いて、Cloud DNS for GKEです。Cloud DNSを有効にしています。DNSのスコープとしては、クラスタースコープとVPCスコープという二つのモードがありますが、メルコインではVPCスコープを使ってます。VPCスコープを使うと、GKE内部のDNS名がVPC全体に伝播するので、クラスターの外のホストから直接特定のKubernetesサービスの名前を引くことができ、Ingressを経由することなく、クラスターの外からmicroservicesにアクセスできます。これはあくまで前提として、VPC FirewallやNetwork Policyで通信が許可されている場合に限ります。 あとは、Google GroupをKubernetesのRoleBindingに指定することができる機能のGoogle Group for RBACも有効にしていて、ユーザー管理をGoogle Groupと連携させたり、Workload IdentityについてはKubernetesサービスアカウントをGCPのIAMサービスアカウントと連携さして、Keyless構成を実現させています。 Istioに関しては、GKEで用意されているアドオンを使うこともできますが、メルコインではアドオンを使わずに個別にセットアップしています。アドオンだと、Googleマネージド Istioが使えるものの、バージョンの指定や、使いたい機能や設定の調整などができないため、メルコインとして使いたいバージョンや機能を指定するために、ユーザーマネージド Istioで運用しています。 Istioの用途としては、主にCanary Releaseで1%トラフィックマイグレーションを行うことや、microservices間の通信をMTLSで暗号化することなどがあげられます。 次にメルコインのmicroservicesの開発・運用の全体像を見ていきます。先ほど、全てのmicroservicesは共通のGKEクラスターの中で動いていて、ネームスペースで区切られたマルチテナントになっており、GCPもプロジェクト単位でわかれているという話をしました。これらの開発・運用方法についても紹介したいと思います。 microservicesごとに開発チームが決められており、そのチームがオーナーシップを持って運用も行います。この例では、サービスAチームはKubernetesのネームスペースA上のmicroservicesと、それに関わるGCPプロジェクト内のSpannerや、Pub/Subといったリソースの管理です。 ただし、これらの構築や運用には多くの専門的な知識やリソースの管理が必要です。限られたメンバーとスケジュールの中で、1から全てをプロビジョニングするのは大変で、メルコインとして期待する設定が行われていないといった可能性も出てきます。 SREとして、チームの開発を促進し、かつメルコインで定めた設定をプロビジョニングできるように、抽象化したモジュールを提供しています。これらを使うことで、開発者は全ての設定を一つ一つ行う必要はなく、既に標準化されたものをプロビジョニングできます。 具体的には、SpannerやPub/SubといったGCPの各種リソースだけではなく、オンコールでインシデント管理を行うために、メルコインで利用しているPagerDuty、コード管理のためのGitHub、監視に関するDatadogや一部のKubernetesのリソースに関わる設定は、Terraformで定義し、Kubernetesのワークロードに関わるリソースはCUEを使って抽象化できるようになってるので、もう少し具体的に説明していきます。 Terraformで提供しているモジュールの例としては、ここにあるようにいくつかの用途に応じて数種類あります。 microservices-starter-kitは、開発者がmicroservicesを作る際に使うキットになっています。GCPプロジェクトやKubernetesネームスペースなどが作られ、必要なIAM設定など、microservicesを作るために必要な設定が含まれています。 microservices-teams-kitは、サービスチームに関わる設定を提供していて、チームのGoogle Groupのメンバー管理や、そのチームに付与されるIAM設定、オンコールに関わるPagerDutyの設定やGitHubで使われるGitHub Teamの管理などを、これで一元管理しています。 microservices-spanner-kitは、Spanner instanceやデータベースの設定に加えて、データベースのバックアップや、Spanner autoscaler(Spanner instanceの負荷に応じてインスタンスをスケールアウトできるオートスケーラーの仕組みを独自に導入している)それらに関わる必要な設定も含めて、このキットで対応できます。 microservices-slo-kitは、そのmicroservicesのサービスレベルやSLOに応じて、Datadogの監視などの設定を行うことができるモジュールで、一つ一つ監視モニターを作らなくても良い形になっています。 Kubernetesのリソースも同様に、開発者が多くのYAMLを管理する必要があり煩雑になるため、それらを簡易化し、開発者の認知負荷を低減するために、CUEというオープンソースの言語を使って抽象化を行っています。これらによって、YAMLに比べて大幅にコードが削減されるとともに、Istioのような新しく取り入れる技術についても、開発者の負荷を軽減でき、かつメルコインとして、セキュリティや可用性の面でコントロールが利いた状態でワークロードが生成できる状態になっています。 ちなみにCUE自体はまだそれほどメジャーな言語ではないので、気になる方は こちらのブログ を参照してください。 ここまで、抽象化によっていかに開発者が簡単にmicroservicesの開発・運用を行えるかというお話をしてきました。一方であまり過度に抽象化していくと、例えば他と少し異なる設定を行いたいときに対応できず使い勝手が悪かったり、またそれらを対応するために共通化しているモジュール本体を修正する必要が出て、逆にコストが高くなる側面もあります。 そのため、メルコインだけでなくて、メルカリグループも含めて、キットを提供して抽象化しつつも、直接開発者がTerraformを記述できる自由度を持たせた形で、microservicesの開発運用ができる状態になっています。 そうすると、標準化されていないリソースなども本番環境にプロビジョニングされる可能性があるので、メルコインとしてのセキュリティや可用性などの観点から、推奨する設定、あるいはやってはいけない設定といったメルコインのポリシーを守るために、CI/CDパイプライン上で、TerraformやKubernetesのコードの検証をConftestを使って行っています。 一例としては、Shared VPCに接続するためのTerraformモジュールがあります。許可されたサービスのみが接続できるように制限したいので、事前に許可されているかをチェックしたり、TerraformでVPC Firewallを設定する際に、監査などの観点からログを出力することを推奨しているため、そのチェックを行ったり、Kubernetes マニュフェストでも、コンテナが特権モードになっていたり、ホストネットワークを使用していないかなどを検証したりしています。 実際に運用を始めると、障害対応などで緊急のオペレーションが必要なケースも出てきます。対応方法として、インフラなどの構成を変更するために行動を修正してCI/CDを通すやり方もありますが、時間がかかりすぎて復旧までに時間を要してしまいます。 またはIAMの権限を取得するのも同様に、Terraformのコードから、CI/CDを通すと、権限が付与されるまでに待たないといけないため時間がかかってしまいます。このCarrierというツールは、有効期限付きの一時的な権限を、承認をもって取得できるシステムです。 基本的にはSREや開発者は本番環境への一切の変更権限を持っておらず、必要なときにのみCarrierを使って権限申請し、SREが承認した上で、権限取得する運用を行っています。これによって、申請したときの有効期限が切れた後は、自動的に権限も取り消されるので、権限の消し忘れなどもなく、統制が取られた状態で安全に運用できます。 メルコインは、セキュリティやコンプライアンスなどの側面から、メルカリとは完全に独立したGCP Organizationとして分離されています。メルコインのmicroservicesは、共通のGKEクラスターでマルチテナントを構成しており、セキュリティなどの観点でNetwork Policyなどを使って完全に他のテナントと分離した構成です。 開発者がmicroservicesのオーナーシップを持っており、SREからインフラを抽象化したツールなどを提供することでサービスの開発と運用を促進してきました。一方で課題感としては、抽象化しているツールが増えてきたことで、学習コストや開発者の認知負荷が高くなってきてるというのがあって、それらを開発解決するために、よりシンプルなインターフェイスのようなものが必要になっています。 今後、そういった課題に対しても、より良いものを取り入れて改善していけるといいなと考えております。 本日はご清聴いただきありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 How to Unleash Fintech 」の書き起こしです。あわせて、「 【書き起こし】Keynote – Shunya Kimura【Merpay & Mercoin Tech Fest 2023】 」をご一読ください。 @kimuras:「How to Unleash Fintech」というタイトルで、パネルディスカッションを進めます。 @keigow:メルペイVP of Engineeringの@keigowと申します。私は、2016年にメルカリグループに入った後に、2018年のメルペイ立ち上げのタイミングから3年、メルペイに所属してました。2年ほどグループ会社のソウゾウという会社で新規事業の立ち上げに取り組んでいたんですけれども、この4月にメルペイに戻りました。本日は過去からのメルペイの取り組みについても触れられればと思っていて、とても楽しみです。よろしくお願いします。 @nu2:同じくVP of Engineeringの@nu2と申します。今年の5月に入社して、ちょうどオンボーディング期間を終えたばかりです。フレッシュな視点を意識して今回お話できればと思っています。 @kimuras:まず導入ですが、2019年からメルペイのFintechサービスがリリースされて、スマート払いやスマートマネー、クレジットカードサービス、ビットコインなど土台を作ることができました。利用者は約1500万人です。 特にこの1年では、メルカードやビットコインなど、大きなリリースもありました。今回はそのFintech事業にとっても、大きな技術的な成長を報告できるので、ぜひ皆さんに楽しんでいただきたいですし、参考にしていただければなと思っています。 今回は、これまで作ってきたFintechの土台を活かして、今後さらにこの価値の他のサービスも広げていきたいという気持ちでセッションを開催しています。 Fintechサービスの成長に欠かせないのは、攻めだけでなく守りの姿勢を大切にすること。便利なUIにするほどセキュリティのリスクが高まってしまうので、同時に守りも重視しなければいけません。 メルペイ創立から担当されている@keigowさんにお聞きしたいんですけども、これはFoundationプラットフォーム開発に重点を置いてきたというお話をしましたが、@keigowさんとしてはどのような考えがあったのかを聞きたいです。 @keigow:当初から完璧にできていたわけではなく、できていた部分と今でも苦労している部分があるのかなと思っております。組織の良い部分は、マイクロサービスアーキテクチャで開発を進めたこと。また、決済のコアとなるマイクロサービスを独立したチームで開発を進めることは、立ち上げ当初から意識していました。 メルペイ立ち上げから5年間、エンジニアリング組織には大小様々な変化はありましたが、その点の根本の部分は変わっていないと思います。 現状のメルペイのエンジニアリング組織は、主にProduct、Foundation、Enablingという三つの領域にわかれています。Productエンジニアリングは、新しいProductの機能開発や改善、お客さま体験の向上に直接つながる開発を行います。 続いて、先ほどプラットフォームとして表現されていたFoundation。Fintech領域で特に大事な部分、決済や残高の管理、与信の管理のマイクロサービスというところは、基本的に1ヶ所に閉じて、専任のチームをアサインして、その中で中長期を意識した開発を進めていくということは、創業当初から続けています。 最後に、Enablingチーム。これには、バックエンドやクライアントのアーキテクト、SRE、データプラットフォームの方が所属しています。横断的な技術課題の解決、生産性の向上を担っています。 こうして組織ごとに役割をフォーカスすることで、「攻め」と「守り」を意識できました。 @kimuras:初期の段階から長期的な視点も考えてきたということですね。なるべく改善しながら進めてきた、あるいは組織をそのような形にしてきたということで、うまくできた点かなと思います。@nu2さんの入社したばかりのフレッシュな視点では、どのように見えますか? @nu2:メルカリはメルペイが誕生する前から、今までずっと成長曲線を描いてきたのは、主にお客さまとお客さまが出品される品物のエンゲージメントの点と、売上金の換金という二つのプラットフォームが、Productマーケットにフィットした結果だと思います。 関係企業がグループのFintech領域を担うメルペイになり、これまで今まであまり世の中になかった決済体験みたいなのにつながって、それを提供しつつメルコインも事業を開始して、まさに価値の循環を体現していると感じていました。 機能としてはiDの決済から始り、QRコードやメルカード、即時決済、さらに清算することですぐに与信枠が回復する技術をこのタイムスパンで成し遂げてきたことは、とてつもない開発スピードだと感じました。 同時にお客さまの利用が増えていくことで、トランザクションが増量し、それに伴ってシステムのスケーラビリティがどう担保されているのかは、入社前から興味関心がありました。 @kimuras:実際に入社してみて、いかがですか? @nu2:何年も先まで見据えたアーキテクチャで、現状スケーラビリティを担保されている部分もあれば、クラウド技術に依存しているので、その辺は今後ずっと拡張していくと、コストやレスポンスに支障が出るのかもしれないということは、現場の方たちとお話しているので、そこを知恵を出し合いながら改善を重ねていきたいと思っています。 @kimuras:続いて、Fintech領域のエンジニアリング領域の面白さについてです。堅牢なシステムを作り、セキュリティを守らなければならない上でも、なめらかな社会を実現していくことは、難しくもありとても面白いことだと思います。 おふたりの、仕事のやりがいやエンジニアリングの面白さについても、ぜひ教えてください。 @keigow:一番は、お客さまに新しいサービスを提供できることです。 メルペイ自体はユニークなサービスなのかなと思っています。メルカリやメルカリShopsといった、マーケットプレイスのサービスと一体となって提供され、メルカリグループの新しいミッションが「あらゆる価値を循環させ、あらゆる人の可能性を広げる」というところで、物を売ることで得たお金を支払いに使える、そのお金を利用してビットコインを買えるといったサービスは、これまでの世の中にないものだと思っています。そのような、新しいものを提供することにワクワクしています。 @nu2:私もこれまでのキャリア的にBtoC次にBtoBtoCを経験して、今回はCtoCに携わっています。お客さまと直接向き合う点が大きいと思っています。 社会の一部をソフトウェアとして実装していく点が大きいですね。私自身、メルカリグループのミッションに非常に共感したことが入社の動機になりました。どのような行動を起こせば、なめらかなアクションをとったり、組織に対してフィクションを起こさずに済むかを常に意識しています。 また、我々のサービスは、これからもお客さまに使っていただきたいです。ビッグスケールするときに、想定しなかった技術的な課題が絶対出てくると思っています。国内外を視野に入れたビックスケールサービスを実現することに対して、非常にやりがいを感じています。 @kimuras:ありがとうございます。続いて、今回のMerpay & Mercoin Tech Fest 2023のセッションや見どころを説明してください。 @keigow:「Merpay Engineering Career Talk」というパネルディスカッションでエンジニアリングマネージャーとEngineering Headの3人で、キャリアについて話す予定です。 【書き起こし】Merpay Engineering Career Talk – Keigo Watanabe / Osamu Tonomori / Katsuhiro Ogawa【Merpay & Mercoin Tech Fest 2023】 @nu2:「Merpay & MercoinにおけるLLM活用の取り組み」と題し、発表します。私も入社後すぐに支援する形で参加したLLM技術を用いた社内ハッカソンのような取り組みがありまして、そちらで最も評価されたProductのプレゼンテーションも披露します。 今後生成AIの技術は誰もが注目している技術だと思っていますので、どのような議論が展開されるのか私も非常に楽しみです。 【書き起こし】Merpay & MercoinにおけるLLM活用の取り組み – Yuki Ishikawa / Daisuke Torigoe / Noriaki Utsunomiya / hmj【Merpay & Mercoin Tech Fest 2023】 @kimuras:続いて、見どころセッションについてはいかがでしょうか。 @keigow:一つは、「Merpay iOSのGroundUp Appへの移行」。iOSリアーキテクチャのお話しで、かなり大規模なプロジェクトなので、面白い話が聞けると思います。 もう一つは、「メルコイン決済基盤の実践話」。もともとメルペイの経験も踏まえて、メルコインの決済基盤がどのように作られているのかを詳細に話してくれると聞いているので、楽しみです。 【書き起こし】Merpay iOSのGroundUP Appへの移行 – kenmaz【Merpay & Mercoin Tech Fest 2023】 【書き起こし】メルコイン決済基盤の実践話 – Junwei Liang【Merpay & Mercoin Tech Fest 2023】 @nu2:私は「メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化」と「メルコイン決済マイクロサービスのトランザクション管理を支える技術」の2つです。どちらもマイクロサービスについてのセッションです。 なぜこの2つに注目しているかといいますと、私が入社の決め手の一つでもあるのですが、金融の取引領域にマイクロサービスアーキテクチャを採用してるのもすごくチャレンジングなことだと思っています。 なぜかというと、Network latencyなどの課題をどうクリアするかが大きいポイントだなと思っていまして、成し遂げたい世界観を構築するための技術的な挑戦を他のセッションでもあるんですけれども、マイクロサービスにフォーカスしてこの二つを取り上げました。 【書き起こし】メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化 – Cui Peichong【Merpay & Mercoin Tech Fest 2023】 【書き起こし】メルコイン決済マイクロサービスのトランザクション管理を支える技術 – Shota Suzuki【Merpay & Mercoin Tech Fest 2023】 @kimuras:個人的には、メルコインが社内でも最新のアーキテクチャを使っているということもあって、僕も楽しいと思ってますし、今回紹介できることをとても嬉しく思っております。 @kimiuras:続いて、メルペイ・メルコインの領域あるいはメルカリでもいいんですけども、どんな世界を実現していきたいか、あるいは今後どんなチャレンジをしたら面白いかなどについて、意見をお聞きできたらなと思います。 世の中を便利にするための土台はできてきましたが、これらをいろんなサービスで今後活用していくことによって、より可能性が広がっていくという考え方もありますし、世界に挑戦することも面白いかなと思います。 @keigow:Product的に今のメルペイをものすごく単純化すると、財布にお金が入ってきて、出ていく。加えてビットコインを購入し、資産運用の要素が組み合わさっていると思います。 直近の出金や決済は、iD決済から始まり、コード決済、メルカードなど、かなり整ってきたと感じています。一方で入金や運用についてはもっといろいろな可能性があると思います。物の売買だけでない入金の手段や、より手軽な資産運用も含めて、増やせる財布というか、そこにお金を入れておくことで価値が出てくるという世界観を、メルペイで実現できると面白いと思います。 エンジニアリングという観点では、高い可用性やセキュリティが求められる中で、いかに高いスピード感を持って開発していくかが非常に重要だと思います。守りはするけれど、保守的にはならない、「守りのために攻める」ということを意識したいです。 @kimuras:「保守的にはならない」ということについて、特に気をつけていかないといけないという危機感を覚えることはありますか? @keigow:守りに入ること自体は簡単ではあって、現状維持、あるいはより枯れた技術を利用すること自体は別に間違ってないんですけれども、リスクに見合ったリターンがある技術は当然あると思うので、そこは意識してアンテナを張りたいです。 リスクだけがあるのは全然良くないんですけれども、新しいことを取り入れることは意識していくことが必要な部分かなと思ってます。 @kimuras:新しいところでいうと、マネージドサービスやOSSなどを意識されていますか? @keigow:それもそうですし、LLMをどう取り入れるかは、サービスの提供という観点では面白い部分かなと思います。かなり応用の幅がありそうです。 @nu2:私はメルカリグループが掲げる価値の循環というミッションを実現するため、さまざまな価値を循環させるための基盤・経済圏にお客さまが参加したいと思える状態を作っていかなきゃいけないと思っています。 先ほどお話にあった即時決済や即時回復は今まで社会になかったものでした。我々はそれを利用していますので、どれだけ便利なものなのかを体現できると思います。まだまだお客さまに届いていないとも思うので、便利な世の中を実現して、メルカリグループの経済圏にもっと多くのお客さまに参加して欲しいです。 お客さまが増えることで、セキュリティやアベイラビリティ、レスポンシビリティに非常に高いハードルが生まれると思いますが、対応していきたいです。 @kimuras:「保守的になりすぎてはいけない」というお話がありましたが、そうならないために挑戦していきたいことや考え方はありますでしょうか? @nu2:今のクラウド技術を元にしてサービスを展開していますが、クラウド技術提供者が用意するミドルウェアを待つのではなくて、我々が新しいソフトウェア自身をミドルウェアとして構築・開発し、我々がオープンソースとして逆に提供するぐらいの勢いが必要かなと思っています。 @kimuras:「増やせる財布」「資産管理」という観点で実現してみたいビジョンはありますか? @nu2:財布の中で何を使うかというお客さま自身の情報を預からせていただくので、そこから今すでに実現している信用情報以外のことにも利用できるのではないかと思います。 ただ、あくまでお客さまの価値の循環のために利用することがデータとしてすごく重要だと思っています。 @kimuras:データの種類や量は本当に増えてきていて、データ管理のアーキテクチャも常に見直していますが、今後はデータの活用をさらに進化させていかないといけないフェーズになったと感じています。 資産管理やロイヤルティプログラムなど、今後データサイエンスも伴うようなデータ利活用が、メルペイ・メルコインの成長の一つの軸なんじゃないかなと僕も思っています。 最後に、現状の課題とチャレンジということで、やりたいこと挑戦したいこと、改善したいことがあれば、ひとこといただきたいです。 @keigow:足元の課題はたくさんあるかなと思ってまして、VPとして一番責任あるところで言うと、技術的な改善やリファクタリングをProductの優先順位として高めて推進する体制を作ることは強く意識しています。 以前よりは、議論を進めながら、ロードマップにエンジニアリングの部分を載せていくことができるようになってきているので、ここの部分は引き続き強化していきたいです。 @nu2:我々はFintechサービスをお客さまに提供する際に「安心・安全」というのを掲げているんですけれども、我々が掲げる以上、我々のシステムとしても安心・安全が求められます。 ただそれに対して一定のコストがかかるので、コストとのバランスを見ながら、いかに最適なコストで安心・安全を提供するかは課題だと思います。 @kimuras:ありがとうございます。以上でこのセッションを終わりにします。ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化 」の書き起こしです。 @pedro:私からは、「メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化」について紹介します。 まず、軽く自己紹介します。Cui Peichongと申します。社内ではSlackネームの@pedroと呼ばれています。2019年4月に、バックエンドエンジニアとしてメルペイに入社しました。現在はCredit Designチームに所属し、メルペイのあと払いやメルペイスマートマネーの請求・精算に関わるマイクロサービスの開発に携わっています。 本セッションのアジェンダはこの通りです。まず、返済基盤の現状のマイクロサービス構成について紹介します。そして、返済基盤の機能を提供するinvoiceマイクロサービスを導入した経緯を説明し、導入に伴って生じた技術負債の話もします。最後に、負債の解消となるinvoiceマイクロサービスの独立化について紹介します。 それでは、返済基盤の現状を説明します。今、お客さまに返済機能を提供しているサービスは二つあります。一つ目は、メルペイのあと払いです。 メルペイのあと払いは、メルカリでのお買い物やメルペイが使えるお店・Webサービスでの月々のお買い物の代金を翌月に支払えるサービスです。このサービスは、三つの返済方法を提供しています。一つ目は、自動引落し。接続した銀行から自動で引き落とすことで支払う方法です。それ以外に、メルペイの残高と、コンビニATMの支払い方法があります。 もう一つ、返済機能を提供しているサービスは、メルペイスマートマネーです。メルペイスマートマネーは、メルカリアプリでお金を借りられるサービスです。 メルペイスマートマネーの毎月の返済は、接続した銀行口座からの「自動引落し」と、「残高でいつでも返済」の二つの手段があります。 この二つのサービスの構成は、このようになっています。lendingマイクロサービスはスマートマネーの利用、請求額の算出、契約管理などの機能を提供しています。 deferred-payマイクロサービスは、あと払いの利用、請求金額の算出、定額払いの契約管理などの機能を提供しています。 スマートマネーとあと払いが提供する返済機能には共通部分が多いので、両方のサービスに対応できる返済機能を、invoiceマイクロサービスが実現します。 これらの返済機能を実現するために、invoiceマイクロサービスがメルペイのCommon Foundationとなるいくつかのマイクロサービスとやり取りをしています。 主に銀行接続とチャージを管理するbankマイクロサービスでチャージして、決済処理の全般を管理するpaymentマイクロサービスを通して、スマートマネーやあと払いの債権を管理するdebtマイクロサービスに債権の返済をリクエストします。 以上が、現状のマイクロサービスの構成です。実は、初期にはinvoiceマイクロサービスが存在しませんでした。ここでは、invoiceマイクロサービスを導入した経緯を説明します。 メルペイスマートマネーは、あと払いより後にリリースされたサービスです。そのため、リリースの前に返済機能を提供する必要があるのは、あと払いだけでした。 そして、返済機能専用のマイクロサービスを作る必要もなく、deferred-payマイクロサービスが返済機能を含めて、あと払いに関連する全ての機能を提供していました。もちろん、返済の機能を実現するためにdeferred-payもCommon Foundationとなるマイクロサービスも直接やり取りしていました。 この状態で、メルペイスマートマネーの開発プロジェクトが開始され、その中でいくつかのrequirementsが出てきました。まず、基本的なrequirementsは、メルカリアプリでお金を借りることができ、かつ返済できるサービスでしたが、返済機能に関していくつかの課題がありました。 まず、あと払いの自動引落しと同じ日に実行した場合は、銀行へのAPIキャパシティの制御を考慮しなければなりません。できれば、まとめて銀行へのチャージをリクエストしたいです。 そして、請求書延滞後にメルペイ残高や売上金から自動で充当したいときに、あと払いの請求書との優先順位を制御しないといけません。 このようなrequirementsのもとに、いくつかのマイクロサービスの構成案を検討しました。一つ目の案は、lendingマイクロサービスを作り、スマートマネーの利用・請求・返済の全ての機能を実装するものでした。 この案のメリットは、lendingマイクロサービスが独立しているため、独立して全ての機能の設計・開発ができます。一方で、デメリットもいくつかあります。まず、lendingマイクロサービスとdeferred-payマイクロサービスが離れていることで、それぞれ返済の機能を提供しますが、銀行へのAPIのキャパシティ制御が困難になります。また、あと払いの請求書とスマートマネーの請求書の中と順位の制御も難しくなります。 あと払いの返済機能が既に存在しているのに、lendingマイクロサービスに似た実装を行うことにもなります。 二つ目の案は、独立した返済のマイクロサービスを作ることです。lendingサービスはスマートマネーの利用・請求や契約管理などの機能だけを提供し、invoiceマイクロサービスという独立の返済用マイクロサービスを作り、最初はスマートマネーの返済を管理しますが、将来的にあと払いの返済も実装するというものです。 この案は、一番理想に近い形ですが、デメリットもあります。あと払いの返済機能のマイグレーションを実現する前は、一つ目の案と同じように、銀行へのAPIキャパシティ制御も難しいです。 invoiceマイクロサービスに返済機能を実装するため、deferred-payマイクロサービスと重複しそうです。また、将来あと払い返済機能のマイグレーションを考慮しなければなりません。 三つ目の案は、あと払いの返済機能を利用するというものです。 lendingマイクロサービスがスマートマネーの利用・請求と、契約管理の機能だけを提供し、deferred-payマイクロサービスがこれまでの責務以外にスマートマネーの返済も対応します。具体的には、deferred-payマイクロサービスの返済機能を拡張して、invoiceマイクロサービスとして、あと払いとスマートマネー両方の返済に対応します。 この案のメリットは、返済機能を一本化でき、一つ目・二つ目の案のような銀行へのAPIキャパシティや充当順位の制御に関する問題がなくなります。あと払いの既存の返済機能を拡張するため、重複の実装も少なくなります。 しかし、ご覧のように、マイクロサービスの責務と実際の構成の乖離があります。もともとdeferred-payマイクロサービスはあと払いの機能だけを提供すべきでしたが、スマートマネーの返済も対応することで、複雑になります。 最終的に、リリースのスケジュールと実現の難易度などを考慮し、初期リリース時に一時的な技術負債を覚悟した上で、案3で実装し、その後deferred-payマイクロサービスにあるinvoiceマイクロサービスを独立させる案に決定しました。 この案を実現するために、deferred-payマイクロサービスにある返済関連のデータモデルの整理・拡張が必要です。 ここで請求書のデータモデルを例に説明します。まず、あと払いドメイン専用の項目と、invoiceマイクロサービスが扱う抽象化した請求書の項目を見分ける必要があります。 例えば、smartpay_contract_idは、あと払いドメイン専用の項目です。amountやpaid_amount、invoice_monthなどの項目は、invoiceマイクロサービスとして抽象化した請求書の項目です。 それだけではなく、スマートマネーに対応するために、いくつかの項目を追加する必要があります。例えば、どのサービスの請求書なのかを判別できるように、サービスIDを追加しました。 既存の返済ロジックも、スマートマネーに対応できるように拡張しました。 そして、今後invoiceマイクロサービスの独立化を意識して、既存のインターフェースと分けて新規のinvoice gRPCサービスを作成しました。この案によって、メルペイスマートマネーを無事リリースできました。 ある程度、技術負債を覚悟しましたが、実際に運用のフェーズに入ったら、さらに実感できるようになりました。 まず、コードベースが混在することで、さまざまな影響が出ます。例えば、あと払いサービス機能を開発するときに、invoiceマイクロサービスへの影響を意識しなければなりません。反対に、新たな返済機能を開発するときに、あと払いサービスへの影響も意識する必要があります。 また、データベースが一つになることによる影響もあります。あと払いサービスの運用中にインシデントが発生したときに、データを調査する必要があります。その際、スマートマネーのデータを除外しなければならず、メンテナンスコストが上がります。 あと払いサービスの運用だけではなく、データ分析の複雑さもあります。この技術負債を解決するために、invoiceマイクロサービスの独立化のプロジェクトが開始されました。 まず、独立したinvoiceマイクロサービスを作ります。このマイクロサービスのデータモデルは、deferred-payマイクロサービスにある返済関連のデータモデルから、抽象化したものです。そして、deferred-payマイクロサービスにある、invoice gRPCサービスと全く同じインターフェースのgRPCサービスを提供します。 既存と同じインターフェースを提供することで、Customer単位で簡単にマイグレーションできました。 具体的には、Customerごとにマイグレーションの状態を管理して、マイグレーション済みの場合に、deferred-payマイクロサービスにあるinvoice gRPCへのリクエストを処理せずに、そのままinvoiceマイクロサービスへProxyします。この形にして、clientとしてのlendingマイクロサービス側は、修正しなくてもマイグレーションできるようになりました。 マイグレーションのバッチは、このような形になっています。deferred-payマイクロサービスにあるマイグレーションのバッチがCustomer単位の返済関連データを抽出し、invoiceマイクロサービスにあるマイグレーション専用のgRPCエンドポイントをリクエストし、データをinvoiceマイクロサービスのデータベースに保存します。 実際のマイグレーションの進捗は、この通りです。特に初期段階はかなり慎重にマイグレーションを実行しました。 メルペイあと払いは、割と長い歴史があるサービスなので、想定外のデータもあります。マイグレーションの比率の拡大とともに、イレギュラーなデータを検知し、改修することを繰り返しました。そして、一定期間の安定運用が確認でき次第、マイグレーションのペースを上げ、完了しました。 全てのCustomerのマイグレーションを完了した後に、clientであるlendingマイクロサービスと、deferred-payマイクロサービスの向き先を新しいinvoiceマイクロサービスへ変更できるようになります。 最後のまとめです。 マイクロサービスの開発においては、最初に理想的なアーキテクチャを作るのは難しい場合があります。その際に、技術負債を意識したマイクロサービス構成の意思決定ができ、技術負債の解消計画を立てた上で、理想のアーキテクチャを求めることがいいアプローチだと思います。 マイグレーションに関しては、段階的に実行することで安全に終えることができました。今回はマイクロサービス開発の一つの事例として、invoiceマイクロサービスの導入と独立のお話をしました。参考になれば幸いです。 以上で、本日のセッションを終わりにします。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 メルカリへのFIDO導入の経緯とこれからの展望、課題から得た学び 」の書き起こしです。 @koi:みなさんこんにちは。「メルカリへのFIDO導入の経緯とこれからの展望、課題から得た学び」を始めます。 このセッションではFIDOの概要をある程度ご存知で、これから導入しようとしている方、実際に導入を進めようとしている方に向けて、メルカリで直面した課題や面白さをディスカッション形式でお届けします。 @daichiro:私はメルコインiOSチームの@daichiroと申します。2019年にメルペイに入社して、2021年からメルコインで業務を担当しています。メルペイ時代にdアカウント連携などの機能を実装し、その後iOSの認証認可を担当し始めました。メルコインでは、主に口座開設周りを担当しています。今日はよろしくお願いします。 @hidey:メルペイAndroidチームの@hideyです。2018年にメルペイに入社し、メルペイをリリース後しばらくはメルペイの支払いタブの実装などを担当していました。最近はメルペイAndroid全体の技術的負債の解消などを行っています。FIDOの開発では、主にAndroid側の実装を担当しました。今日はよろしくお願いします。 @kokukuma:@kokukumaです。僕はメルカリの認証認可に関連するIDPチームに所属しています。FIDOについては、メルカリの中にどう適用していくかを考える全体設計に関わっています。 @koi:私はメルカリでIDPチームのプロダクトマネージャーとして働いています。FIDOの実装時期から現在も引き続きFIDOに関わる仕事を中心としています。本日はモデレーターとして本セッションを担当します。 このセッションでは、冒頭10分ほどは私から説明パートとしてメルカリのFIDO・パスキー導入のステータスや今後の展望について紹介し、後半の20分をディスカッションパートとして、登壇しているエンジニアのみなさんと、テーマに沿った議論をします。 さっそく、説明パートに入っていきます。ではメルカリのFIDO/パスキーについての、現在のステータスです。 そもそもメルカリがFIDOのサポートをするモチベーションとなったのは、新サービス・メルコインの立ち上げが大きなきっかけでした。 暗号資産交換業を開始するメルコインでは、高いセキュリティ要件を満たす必要がありました。そのためまずは、メルカリアカウントにログインした状態を前提に、メルコインサービスを使うための認証としてFIDO認証を提供しました。 現在はメルコインだけではなく、SMS認証を利用している機能にもFIDO導入を進めており、現時点では電話番号の変更、メール・パスワードの変更、あんしん支払い設定においてFIDOの登録を行っているユーザーが、FIDO認証を利用可能という状況になっています。 メルカリがFIDOをサポートしている環境については、こちらでまとめています。アプリを先行してサポートしており、Webについては現在対応中です。いわゆるSynced passkeyをサポートしているバージョンはiOS16〜/Android 9〜で、メルカリのアプリのサポートバージョンと差があるといった点は、ディスカッションポイントとして後半に持っていきたいと思います。 リリース後の実績にも触れたいと思います。現在、FIDOCredentialの登録者は104万人となっています。その中で認証成功率、成功するまでの所要時間をSMS OTPと比較した表がこちらです。 認証成功率はSMS OTPと比べて14%ほど高く、所要時間は4分の1程度。SMS OTPと比較するとFIDOでの認証はお客さまにとって良い体験を提供できていることがわかります。 また、ディスカッションに入っていく前に、メルカリでお客さまとのコミュニケーションを行う上で、便宜上定義している言葉をこちらにまとめてみました。FIDO Credentialの設定ページとして「生体認証画面」、FIDO CredentialをそれぞれDevice-bound passkeyを「生体認証」、Synced passkeyを「パスキー」と表現しています。 @kokukuma:補足ですが、今のメルカリはかなりニッチな状況です。現状の一般的なパスキーの導入としては、「Webのログインに対して、あくまでオプショナルな機能として導入する」だと思います。WebアプリケーションならWebで開くし、ネイティブアプリケーションでもログインはin-appブラウザが開くので基本的に認証機へのアクセス方法はWebAuthn APIを使う、ログインに使うものなのでパスキーが使えなかったときの認証方法としてパスワードや他の認証方法は残す、と言ったような感じです。 ただメルカリの場合、メルコインというサービスにおけるビジネス的要求を満たすためにFIDOを導入しています。メルコイン自体は同じメルカリアプリの中にあり、メルカリのアカウントでログインした後に使えるので、FIDOの適用箇所はログインではなくて再認証やステップアップ認証です。 メルコイン自体はWebでなくアプリで提供されるものです。かつ、メルコインを使うにあたって認証するためにブラウザを立ち上げるようなUXの悪い仕様にはしたくないという話もあったので、WebAuthn APIではなく、NativeAPIを使います。 また、メルコインにおいては、フィッシング被害をできる限り軽減したいという考えから、パスワードやSNS OTPではメルコインを使わせない方向性です。そのため、メルコインのビジネス要件を満たすために、今のこのメルカリの状況があるので、一般的なパスキーの導入状況とは異なります。 ちなみに一般的な状況で言うと、Web+DBのパスキーの特集がすごくよくまとまっているので、参考になると思います。 参考記事 https://www.w3.org/TR/webauthn-2/ https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys/ https://developers.google.com/identity/fido/android/native-apps?hl=ja @koi:前提を踏まえて、今後の展望としては、利用箇所の面では他にも存在しているSMS認証の実施箇所で、FIDOを利用できること。また並行して、お客さまにFIDOを利用していただくため、登録率・利用率の拡大を実施していく予定です。 また、セキュリティを担保することを前提に、利便性の良い認証方法を提供し、安心安全にサービスを利用できる世界を実現したいと思います。 説明パートは以上です。では早速、本編のディスカッションパートに入っていきます。 @koi:トピックはこちらです。「実装で困ったところ」「分かっていれば避けられたのに話」「技術的に面白かった話」を1個ずつ話していきたいと思います。 こちらの図に沿って進めていきます。 最初のトピックは、実装で困ったところです。最初にiOSを担当した@daichiroさんに話を聞いてみたいと思います。メルコインはメルカリアプリのサポートバージョンと同じというところで、冒頭iOS14からギャップがあるというお話をしました。その点についてどのような苦労がありましたでしょうか? @daichiro:トピックは、大きく分けて二つあります。一つ目は認証の実装が大変でした。「Authenticator」のところでは、端末が秘密鍵を作って署名をしています。 iOS SDKが提供しているFIDOの認証器がiOS16以降でしか使えない中、iOS14をサポートしなければいけない状況でした。そこで、フルスクラッチで実装をし、iOS14・15の端末については自作の認証器で認証しました。W3Cが仕様を出しているのですが、仕様書とにらめっこしながら、バイナリデータをやり取りするという慣れないことに取り組みました。 二つ目は、マイグレーションです。iOS14・15で自作の認証器を使っていたお客さまが、機種変更やアップデートをしてiOS16になると、Appleが提供するFIDOの認証器を使うようにしないといけないのですが、そこの場合分けや、自作のものとAppleが提供したもののインターフェースが違うと作業が多くなりそうでした。 インターフェースについてはW3Cの仕様に沿っていたので、そこまで苦労することはありませんでしたが、マイグレーションをする必要のあるパターンが多く、そこも大変でした。 @koi: Androidはいかがでしょうか? @hidey:AndroidはiOSと違って認証系の実装の部分は、公式のライブラリでアクセスするものがGoogleから提供されているので、その部分の苦労はありませんでした。一方、ライブラリでラップされているエラーのハンドリングは、少し大変でした。 ひとつハマったのが、Googleの開発者サービス経由で認証器(Authenticator)にアクセスする際、そのバージョンに依存して発生したエラーです。これはリリース前まで見つけられなかったので、本番障害が出てしまいました。 @koi:続いて、サーバーサイド側での苦労というのもあれば聞いてみたいなと思います。 @kokukuma:実装ではそんなに苦労したわけではありませんでした。ただ、設計かつ現在進行系で困っているのは、メルコインのためにFIDOを導入しフィッシング耐性を強化したことで、いろいろな弊害が出ていることです。 フィッシング耐性のために二つ目の鍵の登録もパスキーで守る仕様にしたため、UXに支障が出ています。例えば、パスキーが使えずメルコインが使えない、二つ目の鍵を登録できないという問い合わせが発生しています。その辺りは困っていますね。 一方で、メルコインにおいてパスキーの利用を強制したこと自体は、我々がそんなに訴求しなくてもメルコインの訴求につられて鍵の登録数が上がるという副次的なメリットがあったので良かったと思います。 @koi:次のトピック「分かっていれば避けられた話」に移ります。@daichiroさん、いかがですか? @daichiro:自作認証器は本当に大変なので、止めた方がいいと思います。(笑) もちろんリリースする前にQAやデバッグはめちゃくちゃしましたが、それでもリリースするときに不安になって精神的に良くなかったですね。ただ、サービスをどうお客さまに提供するかは大事なので、今からやるなら自作認証器はなるべく使わずに、iOS16以降で対応することができたと思います。 もう一つは組織的な話になります。メルカリ・メルペイ・メルコインそれぞれのカンパニー間のコミュニケーションで苦労したことがありました。僕があまり英語に慣れてないこともあり、伝えたいことが伝わらずに、時間を無駄にしたという反省があるので、あまり普段一緒に仕事しないメンバーと仕事をするときはもっと丁寧にコミュニケーションをした方がよかったと思います。 @hidey:コミュニケーションに関しては、もっと丁寧にやればよかったと思いますね。 Androidの話でいくと、少し趣旨はずれますが、Synced passkeyのみのサポートでよければもう少し楽になったと思います。リリースタイミングとも関わるので、致し方ない部分でもありますが、できればSynced passkeyのみの対応にすると、最終的な実装も楽になって綺麗に実装できたと思います。 @kokukuma:それは完全にあります。最初は Device-bound passkeyの状態で出して、後からSynced passkeyに移行したのですが、やはりDevice-bound passkeyを使っているお客様からパスキーが使えなくなったというお問い合わせは比較的にきやすいので、最初からSynced passkeyにしておけば、こういうことにはならなかっただろうなと思います。 @koi:最後のトピックは、「技術的に楽しかった話」です。FIDOという新しい認証技術に触れてみなさんが思ったことを、ぜひ聞きたいです。 @kokukuma:FIDOをきちんと利用しようとすると、どうしてもアカウント登録やログインのUIに言及せざるを得なくて。それがきっかけで今のメルカリの登録の導線を改善するきっかけになったのはよかったですし、ワクワクしてます。 @daichiro:個人的な意見ですけど、スマートフォン開発をする上で、スマートフォンの機能を使ったものは、とてもやりがいがあるなと思います。 今回の自作の認証器で言えば、秘密鍵の生成や生体認証は端末を持っていないとできないことですし、iOS16以降の対応のときも、最新のAPIを使っての実装だったのでちまたに資料がない状態で作るのはチャレンジングでした。やりきった後は、成長を実感しました。 それから、認証機能はアプリの中でも使う人がとても多い機能で、サービスにとってインパクトがある機能だと思います。そんな開発に携われたことについては、とてもやりがいがありましたね。 @hidey:個人的には、新しい技術の導入は、それ自体が楽しいという感覚はあります。このプロジェクト自体が割と楽しんでやれたとは思ってます。組み込むときにどういう動作になるのかという調査から始めたのですが、調査自体も楽しめました。 認証回りは数年に1回くらい関わることがあるのですが、毎回前回と比べて新しい技術の進化を感じられるのが、刺激的で面白いなとは思ってますね。 @koi:ありがとうございます。さまざまな苦労もありつつ、みなさん成長できる点が感じられ、いいお話を聞けたかなと思っております。質問が一つきてるのでまとめをさらっと終わらせてから、そちらに触れていきたいなと思います。 まとめとしては、iOS15以下をサポートする場合は、独自実装が発生するのでハードな面もありました。FIDOを実際にプロダクトにどう絡めるのかを考えるのは楽しいです。 また、見え方としては地味でも、多くのお客さまに使ってもらう機能のためやりがいがあるという、いいところも聞けました。 ここで、「他社サービスではWebアプリでパスキーに対応する方式も見られますが、ネイティブアプリから使うことは検討されなかったのでしょうか?時期的な話や接続する部分の実装の懸念点があったならば聞きたいです」という質問が来ています。 @kokukuma:確かにその時、iOSでNative APIが一般的には使えなかったので、自前で実装するか、それともWebAuthnを扱うかという話になっていました。結果的に自前に寄せようとなった理由は、メルコインにおけるUXです。特にメルコインでは、お客様が何かしらの操作をするときに追加で認証を要求するという形での利用が主だったので、その操作の間にブラウザ立ち上げて認証だけして落とすという体験が非常に悪かったというのが理由です。 @koi:では、以上でパネルディスカッションを終わりたいと思います。それではご視聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 なめらかなFintech QAを実現するために テストケースフォーマットを標準化した話 」の書き起こしです。 @satomasa:「なめらかなFintech QAを実現するために テストケースフォーマットを標準化した話」ということで、ここ半年ほど、主に私と@y-sakamotoさんで取り組んだ内容について説明します。 @satomasa:メルペイでQAエンジニアをやっている@satomasaと申します。よろしくお願いします。 @y-sakamoto:同じくメルペイでQAエンジニアをしております、@y-sakamotoと申します。よろしくお願いします。 @satomasa:まず、メルペイQAチームの体制から説明させていただきます。QAチームはQA1・QA2・QA3の3チームにわかれています。それぞれのチームは社員とビジネスパートナーさんで構成され、メンバーはメルペイに存在する各プロダクトにアサインされる形で日々QAの活動を行っております。 メルペイにはいろいろなプロダクトが存在することもあり、QAへのやり方もいろいろあります。バックエンド、フロントエンド、クライアント、QAのプロセスもさまざまです。例えば、テストケースを使わないケースもありました。 また、プロダクトがたくさんあるため、各プロダクトチームの体制も状況もさまざまです。アサインされたチームの状況によって、各QAメンバーが工夫しながらテストケースを進化させていました。そのため、テストケースのフォーマットがチームごとあるいはメンバーごとによっても違う状態でした。 テストケースのフォーマットが標準化されていない状態が続くことで、いくつかの課題が見えるようになってきました。 例えば、アサインチーム変更時のオンボーディングコストが高いこと。例えばプロダクトAからプロダクトBのチームに異動になった場合に、新しいチームのテストケースに慣れる必要があったり、テスト実施時に検出した不具合が管理されていなかったり、チームごとにテスト結果の記載方法が違うため、品質状況を把握するために必要な情報の取得が難しいという問題もありました。 また、QA完了時のテスト計画報告書を作成する際に工数がかかっていました。テスト結果の集計がされていないなどの理由により、QAを完了した後に改めてテスト結果を集計する必要がありました。 以上のような課題を解決するために、テストケースフォーマット標準化プロジェクトが立ち上がりました。 テストケースフォーマット標準化プロジェクトで取り組んだ内容について順番に説明します。 まず、プロジェクト方針の決定ということで、決めたことはいろいろあるんですが、一部を紹介します。 まず、どこまでフォーマットを標準化するかに関しては、当初は「最低限のルールだけ決めて、それぞれのチームである程度自由に変更ができるフォーマットにしよう」ということにしました。 この部分については、後に方針を変更しました。各チームのテストケースを見比べたところ、意外とフォーマットに違いがなかったことと、自由度が高いと、結局バラバラになり、目的を達成できないリスクがあるためです。そこで固定化のフォーマットを作るという方針に変更しました。 プロジェクトの活動方針についても決めました。weeklyでmtgを1時間開催することにし、この時間で、進捗の共有だけではなくて、プロジェクトの作業を行うことにしました。 私も@y-sakamotoも、通常のQA業務を並行して行っているので、このプロジェクトに関わる時間をあらかじめ確保しておくことで、プロジェクトの業務が停滞することがなかったと思います。 次に、各チームのテストケースフォーマットの調査を行いました。 各チームの代表的なテストケースをサンプリングして、10種類ほど集めました。サンプリングしたテストケースをメンバーで比較した結果、各チームでいろいろなテストケースのフォーマットが使用されていることと、基本的な部分についてはあまり違いがないということがわかりました。これによって、どのようにテストケースフォーマットを標準化していくべきかが何となく見えてきました。 次にドキュメントの作成を行いました。今回のプロジェクトで作成したドキュメントは大きく三つあります。テストケースフォーマット、テスト結果集計、運用プロセスです。こちらのドキュメントの詳細は、後ほど説明します。 次にトライアルの実施を行いました。ドキュメントの作成が一通り終わったタイミングで作成したルールやフォーマットが運用に耐えられるかを試すために、トライアル期間を設けました。 まず新しいフォーマットを試してもらえるチームを募集し、実際に運用してもらい、気づいたこと・改善してほしいことをフィードバックしてもらいました。 その内容を、自分と@y-sakamotoさんで確認して、必要に応じてドキュメントを更新しました。トライアル期間でいくつかフィードバックをもらいましたが、運用上、大きな問題が発生しないってことがわかったので、バージョン1.0のリリースに向けて、さらにドキュメントの精度を上げていくことになりました。 いよいよバージョン1.0のリリースとなります。トライアル期間で出たフィードバックを元に修正をして、バージョン1.0としてリリースしました。ただ全チームで一斉に新しいフォーマットに切り替えることが難しいので、切りのいいタイミングで新しいフォーマットへの移行をお願いしました。 プロジェクトの立ち上げが2022年12月で、バージョン1.0のリリースが2023年4月と5ヶ月ほどかかりましたが、何とかリリースできました。 現在は、運用のフェーズとなっております。 運用フェーズでもフィードバックシートを用意して、実際に使ってみて感じた点や疑問点、不明点を書いてもらっています。運用フェーズでもweeklyのmtgは継続していて、新しいフィードバックがあれば、メンバーで議論して、改善が必要な点は、ドキュメントを更新しております。 次に、今回のプロジェクトで作成したドキュメントについて説明します。 @y-sakamoto:私の方から、テストケースフォーマットについて説明します。まずは目的を明らかにしました。先述の通り、今まではチームごとにフォーマットが異なっていたため、品質の分析に必要な情報が得られないケースもありました。 例えば、Aチームのテストケースにある項目が、Bチームのテストケースにはないため、最終的な品質分析を行う際に、Bチームのメンバーにヒアリングをして必要な情報を得るという、無駄な工数がかかることもありました。 またフォーマットが統一されることによって、チーム異動が発生した場合も、改めて異動先のフォーマットに慣れる必要がなくなるため、浮いた時間はドメインキャッチアップなど、よりオンボーディングでフォーカスしたいことに当てられると考えました。 続いて、我々はテストケースの項目とレイアウトを作成しました。テストケースに記載すべき必須項目については、検証観点や環境、エビデンス、確認手順、期待する結果など一般的なものを設定しました。 しかし、チームや検証対象によって必要な情報というのは異なりますので、必須項目以外にも、各チームの判断で項目を追加して良いというルールになっています。 また弊社ではイングリッシュスピーカーの方にテストケースのレビューをお願いすることもあるため、一部を英語化してレビューしやすいように言語面でも工夫を加えています。 メインとなるテストケース以外にも、必要なシートを作成しました。一つはバグ一覧シートです。 これまでは検出したバグを各チームおのおのが定めた場所で管理をしていました。しかし、チーム横断で行われる大規模な開発などでバグ集計をするときは、異なる管理場所を確認をしなければならず、バグを集計するだけでもコストがかなりかかっていました。そこでフォーマット内にバグ一覧シートを作成して、そこさえ確認しにいけば良いという形にしました。 次に自動テスト結果シートです。こちらはリリースの際に実行した自動テストの結果を残すシートになっています。 これまでは自動テストの結果をどう残すのかが定まっていなかったので、テストの証跡として十分ではありませんでした。しかし、実施した場合はこのシートに結果を残すと明確にルール化したことで、きちんと自動テストが実行され、QAもその結果を確認しているという証跡が間違いなく残るようになりました。 @satomasa:次にテスト結果集計について説明します。結果集計を必須にすることで、各チームの品質状況の把握の効率化と一定のルールに沿った集計結果シートをあらかじめ作成することで品質報告書の作成を効率化することが目的となります。 具体的に決めたルールとしては、テストケースの結果に使用する種別をOK・NG・Resolved・対象外・保留の五つとしました。特にNGだったテストケースがOKになった際に使う「Resolved」は各チームでルールがバラバラだったので、今回の標準化で統一された部分です。 テスト結果で集計する項目も決めました。 具体的には、項目数、実施対象項目数、OK、NG、Resolved、対象外、保留、進捗率、完了率、残項目数の10項目としました。項目も決めたのと、各項目の計算方法も、今回決めたので、チームによって、進捗率の計算方法や実施対象項目数のカウント方法が違うことがなくなり、全チーム同じ結果が集計できるようになりました。 現在、メルペイではこの集計シートを使ってテスト結果を管理しております。 次に、運用プロセスです。今回定めたテストケースフォーマットを正しく運用するために、運用プロセスを定義しました。 テスト実施中に検出した不具合をバグ一覧シートにまとめる、自動テストの結果を自動テスト結果シートに記載する、などの内容が書いてあります。運用が正しく行われているかを確認するために、チェックリストも作成しました。 テスト完了時にチェックすることで、テスト完了時にも、ルール通りに運用されているかの確認を行っています。 @y-sakamotoさん、良かったところはいくつかあると思いますが、何かありますかね。 @y-sakamoto:僕はテストケース設計するときに毎回フォーマットに悩む時間が少なからずあったので、フォーマットがすでに用意されていることで無駄な考える時間が数が減って、テスト観点出したり、設計時に本当にやるべき作業により集中できたと思います。 @satomasa:テストケースレビューの効率化もできたと思います。テストケースレビューは、開発の人も担当することがあるので、QAエンジニア以外にもメリットがあったと思います。 @y-sakamoto:フォーマットがバラバラだと、違うチームからレビューを頼まれたときにどこを見たらいいかわからないこともあったので、フォーマットが統一されているとレビューは確かにしやすいですね。 パートナーさんにも聞いたのですが、フォーマットが統一されたことで進捗状況が一目でわかると好評で、私も嬉しかったです。 @satomasa:それから、チーム異動時のオンボーディングコストの削減。今のところチーム異動が行われるケースはありませんが、削減される見込みです。 次に苦労したことです。難しい点は、やはり全ての要求を満たすテストケースフォーマットを作ることでした。 @y-sakamoto:全員の意見を盛り込もうとすると、情報過多になりフォーマット化した意味がなくなることもあると思います。意見を取捨選択することも難しかったです。 また、意見を反映しなかった場合に、「意見をくれた人にどうやって説明しよう」という大変さもあったかなと思います。 それから、最初の方針決めるときに、例えばバックエンドとクライアントという性質が違うものを同じフォーマットにまとめる運用と定めましたが、その判断は勇気が必要だったなと思います。 性質が違うものを同じケースでうまくやれるのかという不安はありましたが、意外に使ってみると大丈夫だったので一安心でした。 @satomasa:自分も@y-sakamotoさんも通常のQA業務を抱えつつ、こちらのプロジェクトに参加してたので、業務が忙しいときはこちらのプロジェクトに関わる工数が確保できず苦労しました。 @satomasa:今回のプロジェクトを通じて、思わぬ効果もありました。 具体的には、QAチーム内でのコミュニケーションが活性化されました。現状のQAチームの体制上、各プロジェクトチームに配属になっているので、なかなかQAメンバーでコミュニケーションを取る機会が正直ありませんでした。 一つのことにQAメンバーで取り組む機会がなかったので、今回のプロジェクトを通して、今までコミュニケーションが取れていなかったQAメンバーとも、コミュニケーションが取れるようになったのが大きかったかなと思ってます。 @y-sakamotoさんとも所属しているプロダクトチームが違うので、これまではあまり話したことがありませんでしたが、今回のプロジェクトを通してコミュニケーションが取れたと思います。 @y-sakamoto:そうですね。プロジェクトが違うと、長い間一緒に何か一つのことをやる機会がなかったので私も@satomasaさんとこの標準化のプロジェクトをやれてよかったかなと思いますし、これからのQA業務やまた何か一緒にやろうってなったときもよりスムーズにできると思います。 @satomasa:最後に、今見えている課題と、今後取り組んでいきたいことを紹介します。 まずは全チームへ浸透させたいです。多くのチームに使ってもらうことで、いろいろなフィードバックを得られるので、それを参考にしながらよりよいフォーマットを作りたいです。 今後取り組んでいきたいことは、テスト結果報告書の自動作成です。テストケースフォーマット等や集計結果を標準化したことで、テスト結果報告書に必要な情報が収集できるようになりました。 その情報をもとに、テストが終わったタイミングで、テスト結果報告書を自動作成できる仕組みを作れたらと思います。 @y-sakamoto:自動作成を実現できたら、ものすごく工数削減になると思います。 @satomasa:以上が、テストケースフォーマット標準化プロジェクトで取り組んだ内容です。ご清聴ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 発生可能な取引の属性データを用いた素早い不正検知 」の書き起こしです。 @Liu:みなさん、こんにちは。本日のプレゼンテーションにお越しいただきましてありがとうございます。 本題に入る前に、簡単に自己紹介をさせてください。私は2019年10月に機械学習エンジニアとしてメルカリに入社し、不正防止システムの開発に関わっています。 @Li:私は@Liです。私は2017年4月にヤフー株式会社に入社し、ソフトウェアエンジニアとして働いていました。2019年1月からは機械学習エンジニアに軸足を移し、2021年9月にはメルカリに入社しました。現在は機械学習プラットフォームの構築に関わり、最近ではFeature StoreやGraphDBなどの技術開発に取り組んでいます。 @Liu:ここでは、不正防止モデルとテクニックをご紹介しております。関心がある方はブログの記事をご覧ください。 参考記事 不正検知システムに機械学習を導入してコストマネジメントを実現した話 ML technique used to detect ChargeBack in Merpay つながりをデータから解き明かしたい ~ 複雑ネットワークの世界とそれを活用した不正検知の紹介 そしてここにいくつかの過去のイベントがございます。 参考資料 Using Feature Store and Vertex Pipelines in Fraud Prevention System Feature StoreとVertex AIを使った機械学習基盤の実現 グラフ理論と不正対策〜つながりをデータから解き明かしたい それではプレゼンテーションの主要なポイントに注目をしたいと思います。主に5つをカバーします。 まず最初に背景について説明します。私たちの不正検知の戦略は、大きく二つに分けられます。事後検知と即時検知です。 事後の検知とは、不正な取引が行われた後に発覚し、商品の配送を停止するなどの措置を取り、不正の被害を防止することです。すでに配送完了とされている商品もあるため、不正を見逃す可能性があると言われています。 一方、即時検知は取引の進行中に検知する方法であり、不正行為が発生した場合には素早く対処することができます。応答時間は0.1秒の場合もあります。 即時の不正検知を実現するためには二つの重要な要素があります。 まず、TnSのバックエンドチームが提供するJudgeサービスがあります。このサービスは超高速な不正防止システムであり、低遅延の設計がなされています。 次に、機械学習チームが開発した不正関連の機械学習ソリューションがあります。このソリューションは、潜在的なリスクランクを1分から1日の単位で算出し、Judgeサービスに提供します。機械学習ソリューションとJudgeサービスの不正防止システムを組み合わせることで、私たちはさまざまな不正取引をニアリアルタイム(Near-Realtime)で検知し、防止することが可能になります。 参考記事: 「0.1秒でも遅ければ、お客さまを守れない」不正検知領域に挑むメルペイのエンジニアが日々感じる“奥深さ このような背景を踏まえて2つ目のアジェンダに移りたいと思います。 これは不正検知をニアリアルタイムに加速するためのメカニズムです。取引が完了する前に潜在的な取引のリスクランクを算出し、提供することで、プロアクティブなアプローチで不正リスクを低減することができます。 これを実現するための鍵は、取引が発生したり完了したりする前に存在している属性データを活用することです。 このデータには、アイテム情報や、セラー情報、バイヤー情報などの重要な詳細が含まれています。これらの情報は、潜在的な取引のリスクを評価するために必要です。このデータを分析することで、不正取引の可能性を予測し、事前に対策をとることができます。 これによって私たちの不正検知システムをプロアクティブで効率的に改善しています。そして全てのお客さまに安全な体験を提供することを保証しています。 私たちの仕組みは主に3つのステップで構成されています。まず、機械学習モデルを活用して、属性データに基づいて潜在的な取引のリスクランクを計算します。その後、潜在的なリスクランクは計算が完了するとJudgeサービスに送られ、不正判定に使われます。 Judgeサービスは、継続的に進行中の取引をリアルタイムでチェックし、送られたリスクランクを使って潜在的な不正取引を特定します。このプロセスにより、私たちは不正取引が被害をもたらす前に発見し防止できるようになります。 私たちのMLソリューションでは、元々バッチ予測を行いましたが、この方法には一つの課題がありました。バッチ予測する前に取引が終了してしまった場合、検知が取引の終了後になり、防止対策に手遅れが生じる可能性があります。 この課題を解決するためには、取引が終了する前に潜在的なリスクランクを計算し、Judgeサービスに送信する必要があります。つまり、既存のバッチ予測では手遅れになる取引を検知するために、不正検知プロセスを加速する必要がありました。それには、バッチ予測よりも早い検知方法が必要でした。 不正検知プロセスを加速するために、私たちは既存のバッチソリューションにストリームソリューションを導入して、ニアリアルタイムの検知を実現しました。この新しいソリューションでは、Feast Online StoreとStream予測システムを作り、利用しています。これによってデータ処理と予測をニアリアルタイムで行い、より効率良く不正検知を行うことができます。 プレゼンテーションの三つ目の要素・システムアーキテクチャに進みたいと思います。 システムアーキテクチャは、さまざまなコンポーネントを統合し、スムーズで効率的な検知プロセスを保証しています。 アーキテクチャは、四つのパートで作られております。 まず、Feature Storeですが、これについては次のパートで@Liから紹介されます。そして次がバッチシステムで、Vertex Pipelinesを使用して実行されています。ストリームシステムではマイクロサービスを活用して、ニアリアルタイムの処理を行っております。 そして、Publish APIを使って最終的な計算結果をJudgeサービスに送ります。このアーキテクチャにより私たちは潜在的な取引のリスクランクを予測・計算し、提供することができます。 バッチシステムは、大規模なデータ処理やモデル予測する上で重要な役割を担っており、膨大な過去データをもとに効率的にリスクを計算することができます。 バッチの実行管理はCloud Schedulerによって行われています。これにより1日または1時間単位で予測をスケジュールし、トリガーすることができます。また、データ処理とモデル予測にはVertex Pipelinesが使用されています。 データは、SpannerとBigQuery上で保存・管理されています。 次がStream Systemです。 Stream Systemは、3つのマイクロサービスから成り立ちます。まず、複数のサブスクライバーを持つワークロードサービスです。次に、特徴量の取得と挿入を担当するAPIサービスであるFeature Serverがあります。そして最後に、ML予測やロジック処理を行うサービスがあります。特徴量データと予測結果などはSpannerを用いて保存と管理がされています。 こちらはマイクロサービスが連携・動作しているフローを示したシーケンス図です。 Publish APIは、潜在的なリスクランクの計算結果をJudgeサービスに送信する役割を担っています。Outboxに保存されているリスクランク情報は、Publish APIにリクエストしてPublishします。 こちらはOutboxに格納されているデータフォーマットです。中には、Pub/Subに必要な情報が含まれています。また、Publishされたかどうかを判定するフラグ情報や、「この時間までレコードを送信しないように」指示するschedule TIMESTAMPも含まれています。 Publish APIは、Cloud Runにデプロイされ、以下のように使われています。 Publish APIは計算された潜在的なリスクランクをPub/SubのMessageとしてJudgeサービスに送信します。 バッチシステムからの計算結果は、Outboxに定期的に蓄積されます。Cloud schedulerは1分ごとにPublish APIがJudgeサービスに対してOutboxのデータをPublishするようトリガーします。Stream Systemの計算結果は、専用のPub/SubからPublishされます。Publish APIは送られた計算結果をSubscribeし、JudgeサービスにPublishします。 こちらでは、Public APIの仕組みを示しています。興味のある方はぜひご覧ください。 私からのメッセージは以上になります。ありがとうございました。 @Li:それでは、続いてFeature Storeについて説明します。 Feature Store (FEAST) は主にデータの入力部分を担当しています。特徴量テーブルの管理やモデルのトレーニング、予測に必要なデータを提供します。データはBigQueryとSpannerに保存されており、モデルのトレーニングやバッチ予測用のデータはOffline Store (BigQuery)から、オンライン予測用のデータはOnline Store (Spanner)から提供されます。 先ほど不正検知のためのストリーム予測が紹介されましたが、ニアリアルタイムでの不正検知を実現するためには、推論だけでなく、特徴量の取得もニアリアルタイムかつ低遅延で提供する必要があります。そのために、私たちはFeast Online Storeを導入しました。 まず、Feature Storeがどのような役割を果たすのか、簡単に紹介させてください。 この図は、Feature Storeのない典型的なMLインフラの一部を示しています。Feature Storeがないと、データソースへの接続やデータ処理のコードなど、同じコードが複数のトレーニングジョブ間で重複してしまい、冗長になります。また、特徴量の処理フローはトレーニングとサービングのプロセスに埋め込まれているため、特徴量の再利用が容易ではありません。 そのため、データサイエンティストはモデルを構築する際、データストアにアクセスするための低レベなコードを書く必要があり、データエンジニアリングのスキルが求められます。 参照: https://www.hopsworks.ai/post/feature-store-the-missing-data-layer-in-ml-pipelines この図は、Feature Store導入後の概要を示しています。Feature Storeを使用することで、データソースとモデルの間の特徴量を一元的に管理し、全ての特徴量を一箇所に保存・管理し、異なるモデル間で再利用することができます。 データサイエンティストは簡単に特徴量を検索し、それらを使用してモデルを構築することができます。一方、MLエンジニアはモデルの管理に集中することができ、データエンジニアは特徴量の作成と管理に専念することができます。効果的な役割分担が可能となり、生産性が向上します。 Feature Storeの中には、Online StoreとOffline Storeという2つのコンポーネントがあります。これらは主に異なる目的で使用されます。 Online Storeは、オンライン予測時に特徴量を提供するために使用されます。対象の最新特徴量のみを保存し、低遅延のアクセスを可能にすることで、特徴量値の迅速な取得を最適化しています。 一方、Offline Storeは大量の過去データを保存・管理することに特化しており、バッチ予測やモデルトレーニングジョブに活用されます。 これらの2つのコンポーネントは、効率的かつ効果的な特徴管理を提供するために協力して動作します。 Feature Storeのアーキテクチャはこちらのようになります。 データ自体は、BigQueryやSpannerなどのデータストレージに格納されています。Feature Storeは、中間層として機能し、特徴量へのアクセスを簡単かつ整理された形で提供します。 まず、Online Storeを見てみましょう。 Online Storeには、2つの異なるデータ収集方法があります。1つ目は、Kafkaから流れてきたデータをFlinkが処理し、処理済みのデータがFeature Server APIを介してOnline Storeに取り込まれる方法です。2つ目は、Offline StoreからデータをOnline Storeにマテリアライズする方法です。 なぜなら、一部の特徴量はリアルタイムではなく、直接的にKafkaから取得することができないため、Offline Storeからデータを取得して必要な特徴量セットを揃え、予測時に提供する必要があるからです。マテリアライズジョブはCloud Schedulerからトリガーされます。 Offline Storeに関しては、データ変換ツールであるdbtを使用して特徴量テーブルが作成および管理されます。 先程、Online Storeへのデータ取り込み方法について2つ存在すると話しましたが、ではいったいどの特徴量はマテリアライズし、どの特徴量をストリームで取り込むべきでしょうか。 基本的には、リアルタイムで取得可能な特徴量はストリームで取り込み、処理するべきです。一方で、集計された特徴量などのリアルタイムではない特徴量は、Offline Storeからマテリアライズするのが適しています。 もちろん、すべての特徴量をOnline Storeにマテリアライズすることも可能です。その場合、モデルのパフォーマンスは基本的にバッチ予測と同様になります。 マテリアライズジョブの実行方法には、定期実行とオンデマンド実行の2つがあります。 定期実行では、主にCloud Schedulerがトリガーとして活用されます。Cloud SchedulerはPub/Sub経由でマテリアライズジョブに関する設定情報を送信します。それにより、サブスクライバーAPIがメッセージを受け取り、Feature Serverにジョブの開始をリクエストします。 一方、オンデマンド実行では、マテリアライズジョブ情報を含むメッセージを直接Pub/Subに送信します。その後の流れは定期実行と同様です。 このときのPubSubは、マテリアライズジョブに関するすべてのリクエストを受け入れるハブとして機能しています。 最後に話したいもう一つのポイントは、Online StoreとOffline Storeの間でFeatureViewを管理する方法です。 FeatureViewは、特徴量データをコンテナのように保持し、エンティティに関連する特徴量の論理的なグループを表現しています。 Offline Storeには"M"という名前のFeature Viewがあり、リアルタイムの特徴量Aと非リアルタイムの特徴量Bを含んでいると仮定しましょう。 予測のために、Online Storeにもデータを持たせたい場合、どのようにOnline Storeにデータを取り込むかを選択する必要があります。 ここでの問題は、特徴量AはKafkaから取得できますが、特徴量Bはマテリアライズジョブを介してOffline Storeからのみ取り込むことができるということです。 異なる方法で同じFeatureViewにデータを取り込むと、データ上書きが発生し、新しいデータが古いデータに上書きされてしまう可能性があります。 この図は、2つの方法を使用して同じFeatureViewにデータを取り込む場合に何が起こるかを示しています。 Kafkaからの取り込みとマテリアライズジョブの両方がFeatureView単位でデータの挿入を行うため、同じFeatureView内ではストリームで取り込まれた最新の特徴量が、マテリアライズジョブで取り込まれた1時間前の特徴量に上書きされる可能性があります。 もちろん、Offline Storeからすべての特徴量をマテリアライズして上書きを防ぐこともできますが、ストリーム取り込みはニアリアルタイムで行われるため、最大限活用したいと考えています。 解決策は非常にシンプルです。それは、Online Storeで取り込み方法ごとにFeatureViewを分けることです。 まず、Online Storeで新たに2つのFeatureViewを作成します。 "stream_feature_view_M"では、"feature_view_M"の中でKafkaから取り込まれるリアルタイム特徴量定義のみを含めます。 "materialize_feature_view_M"では、"feature_view_M"の中でOffline Storeからマテリアライズされる特徴量定義のみを含めます。 モデルには、2つのFeatureViewデータを合わせて全体特徴量としてを提供します。 最終的に、Offline Storeではモデルのトレーニングとバッチ予測向けに"feature_view_M"の特徴量を提供し、Online Storeではオンライン予測向けに"stream_feature_view_M"と"materialize_feature_view_M"を合わせた特徴量を提供します。 これにより、同じFeatureView内で特徴量の更新頻度が違うとしても、データが上書きされず、正しく更新された特徴量データを提供することができます。 これがこの解決策の基本的な考え方の説明になります。 最後にまとめです。 本セッションでは、不正検知速度を向上させるための新しい仕組みについて説明しました。この仕組みでは、取引が行われる前に潜在的なリスクランクを算出し、即時不正防止システムに提供することで、全体的にニアリアルタイムの不正検知を実現しました。 この仕組みは不正検知を高速化し、機械学習モデルの予測をニアリアルタイムで不正防止に活用することができます。 また、このメカニズムを実現するためのシステムアーキテクチャやその具体的な実装方法についても話しました。既存のバッチソリューションにストリームソリューションを導入することで、包括的な不正防止ソリューションにより一歩近づくことができました。 お知らせがあります。私たちは不正防止システムにGraphDBを取り入れました。グラフベースのアプローチは、不正検知に置いて顕著な効果を発揮しています。データ間の関係やパターンを見つけることで、さまざまなタイプの不正を特定することができます。さらなる詳細については、近日中に公開されるブログ記事をお楽しみにしてください。 それでは本日のプレゼンテーションは以上とさせていただきます。ありがとうございました。
Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。 この記事は、「 GoによるSQLクエリテストの取り組み 」の書き起こしです。 @a-r-g-v(batta):GoによるSQLクエリテストの取り組みについて、発表させていただきます。 初めに自己紹介をさせてください。2020年に新卒としてメルペイに入社をしました。そこから3年間ほど、メルペイの加盟店管理のシステムを作るチームに配属されていました。現在は、メルカリの認証認可を担うチームに所属しております。 こちらが本日のアジェンダです。 はじめに、背景を説明します。加盟店管理のチームには、複雑な条件を持つBigQueryのSQLクエリがいくつか存在しています。 例えば、加盟店管理の費用計算などの計算クエリのように、外部環境の変化によって要件が定期的に変更され、マイクロサービス化などのシステム化が難しいクエリがあります。このクエリは、複雑であるだけでなくテスタビリティにも問題がありました。 そのため、開発者がテストを実施することが困難になっており、クエリの変更を安心して行えない状態にありました。 では、このクエリの複雑性とはどのようなものだったのでしょうか?大きく二点ありました。 一つは、抽出条件の複雑さです。契約条項に基づく複雑なビジネス要件が、クエリの複雑さを増す要因となっていました。例えば、加盟店管理費用を計算するビジネス要件においては、正しく費用を計算するために、審査通過日、加盟店獲得後の決済情報、決済用QRコードの要否の情報を組み合わせて、クエリを行う必要があります。この条件がクエリを複雑にしていました。 また、クエリが複数のマイクロサービスのデータベースを横断して参照していることによって、複雑さを増していました。メルペイでは、マイクロサービスアーキテクチャを採用しており、業務ドメイン単位でサービスが分割されています。 例えば、加盟店の申し込み、審査、事業者の情報、決済履歴、QRコードの配送履歴などは、それぞれ別のマイクロサービスとして分割されています。一方で、管理費用を計算するためには、これらのデータベースを横断的に参照する必要があります。また、これらの依存しているマイクロサービスの中には、別のチームが管理しているものもあります。この状況が、クエリを複雑にさせています。 では、チームにはクエリにまつわるどんな課題があったのでしょうか?大きく二つありました。 一つは、クエリに対する開発テストが煩雑であったことです。複数のマイクロサービスのテーブルに依存しているために、投入対象のテーブルの数や、投入データ行数が多くなっていました。また、クエリの抽出条件が複雑であるため、必要なテストパターン数が多く、データとして投入する量も多くなっているという課題がありました。 また、手作業の多さも問題でした。実際のテスト環境のテーブルに対して、マイクロサービスが生成していないデータを投入することは、問題です。そのため、クエリをテストするために、新しくテーブルを作り、テストデータを投入した後にそのテーブルを使用するようにクエリを書き換え、クエリを実行・結果検証・クリーンアップという手順を、都度のクエリごとに行う必要がありました。これを毎回のクエリ改修や、テストパターンごとに行うのが大変であるという課題がありました。 二つ目は、クエリに対する自動テストの欠如です。デグレードを検出する自動テストスイートが存在しませんでした。そのため、クエリの変更を安心して行うことができない状態になっていました。 これらの課題に対する解決方法として、Goのテストから、クエリに対するテストを実装できる仕組みを作成しました。 具体的には、テストコードから参照されるライブラリとして実装しました。これは、テストコードによってテストデータを投入し、BigQuery上でSQL実行を簡単に行える仕組みを組みました。この仕組みによって、可読性・メンテナンス性が高い形でテストを行えるようになりました。 また、このテストデータ作成を支援するために、クエリからGo構造体を自動で生成するツールも作りました。さらに、この方法で作成した自動テストケースを蓄積し、CIで実行することによって、デグレードの検知を自動化しました。 次に、全体の動作イメージを説明します。クエリのテストはGoのテストとして、テストケースを実装するようにしました。 テストケースごとに、こちらを実行します。まず、テスト対象が依存しているテーブルを抽出して、テスト用のデータセット配下にテーブルを1件ずつ作成します。 テストケースで指定されているテストデータを、テスト用のテーブルに挿入します。次に、テスト対象のクエリのFROM句に書かれているテーブル名を、作成したテスト用のテーブルを利用するように書き換えます。 書き換えたクエリを実行して、期待している結果と同じかどうかを確かめ、最後にテストケースのクリーンアップ動作で作成したテスト用のテーブルを全て削除する形で動作します。 また、テストケースから、テストデータの投入を支援するために、クエリが利用しているテーブルをGoの構造体として自動生成する仕組みも作りました。 具体的には、同一リポジトリに存在する全てのSQLファイルを読み、コード生成を行うコマンドを作りました。コマンドは二つの構造体を生成します。 一つは、クエリが依存しているテーブル一覧を表す構造体です。クエリが依存しているテーブルを全部列挙して、対応関係をGoの構造体として生成します。ここの利用テーブルの列挙は、正規表現を用いてFrom句をパーズして行いました。 二つ目は、各テーブルの定義に対応するGoの構造体です。上記で算出したクエリごとに、テーブルのスキーマ定義を実際のテスト環境のBigQueryのテーブル定義を参照し、自動生成するコマンドを作成しました。 それでは、実際に作成したツールを用いて、クエリに対してテストを作成する方法を実現したいと思います。 こちらがデモで使用するテスト対象のSQLクエリです。このクエリは、UsersテーブルとChargeテーブルをユーザーIDで結合して、ReferralTypeがORGANICであるユーザーの決済金額の合計を算出するクエリです。このクエリに対してテストを書きます。 先立って、このUsersテーブルとChargeテーブルのテーブル定義をお見せしたいと思います。 こちらが、BigQuery上に存在するUsersテーブルの定義です。Usersテーブルは、ユーザー1行ごとに行が作成されるテーブルです。 もう一つは、ペイメントサービスのChargeテーブルです。Chargeテーブルは、ユーザーの決済コードを1回ごとに1行作成されるテーブルです。 それでは、実際にテストを変えていきたいと思います。まずテストを書く前に、コード生成のコマンドを実行します。このコマンドを実行することによって、このクエリが依存しているUsersテーブルとChargeテーブルのGoの構造体が自動で生成されます。 また、先ほどのクエリが依存しているGoのテーブルの一覧を表す構造体と、BigQueryに対して、簡単にデータを投入できるヘルパー関数が生成されます。このヘルパー関数を使って、クエリに対してテストを書いていきます。 ヘルパー関数を指定し、Goのテストを書いていきます。スライスの一つ一つが1行に対応するイメージです。先ほどのクエリは、ユーザーIDでジョインしていたテーブルですから、同じユーザーIDを使うために定数を宣言しておきます。 このように同じユーザーIDを使用するようにして、金額も1,000にしておきます。あとユーザーのタイプがオーガニックでないといけないので、そのようにします。このヘルパー関数が生成するクエリをプリントするのと、実際にBigQuery上でこのクエリを実行してみたいと思います。 実行すると、まずクエリが出力されます。ヘルパー関数がテストテーブルを作り、データを挿入して、そのテストテーブルを使用するように、書き換えたクエリが作成されています。 これをBigQueryで実行すると、ここで投入したデータ、つまり「Totalamount:1000」というデータが実際に出力されます。このように、Goのテストの書き味で、クエリに対してテストが書けるようになります。 次にクエリテストの取り組みの効果についてお話します。大きく二つの効果がありました。 一つ目は、開発者テストの実施が容易になり、安心してクエリを変更できるようになったことです。テストデータのコーディングに型の支援を入れるようになったため、列名やデータ種別の誤指定の防止や、IDによるコード補完の恩恵を受けることができるようになりました。また、テストデータの共通化やGoのテーブルテストの活用が可能になり、差分テストケースの追加が簡単になりました。 これにより、境界値テストケースの一つの値だけを変更してテストを行うケースの追加が簡単になりました。また、共通化により、クエリに対してテストを網羅的に実施するコストが低下しました。 二つ目は、開発者テストの蓄積によりデグレード検知ができるようになったことです。自動化されたテストケースが蓄積されたことにより、クエリ変更に際するでグレートの検出が簡単に行えるようになりました。 そのため、より安心感を持ってクエリ変更を行うことが可能になりました。 今後の展望として、追加したい機能や応用の方法を三つ考えています。 一つは、QAテストケースの置き換えの検討です。QAテストにおいても本ツールを応用して、テストデータの投入やQAテストの実施、テストケースのメンテナンスをQAチームが完結して行える仕組みを作成したいです。 二つ目は、クエリのテストケースの網羅性を可視化する方法の検討です。Goの通常のテストでは、コードカバレッジなど、テストケースの網羅性を計算・可視化するためのメトリクスを簡単に利用できます。同様に、SQLクエリに対してテストカバレッジを算出する研究があり、類似の仕組みを本手法にも導入できないか検討したいと考えています。 三つ目は、投入テストデータの正しさの検討です。投入テストデータとマイクロサービスが実際に作成するデータに不一致があると、テストの意味がなくなってしまいます。現状では、クエリテストに利用するテストデータを作成する際、依存マイクロサービスの振る舞いを理解して、データを作成しています。この不一致のリスクを最小限にするために、データインターフェースの明文化などを検討したいと考えております。 以上で発表を終わりにします。ご清聴ありがとうございました。
はじめに こんにちは、mercari.goスタッフの shota sugiura です。 9月7日にメルカリ主催のGo勉強会 mercari.go #23 をYouTubeでのオンライン配信にて開催しました。この記事では、当日の勉強会の活動内容をレポートします。動画も公開されていますので、こちらもぜひご覧ください! mercari.go #23では、株式会社ナレッジワークより @tenntenn さん、株式会社カウシェより @yuki.ito さん、株式会社Stackより @そな太 さんをお招きして、パネルディスカッション形式でGoに関する意見交換をしていただきました。Go1.21が2023年8月にリリースされたことを受けて、Goのモダンな書き方やError Handlingの方法、Go1.21で利用したい新しい機能をテーマに、各社の事例を交えた興味深い議論が行われました。 mercari.goスタッフとして、イベント視聴した私の感想も含め、パネルディスカッションの内容を簡単にまとめてご紹介します! テーマ1: Goのモダンな書き方 https://www.youtube.com/watch?v=QtLTQkAj8ec&t=126s 最初のテーマでは、各社の事例を元にしたGoのモダンな書き方についてお話していただきました。 @yuki.itoさんからは、カウシェで実践しているモノレポでのマイクロサービス開発について話していただきました。モノレポにすることで、会社としてのスタンダードなパッケージ構成の提供やビジネスロジックに関わらない処理の共通化ができ、プロダクト全体の品質を担保できます。最近リリースされた gonew というツールを早速使っていて、これを利用して会社標準の新しいアプリケーションを素早くスピンナップできるようにしているそうです。また、全社で共通のgo.modを使ってモジュールの管理をしているというのも非常に興味深い話でした。 Go 1.21に入ったツールチェーンに関する変更についても触れられました。go.modに書いてあるversionをみてツールチェーンのアップデートが自動でかかるようになったなど、嬉しい変更が入っています。これに関連して、Goのビルドの完全性に向けた取り組みについての ブログ が話題に上りました。最近特に、Goチームがサプライチェーンアタックへの対策に力を入れているようで、こういった言語標準レベルでの取り組みによってGoがより便利で安全なものになっているのだなと感じました。 テーマ2: Error Handling https://www.youtube.com/watch?v=QtLTQkAj8ec&start=1545s 過去のmercari.goでもたびたび話題になっているError Handlingですが、パネラーの方々それぞれのアプローチが聞けて参考になりました。 @そな太さんは、標準のインターフェースを利用できて、かつスタックトレースを取りたいという理由から xerrors を使い続けているそうです。特に困ることはないそうですが、最新標準に入った複数のエラーをラップする機能などを利用できないデメリットを許容できるかは考えどころです。 @yuki.itoさんは、標準のパッケージのerrors、fmt.Errorfを利用しているそうです。スタックトレースは取れないですが、必ずエラーの発生箇所を特定できるような有意なメッセージをつけてエラーをラップするというのを社内で徹底しているそうです。ただ、うっかりラップし忘れるのを完全に防げるわけではないので、linterなどで機械的に防ぐのも良いかもしれないとお話されていました。 @tenntennさんからは、非常に面白いアプローチが紹介されました。Goチームが管理しているpkg.go.devのinternalなpackageに derrors というものがあり、このパッケージのWrap関数を真似して利用しているそうです。名前付き戻り値でエラー変数を定義し、そのポインタを引数に渡してderrors.Wrapをdeferで呼ぶと、nilでないエラーが返ってきた時に必ずラップする仕組みになっています。エラーのラップだけではなくて、GCPのError ReportingやSentryのようなエラー通知の処理も挟むことができるのでとても便利そうです。 このほかにも、クリーンアーキテクチャーにおけるエラーの扱いや、ログレベルに関する話など、多くの人が気になっているであろう話題に関して各々の取り組みを紹介いただきました。 テーマ3: Go1.21で利用したい新しい機能 https://www.youtube.com/watch?v=QtLTQkAj8ec&t=3140s このテーマの最初に話題に上がったのは1.21で導入された slog です。@yuki.itoさんと@そな太さんはまだ本番では利用できていないですが、ゆくゆくは今利用しているライブラリを置き換えてslogを利用してくことを検討しているそうです。既にサードバーティのライブラリで実現できていた機能ではありますが、そのような誰しもが使う機能が標準に入ったことの意味は大きそうです。 Go1.21ではあらたにmaps, slicesパッケージが導入されましたが、このmapsパッケージに入る予定だったmaps.Keys, maps.Valuesは1.21のリリース直前に削除されました。この動きの背景となっているiteratorのデザインや、それを利用した xiter パッケージのプロポーザルに関する話題でパネルディスカッションが盛り上がりました。今まさに議論されている機能なので、これがどのような形でまとまって実装されていくのかとても興味深いですね。 おわりに 今回はいつものmercari.goとは一味違うパネルディスカッション形式の勉強会をお送りしました!Goのモダンな書き方や今後の展望など、Goの最先端の情報を追っているお三方ならではのお話を楽しんでいただけたのではないでしょうか? ライブで視聴いただいた方も録画を観ていただけた方も本当にありがとうございました! 次回のmercari.goでは、9月末に開催される GopherCon 2023 の参加者を集めて活動報告会を開きます。10月下旬に開催する予定なので、 メルカリcompassグループ のメンバーになってイベントの通知をお待ちください。次回もお楽しみに!
こんにちはメルカリで Architect チームの Director of Engineering をしている @motokiee です。 iOSエンジニアの祭典である iOSDC Japan 2023に参加してきました。今年で8回目を迎えた iOSDC Japan ですが、2019年以来のオフラインメインでの開催ということでとても盛り上がっていました。 また、メルカリとしては初めてブースを出展したのですが、180名以上の方に立ち寄っていただき参加者の方々と交流することができとても有意義でした。 今回、メルカリからは2名が発表を行いました。iOSDC Japan 2023 day2 で 「メルカリ10年間のiOS開発の歩み」 というタイトルでメルカリの10年間のiOS開発の変遷について40分のトークを行いました。このブログでは、補足情報としてトークをしようと思ったきっかけ、時間の都合上トークには盛り込めなかった10年の歴史の調査方法についてご紹介します。 もう一名の登壇者である @lestrrat は欠席により空いてしまった LT に代打枠で登壇し、サワードウ(パン)について発表を行いました。サワードウはiOS関連技術とは関係がないのですが、当日 LT で欠員が発生してしまい、 iOSDC Japan 主催者の長谷川さんからのリクエストで当日急ピッチで準備を行って発表を行いました。 急遽準備を行ったこともあり、機材トラブルでスライドなしで LT を行いました。投影したかった スライドはこちら です。 お聴きになった皆さんは早速パンを焼いているでしょうか? トークについて 「メルカリ10年間のiOS開発の歩み」 ではタイトルの通り、メルカリの10年間のiOSアプリ開発の歴史を振り返りました。 発表資料はこちら です。 初期のスライドは200枚を超えていましたが、内容を削ぎ落として140枚ほどのスライド数に落ち着きました。トーク時間も本番では40分ぴったりで終えることができました。 CfPを出そうと思ったきっかけ 今回この内容でCfP(Call for Proposal)を出そうと思ったきっかけは、もちろんメルカリが10周年を迎えたことが理由の一つです。メルカリ社内でも10周年を祝う企画が内外で多々行われていますが、エンジニアリングとしての社史を残し、10年続くサービスの移り変わりを外部に公開することでコミュニティに貢献したいと考えました。 自分は2016年に入社してからメルカリのフリマ事業にずっと関わってきたわけではないのですが、メルカリAppはもちろん、新規事業も含め幅広く携わってきたので全体感を持ってトークを構築できるのではないかと考えました。 ※ メルカリ本体での開発はもちろん、iOS Re-architecture の推進、メルペイ立ち上げサポート、リリースフローの整備、子会社での複数の新規事業開発(メルカリ アッテ、メルカリ カウル、メルカリ Shops)、iOS Architect チームの Director などを行ってきました もう一つの理由は、トークの中でも触れた10年近く事業を支えてきた初代メルカリiOSリポジトリのアーカイブでした。 メルカリは去年 GroundUP というアプリをゼロから書き直すプロジェクトを完了 させ、今年アーカイブを実施しました。このリポジトリを通じてたくさんの人と働いてきたという個人的な思い出もあり感傷的な気持ちになりました。 10年の開発の歴史を40分のトークにまとめるにはかなりの時間と労力を要するだろうとは思っていたのですが、実行に踏み切れたのはそんな思いがあったからです。 実際、6月後半くらいからトークのアウトラインを考え始め、調査に2週間、スライドにまとめ、最終的に公開された状態にまで仕上げるのにさらに1ヶ月近くを要しました。 トークに含められなかったこと メルカリのiOSアプリ開発と一口に言っても、この10年間で本体のフリマアプリ以外にも多種多様なアプリを立ち上げてきています。残念ながら今回の資料には入れられなかったアプリもあったのですが、この10年で行ってきた主なチャレンジをカバーできていると思います。 また、社内には歴史的経緯を知っている人たちも少なくなってきています。特にiOSアプリ開発に深く関わってきたなかでは自分が一番長く在籍しているという状況だったこともあり、様々なツールを使って調査を行いました。 トークでは調査の方法について触れる時間がなかったため割愛しましたが、実際に使った調査手法をスライドの56ページから62ページにまとめているのでご興味があれば御覧ください。 おわりに たくさんの興味深いトークが共有され、他の参加者やスポンサーの方々と直接コミュニケーションを取れる貴重な機会でした! メルカリとしては第一回から8年連続の8回目の iOSDC Japan スポンサーとなりましたが、これからも引き続き技術コミュニティへ貢献を続けていきたいと思っています。 スタッフの皆さん、参加者の皆さん、スピーカーの皆さん、お疲れ様でした!また来年お会いできることを楽しみにしています! メルカリはiOSエンジニアを募集しています!もしメルカリに興味を持っていただけたらぜひこちらもご覧ください! https://apply.workable.com/mercari/j/AEA2A632A9/ https://apply.workable.com/mercari/j/5EFBF06F3B/ https://apply.workable.com/mercari/j/79482261D5/ もちろんサワードウ(パン)を焼いてみた、という報告もお待ちしています。
こんにちは、メルカリ Engineering Office チームの@yuki.tです。 私たちのチームでは、しなやかで強固なエンジニアリング組織を作ることをミッションに、様々な活動を行なっています。私はその中でも、主にエンジニア評価のサポートに携わっています。 メルカリでは、約3年前にEngineernig Ladderとして、メルカリのエンジニアに期待される行動を成長段階ごとに明文化したものを作成しました。Engineering Ladderは主にエンジニアの評価や目標設定に使われています。 この記事では、Engineering Ladderが作成されてから3年間でどのように活用・改善され、どのような影響があったかをまとめます。 評価・等級制度の作成や、エンジニアの組織作りに携わっている方にぜひ読んでいただきたいです。 Engineering Ladderとは 一般的にキャリアラダー等と呼ばれている、職務に必要なスキルを明確にするための仕組みです。等級制度と紐付け、各等級ごとに求められるスキルや行動を定義し使用されていることが多いです。 エンジニア向けには海外の事例が多く、Spotify、Medium、CircleCI、Google、Dropbox社などで利用されており、外部公開している企業もあります。 最近では国内でもキャリアラダーを公開する企業が増えてきました。 メルカリでは、 3つのバリュー (Go Bold, All for One, Be a Pro)をベースにし、期待される行動を明文化したものを「Engineernig Ladder」と呼んでいます。 各エンジニアが持つ個性やスキルを尊重しながら、互いの強みを活かす組織を目指すために作られました。 Engineering Ladderは、評価や目標設定、キャリア設計で利用されており、今自分がどの段階にいて、次の段階に進むために必要な行動、スキルは何か、ということを確認するための指標となっています。 どのように使われているか メンバー自身の自己評価や、マネージャーからのfeedbackでEngineering Ladderを参照して使用しています。 会社全体で使われている等級制度(グレード定義)もありますが、すべての職種に使用できるように抽象度が高い内容のため、エンジニアの仕事に当てはめにくい場合があります。それに対して、Engineering Ladderはエンジニアの仕事に合致するように具体化した基準として位置づけられています。 Engineering Ladderのこれまでの改善と影響 1年目:Engineering Ladderの使用をスタート Engineering Ladderの作成後、まず評価での使用を開始しました。 開始後は「該当期間の成果を具体的に書けるようになった」や「評価のすり合わせができるようになり、納得感が上がった」という意見があり、ポジティブな影響がありました。 他にも、組織で期待されているエンジニア像を共有・発信するために、採用面接用のEngineering Ladderをベースにした質問項目も作られました。 メルカリでEngineering Ladderを作ることになったきっかけ、作成の過程、効果については、こちらの記事で詳しく説明されています。 参考記事: 会社の文化を言語化すると何が起こるのか。Engineering Ladderの作成プロセスとその結果 Continious feedbackの推進 Engineering Ladderの作成後、評価を助けるツールとして、Continuous feedbackという仕組みが推進されました。 Continuous feedbackは、評価時期だけでなく、1ヶ月等のより短いスパンでマネージャーとメンバーで認識をすり合わせる仕組みです。このときにEngineering Ladderを使って行動を振り返ることを推奨しています。 この仕組みを導入したところ、メンバーの評価への満足度が向上しました。 Continuous feedbackの効果を確認するためのSurvey結果 Continuous feedbackについてはこちらの記事で詳しく書かれています。 参考記事: 評価の満足度を劇的にあげた秘訣。Continuous Feedbackのすすめ これらのようにポジティブな影響が見られた一方で、Engineering Ladderの内容にはまだまだ下記のような課題がありました。 書かれている内容にわかりにくい部分がある 全社のバリューやグレード定義と完全に一致していないようにみえる 特に全社のグレード定義との整合性については、Engineering Ladderが作られた後に全社の定義が刷新されたという経緯があり、整合性が不完全な状況でした。 2年目:会社全体のグレード定義と合わせるためアップデート 前述の通り、作成時点のEngineering Ladderは会社全体のグレード定義の項目との整合性が不完全だったため、この年に構成と項目を大きく変更しました。 変更前:メルカリの3つのバリューを元にエンジニアリング組織で作成した項目 変更のためには、まず会社全体のグレード定義の項目を、エンジニア向けにさらに分解してあらたな項目(Key behaviors)を作成しました。 変更後:全社グレードから作成されたKey behaviors Key behaviorsを作成した理由は、抽象度の高いバリューを細分化してエンジニア向けに具体化することと、今後組織の求めるエンジニア像がアップデートされた際にKey behaviorsごとの差し替え・変更を可能とし、メンテナンス性を高めることでした。 Key behaviorsの作成後は、それまでのEngineering Ladderの文章を、関連するKey behaviorsに当てはめて再構成し、抽象度や記載内容のわかりにくい部分の修正など微調整を加えました。 このときのアップデートでは、すでに完成された文章がある状態から作成しましたが、もしゼロからキャリアラダーを作成する場合も、最初に項目を作成したうえで成長度合い(等級制度のグレード等)に応じて文章を作っていくことができます。 そして完成されたEngineering Ladderが、 現在公開されている内容 です。 (このあとも部分的に更新されているため細かい文言は当時から変更されています。) バージョンアップ前のEngineering Ladder(社内公開用) ※3つのバリューをベースに作られたものの、関係性は示されていませんでした バージョンアップ後のEngineering Ladder(社内公開用) ※内容の改善と併せて、3つのバリューとの関係性をわかりやすくして公開しました このアップデート前は、会社全体のグレード定義とEngineering Ladderの整合性が不完全だったため、エンジニアリング組織は独自の評価記入フォーマットを使う必要がありました。それが改善されたことで、エンジニアリング組織も会社全体と同じ評価記入フォーマットが使えるようになりました。 3年目:使用する組織が増え、幅広く影響力を持つツールに Engineering Ladderは、作成直後はメルカリのエンジニアリング組織だけで使用開始しましたが、年を追うごとにグループ内で使用する組織が増え、現在はカンパニーを跨いでグループ内のエンジニア組織で広く使用されています。 社内での閲覧数の推移 またメルカリではEngineering Ladderを社内のGitHubで管理しており、Issueの起票だけでなく、各メンバーが直接Pull Requestを出して、コントリビューションできるようにしています。 Engineering Ladderの内容に疑問や、改善点を見つけた場合に、それらをメンバー自身が解決できるという仕組みです。Pull Requestの内容はEngineering Ladderのプロジェクトメンバーがレビューしたうえで半年に一度Releaseされます。 公開後のコントリビューション数をみると、公開直後はCommit数が多いですが、改善を繰り返すうちにCommit数が減っています。 (2022年12月と2023年6月に大きな山がありますが、これは半年に一度行われている、プロジェクトメンバーによる定期アップデートのCommitです) コントリビューション数の推移 各組織からのFeedback 各組織からは、主に下記のようなFeedbackが得られています。 組織全体で評価の認識を揃えることと、納得感の向上に繋がっています。 評価される行動が言語化されているので、メンバーを評価しやすくなった 個人ではなく行動の評価であることが評価時にメンバーへ伝えやすい メンバーへの説明だけでなく、マネージャー同士の認識も揃えることができる メンバーとマネージャーで共通認識を持つことで、評価の納得感が高くなった メンバーの行動をEngineering Ladderに当てはめて次のグレードとのギャップを埋めることで、目標設定に活用できる 今後について 今後は、Engineering Ladderにある、Engineering Manager Skillsの改善をしつつ、 エンジニアリング組織のVision との連携をより強固にしていき、組織の方向性を伝えるツールとしてより役立てることを検討しています。これまでは主にメンバーやマネージャーからのFeedbackや、GituHub上のIssue・Pull requestからの改善が中心だったところを、組織の変化に応じたメッセージを伝える場としても使っていくという意図です。 またEngineering Ladderを重要視しすぎると、特に入社したばかりのメンバーはEngineering Ladderの内容が全てだと考えてしまう恐れがあるため、Engineering Ladderを使うことで根底にあるメルカリのカルチャーを各メンバーが理解して体現できることも目指していきたいと考えています。 社外への影響 最後に社外への影響についてです。メルカリで公開しているEngineering Ladderは Creative Commons Zero(CC0) を適用しているため、他社様が自社でキャリアラダーを作成する際に参考にしていただくこともあります。 他社様におけるキャリアラダーの導入事例 最近では、メルカリのEngineering Ladderを参考に株式会社LegalOn Technologies様が自社の評価基準を作成されたとご連絡をいただきました。 新しい基準の作成後は、評価がしやすくなったり、会社としての方向性が定まったことによるポジティブな影響が得られたそうです。 詳細については、 株式会社LegalOn Technologies様のブログ でご紹介されています。 まとめ この記事では、メルカリのEngineering Ladderについて、社内での活用方法や、作成後にどんな改善が行われ、どのような影響があったかをまとめました。 Engineering Ladderは公開後も会社の状況に応じて内容や使い方の更新を続けることで、より使いやすく改善されています。そして特に評価の納得感の向上に貢献しています。 現在ではメルカリのグループ会社や、他社様からも参照していただいています。 この記事で紹介したEngineering Ladder以外にも、メルカリでの開発者体験やカルチャーにご興味がある方は、ぜひキャリアサイトをご覧ください。 Mercari Careers
要約 ビジネス環境においてフィードバックを得るのは簡単なことではないかもしれません。その点、アンケートは良い方法のように思えますが、期待どおりの結果を得るには、注意しなければならないことがあります。 アンケートから得たいことを明確にしましょう – アンケートは良い投票システムとは言えません。後で結果を返すようにしないと、回答者はアンケートでフィードバックを返すのをやめてしまいます。 一般に、多くのアンケートは回答者を疲れさせてしまいがちで、その結果、チャンスを失っています。また、私が「survey blindness(アンケートによる盲目化)」と呼んでいる現象があります。回答者はあまりに多くのアンケートを目にするために、どれに答えたかわからなくなり、アンケートに答え損ねてしまうのです。 より手っ取り早くてもっといい方法として、個人や小グループの対象者と対面で話をするという方法があります。 私たちの経験から、回答者は、アンケートによってどのような変化が促進されるのかを理解すると、アンケートに対する認識が高まるということがわかりました。 はじめに 「アンケートから役に立つ情報は得られているか?」 数ヵ月前、私たちのチームはこのような問いかけを始めました。業務上、私たちは多くのアンケートを行っています。毎回の全社会議やその他の大きな集まり、イベントなどではそれぞれ独自のアンケートを行っていました。 私たちのような比較的小さなチームでさえ、多くのアンケートを担当していました。「フィードバックフォーム」と呼ぶこともありましたが、これらは見た目も中身も基本的にはアンケートと同じでした。 時には、返ってくるアンケートの数がイベントの人気を測る指標の1つだと考えたりしたものです。けれども、そうではないことがよくあるということもわかりました。返ってきたアンケートの数がイベントの良し悪しと無関係ということもよくあります。 私は手始めに、アンケートについて十分に考察するために、その過程、設計方法、目標、アンケートで収集した情報をどのように活用したかについてチームに尋ねてみました。 さまざまな発見がありました。 始めに言っておきますが、すべてのアンケートが悪いわけではありません。私たちの場合、まるでアンケートという立派なハンマーに、釘のようにたくさんのやり取りや「フィードバック」を必要とする質問が用意されているかのような状態になっていたということです。 私がこのことに疑問を感じるようになったのは、単純に会話で「アンケート」という言葉を聞いた人の反応からです。あきれてうんざりというのが大抵の反応でした。また、大きなイベントのアンケート回答率が1桁だったり、大規模なアンケート調査で自由回答欄には何も書かれていないということも何度かありました。こうしたことから、アンケートは効果的な投票システムではないという論点も見えてきました。 これは明らかに、間違った使い方をしているか、使い過ぎかの徴候です。 釘とハンマーのどちらが先だったのかはわかりません。おそらく、Googleフォームを見つけた誰かが、オンボーディングセッションに対するみんなの感想を知りたいと頼まれてアンケートを作成し、それが毎月のように使われるようになったといったところでしょう。 最近では、ご存じのように新型コロナウイルス感染症の拡大によって多くの人が2年以上も在宅勤務をすることになり、気軽に会って誰かの意見を聞くことや、雰囲気を察することが急に難しくなったため、ミーティングやイベントがうまくいったのか、どのような点を改善すればよいのかなどを知るために、簡単な質問をするのはいい考えだと思われるようになったのです。 私たちはまた、アンケートをイベントの人気や満足度を推測するKPI(重要業績評価指標)として使い始めました。これは、ある種の投票システムとして提出されるアンケートフォームの数を評価するのと非常に近い意味合いもあります。 設計 こうした多くのアンケートに最後まで回答し、実際にクリックしてたくさんのアンケートに答えてきた結果、私は「このアンケートはどのように使われるのだろう?」「責任者は誰なのだろう?」「どうしてこの情報が必要なのだろう?」「私のコメントはどうなるのだろう?」などと考えるようになりました。 この答えはすぐにはまったくわかりませんでした。自分たちのチームが担当するアンケートに関してさえもです。フィードバックに対してどのような対応ができるのかも、それをアンケートに答えてくれた人にどのようにして伝えればいいのかも、そもそもわかりませんでした。 私たちが質問していたのは、イベントは役に立ったか、長すぎなかったか、短すぎなかったか、テーマは興味のあるものだったかなどです。 よく使ったのが1から5までのスケールでの評価です。1が「役に立たなかった」、5が「非常に先進的だった」などです。多くの評価システムと同じように、この方法も結果を歪める傾向にありました。特に記名式の場合は、4か5の評価がほとんどでした。 自由回答欄がある場合でも記入されていないことがほとんどで、得られたフィードバックの大半の理由はわかりませんでした。 また、質問はかなり一般的なものだったので、しばらくすると似たようなフォームはすべて渾然一体となっていきました。 もちろん、フォーム作成ソフトは、星や「非常に役に立った」から「まったく役に立たなかった」までのスケールがテンプレートになっているものも多く、このスタイルに適した設計になっていることもあります。また、私たちはたくさん質問をするほど粒度の高い情報が得られると考えてしまうことがあります。けれども、必ずしもそうではありません。 アンケートを行ったり、フィードバックが欲しい理由は無限にあり、テーマも多種多様です。ですから、設計に絶対的な正解や不正解はありません。けれども、より良いものにすることができることはわかっていました。 どのように見えるとしても、アンケートは双方向ツールだということに私たちは気が付きました。質の高い情報を手に入れたい場合は、プロセス全体をより良いものにするために、私たちも情報を提供する必要があったのです。 より良いものにするために、基本的なレベルで回答者に次のことを理解してもらうようにする必要がありました。 アンケートへの記入を求める理由。 誰のためのアンケートか。 情報の使い道。 アンケートの結果実施したことに対するフィードバックはいつ、どのように提供されるのか。 私たちは欲しいデータの価値と、それに対する行動をどのように計画するかを検討することから始めました。 例えば、研修セミナーであれば、「長すぎましたか?」と尋ねるより、 「説明の時間は、システムについてよく理解するのに十分でしたか?」と尋ねたり、 「講師の[マイクロサービス]、[クラウドインテグレーション]、[セキュリティ要素]についての説明は短すぎたり長すぎたりしましたか?」と尋ねるほうが効果的かもしれません。 一般的な質問をする代わりに、よりイベントに合わせた質問をし、それ以外のことは自由回答欄で拾うようにするべきです。 定期的なイベントの場合、これは明らかなことかもしれません。そう考えると、このようにしてより良いデータを手に入れない理由などあるでしょうか?ここで注意しなければならないことがあります。繰り返されるイベントから再現可能なデータを得たい場合は、おそらく、年間を通して、中心となる質問とセッションごとの具体的な質問を用意する必要があります。 話をする 同じ時期に、開発者体験の一環として、私たちはエンジニアリングマネージャー(EM)一人ひとりと30分間、事前に内容をほとんど決めることなく話し合いを行うことを決め、これを「Outreach and Visibility(見える化)」プロジェクトと呼びました。 このプロセスを始めてまもなく、EMもアンケートのことが気になっているのだということがわかりました。 「なぜこんなに多くのアンケートをするのか?」という質問も多かったのですが、一番多かった質問は、「こうしたアンケートによってどのような変化が促進されたのか?」というものでした。 これは私たちの感覚とも重なる部分がありました。多くのアンケートを実施しましたが、伝達方法の変化についてはどうだったでしょうか。私たちは実際に多くの社内サービスを改善しました。アップデートし、改善し、必要ないものは廃止しました。では、何が食い違っていたのでしょうか。私たちは、熱心にアンケートを送り、結果について調べ、分析し、その結果も回答者に送ってきました。けれども、その結果、何を変えたのかは伝えてこなかったのです。 多くの場合、とても単純なことでした。なぜ変更したのかを伝えてこなかったのです。変更した理由がフィードバックやアンケートによるものであっても、そのことを回答者に伝えていなかったわけです。この点を変える必要がありました。プレゼンテーションの終わりやSlackチャンネルで例を挙げるときに、この話にもっと触れなければならなかったのです。フィードバックへの感謝が必要でした。ここから私たちは、Engineering Ladderにアップデートを示す方法をより明確にするようにしました。 また、定期的な「Outreach and Visibility(見える化)」の話し合いは好評だったため、継続してさらにフィードバックを集め、懸念に耳を傾け、その中で、得られたフィードバックから行っていることを伝えたり、改善点を示したりもしています。同時に、フィードバックフォームのいくつかを廃止し、Slackで直接フィードバックするよう勧めています。 おわりに ビジネスから情報を得ることは、動きの速い業界では非常に重要です。アンケートはこのために有効なツールですが、他のツールと同じように、それぞれの課題ごとに正しく設計して使う必要があります。1種類ですべてを済まそうとすればエンドユーザは疲弊し、フィードバックの質が低下してしまいます。 究極的には、話をするという選択肢は常にあります。このハイブリッドなビジネスの世界で、それはテレビ会議で行われるかもしれませんし、オフィスで行われるかもしれません。1対1で行われるかもしれませんし、小グループで行われるかもしれません。けれども、それはいつでも可能です。 どのような方法を選ぶとしても、回答者に、その回答のおかげで改善がなされたのだということを説明し、この循環を完結させることが不可欠なのです。
こんにちは!Merpay Engineering Enagement Team の@mikichinです。 来たる8月22日(火)から8月24日(木)までの3日間にわたり、「Merpay & Mercoin Tech Fest 2023」をオンライン開催します! テーマは「Unleash Fintech」。メルペイ・メルコインのこれまでの技術的な取り組みはもちろん、メルカリグループのFintech事業における新たな挑戦をお伝えします。メルペイ・メルコインが今後どのように“Unleash(解放)“していくのか、ぜひご自身の目と耳で確かめてください!! 肝心なトークセッションは、昨年全20セッションだったところ、今年は全33セッションにパワーアップ! 本記事では、24日のトークセッションの見どころをご紹介!3日目は基盤となる技術と組織開発を中心としたテーマをお届けします! まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちら からお願いします。 [12:10〜12:40] fake clock microservice -時刻をハックしてテストする方法- 現在時刻で変わるロジックのテストをどのように行うかという問題は、よく知られています。メルペイでは、時刻に関するロジックが複数のマイクロサービスに散らばっているという事情があります。また、特に与信領域ではイベントのライフサイクルが数ヶ月単位と長いため、既存の解決策だけではうまくフィットしない部分があり、独自で解決してきた歴史があります。 これまでの時刻問題の解決策の変遷や、それぞれのメリット・デメリットなどについて話します。 [12:40〜13:10] メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み メルコインではGCPを利用して、各マイクロサービスはGKE上で動いています。セキュリティやコンプライアンスの観点から、メルカリ・メルペイとは完全に分離したインフラを持つため、完全にイチからの立ち上げを行いました。限られた時間とリソースのなかでどのようにSREがセキュリティとコンプライアンスに準拠したインフラの設計と構築をしたか、さらにサービスの信頼性を向上するためにSREとして取り組んだ内容を話したいと思います。 [13:10〜13:40] メルコインにおけるシステム間のデータ分離を実現するための通信アーキテクチャ セキュリティやデータプライバシーの担保は利便性や開発者体験とトレードオフになりがちです。私たちが今回取り組んだ「システム間のデータ分離」についても、さまざまな観点で開発者の体験が損なわれてしまう恐れがありました。このセッションでは、開発者体験を損なうことなくデータ分離を実現するために私たちが設計した通信アーキテクチャ設計についてお話しします。 [13:40〜14:10] Building a Global environment at Merpay: India & Japan Merpay is being developed by diverse talents from over 40 countries. Last year Mercari established the Center of Excellence in India and Merpay now has development teams not only in Japan, but also in India. Join us to find out how we work together, what we learned, and what our future looks like! [14:10〜14:40] なめらかなFintech QAを実現するためにテストケースフォーマットを標準化した話 メルペイには多種多様なプロダクトが存在しており、メルペイQAチームの各メンバーはプロダクトの特性に合わせて、テストケースを作成していました。そのため、共通で使用するテストケースフォーマットの作成は非常に難易度の高い試みでした。各QAチームのひっかかりを最小限にする「なめらかなテストケースフォーマット」をどのように作り上げていったのか、運用開始に至るまでのどんな苦労や工夫があったのかをお伝えし、品質に関わる全ての方の参考になれば幸いです。 [14:50〜15:20] メルコイン決済基盤の実践話 暗号資産ビジネスにも欠かせない決済、台帳、会計・法定帳簿の管理機能を提供するため、既存のメルペイの決済基盤からドメイン責務の再整理し、メルコイン向けに機能の再設計・開発を行いました。本セッションでは、暗号資産ビジネスを含め、Fintechを支える基盤作りに興味を持たれている方々に向けて、メルコインの決済基盤のシステム構成、各ドメインサービスの機能設計について紹介します。 [15:20〜15:50] メルコイン決済マイクロサービスのトランザクション管理を支える技術 マイクロサービスアーキテクチャにおいて、整合性の担保、そしてそのリコンサイルをどう設計/実装するのが良いのかという課題を抱えている方に参考になれば幸いです。 [15:50〜16:20] Merpay Engineering Career Talk 自身のキャリア形成をしていく上でProactiveに行動するためには個人の信念だけでなく、会社のValue/Mission共感などが必要になってきます。しかし、組織規模が大きくなっていくにつれて掲げる目標が変化していき、Value/Missionの解釈も揺れ動いていきます。非連続な変化も起きてしまう中でも個人が会社にAdaptしながらキャリア形成を推進していくには、適応や柔軟性という言葉だけでは語りきれない選択の繰り返しを行っていく必要があり、登壇者は全員が未上場前から入社し5年以上在籍しています。キャリアを語るという観点では、結果論的な話になってしまいがちですが、ひとつの会社に在籍している中で中長期的なキャリアを目指している人にはぜひご視聴していただきたいです。 [16:20〜16:50] gRPC Federation を利用した巨大なBFFサービスに対するリアーキテクチャの試み 巨大なBFFサービスに対する責任の所在やメンテナンスコストを改善するためのアプローチとして Apollo Federation といった GraphQL を利用した Federated Architecture を採用するパターンがよく知られています。しかしすでに gRPC で運用してきたところに GraphQL を新しく導入するコストは決して安くありません。そこで gRPC の資産をそのまま利用しつつ Federated Architecture を構築する仕組みを開発しています。同様の理由で Apollo Federation の導入を躊躇している方に対して他のアプローチを考えるきっかけになれば嬉しいです。 [16:50〜17:10] Enabling ProgramのEngineering Headをちょっとやってみている Microservices Architectureで5年以上開発してきたメルペイですが、組織の規模が大きくなったりリリースしてから一定の期間が経過したことにより様々な課題が見えてきました。Mircroservices ArchitectureとMonolithやMonorepoなどが開発戦略に関連するものとして比較されますが、どれを採用したとしてもそれらをどう運用して改善していくかが最も重要です。組織的な開発の課題に対してどう取り組んでいるかを知ってもらえると良いと思います。 「Merpay & Mercoin Tech Fest 2023」のお申し込みは こちら から。 イベント詳細 開催日時: 2023年8月22日(火)〜24日(木)12:00-17:30 概要: IT企業で働くソフトウェアエンジニアおよびメルペイ・メルコインの技術スタックに興味がある方々を対象にしたオンライン技術カンファレンスです。事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングについて知ることができる、メルペイ・メルコインにとってこの夏一番のお祭りです。 テーマ: Backend、Architect、SRE、Data Platform&Management、Machine learning、Frontend、iOS、Android、QA/テスト、 組織づくりなど 参加費:無料 場所:オンライン 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @mercaridevjp でお知らせしますので、気になる方はぜひフォローをお願いします。
こんにちは!Merpay Engineering Enagement Team の@mikichinです。 来たる8月22日(火)から8月24日(木)までの3日間にわたり、「Merpay & Mercoin Tech Fest 2023」をオンライン開催します! テーマは「Unleash Fintech」。メルペイ・メルコインのこれまでの技術的な取り組みはもちろん、メルカリグループのFintech事業における新たな挑戦をお伝えします。メルペイ・メルコインが今後どのように“Unleash(解放)“していくのか、ぜひご自身の目と耳で確かめてください!! 肝心なトークセッションは、昨年全20セッションだったところ、今年は全33セッションにパワーアップ! 本記事では、22日のトークセッションの見どころをご紹介!2日目はBackend、Data & Modelingを中心としたテーマをお届けします! まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちら からお願いします。 [12:10〜12:40] メルペイのあと払いとスマートマネーを支える返済基盤マイクロサービスの進化 本セッションでは、事例を通して既存マイクロサービスの分割やデータマイグレーションなどをご説明します。マイクロサービスアーキテクチャの最適化に興味や課題を持っている方にとって参考になれば幸いです。 [12:40〜13:10] 拡張性を備えたソフトウェア設計 In this session Rupesh will share the challenges and accomplishments while building EGP(Engagement Platform) as an internal product for Marketers at mercari group. How is it different from the usual product development lifecycle. How we could leverage its foundational design to build new features incrementally, and most recently, the batch feature which was never thought of to be built on EGP ! [13:10〜13:40] 発行枚数100万枚を支えたメルカードGrowth施策の裏側 メルカードの Growth に関連する施策は多岐に渡り、多くのチームが関わっています。そのような中、コミュニケーションやプロジェクト管理における課題に対してどのような工夫をしてきたか、自分たちの開発がいかにビジネス的に貢献しているのかという点でどのようなモチベーションややりがいを感じているかといった内容をお話します。 [13:40〜13:55] メルカードの常時ポイント還元開発の裏側 本セッションでは、まず始めに、メルカードの常時ポイント還元の仕組みについて概要を話します。ポイントの付与判定は、常に多くのマイクロサービスとの関わりが発生しています。そのため、現場で発生した細かな判断など開発の苦労話もありますが、幾つかピックアップしてお話します。 Fintechならではの開発現場の空気感を感じ取っていただければ幸いです。 [13:55〜14:10] メルペイ加盟店売上精算の仕組み このセッションではメルペイ加盟店の売上を精算するマイクロサービスが、メルカリShopsやメルコインなどのサービスを導入するために行ってきた開発や直面してきた課題点などをお話します。複雑な集計を伴うシステムの課題点や考慮点などが、同じような課題を抱えている方々の参考になると嬉しいです。 [14:10〜14:25] GoによるSQLクエリテストの取り組み 本セッションではBigQueryのSQLクエリのテスト方法を実装方法や動作デモを交えて紹介する予定です。複雑なSQLクエリのテストに課題感を持たれている方々の参考になると嬉しいです。 [14:35〜15:05] 発生可能な取引の属性データを用いた素早い不正検知 このセッションでは不正検知システムの機能や仕組み、運用事例などを紹介する予定です!不正行為の防止において最新技術を使った解決策として参考になると嬉しいです! [15:05〜15:35] Fintechにおける機械学習の品質保証とリスク管理 リスク管理のルール遵守と現場の生産性を両立させるために、ルール作りの時点でどのような工夫をしているか。エンジニアとしてどのようにリスク感度を高めようとしているかをお話します。 与信モデル更新マニュアルも作成しており、ブログでご紹介しています。本セッションご視聴前に、ぜひご一読ください。 https://engineering.mercari.com/blog/entry/20230622-d8b521dd2e/ [15:35〜16:15] Merpay & MercoinにおけるLLM活用の取り組み Fintech企業における最新技術を活用した取り組み事例や、取り組みを通じて見える知見についてお伝えできればと考えています! [16:15〜16:30] BigQueryのデータ監視社内サービスを作った話 BigQueryデータを監視したいという要件をお持ちの方のほか、社内に複数のデータ利用者がおり、彼らにセルフサービスのデータサービスを提供したいという方にとって参考になると嬉しく存じます。 [16:30〜17:00] 社内用GitHub Actionsのセキュリティガイドラインを作成した話 「社内でのGitHub Actions利用の広がりにあわせて、安全安心に使うためのガイドラインを作成したい」 そんな思いでGitHub Actionsのセキュリティガイドラインは、社内の有志メンバーによって策定されました。今回の発表ではこのガイドラインの内容を一部紹介するとともに、社内での活用事例やガイドライン作成のプロセスなどもご紹介します。GitHub Actionsを利用する方々が安心安全に利用するための一助になれば幸いです。 https://engineering.mercari.com/blog/entry/20230609-github-actions-guideline/ [17:00〜17:30] BigQueryのコンピューティングリソース管理の取り組み BigQueryを運用されている方、特にSLOT管理の課題に直面している方々に向けて課題に対する具体的な取り組みをご紹介します。 「Merpay & Mercoin Tech Fest 2023」のお申し込みは こちら から。 イベント詳細 開催日時: 2023年8月22日(火)〜24日(木)12:00-17:30 概要: IT企業で働くソフトウェアエンジニアおよびメルペイ・メルコインの技術スタックに興味がある方々を対象にしたオンライン技術カンファレンスです。事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングについて知ることができる、メルペイ・メルコインにとってこの夏一番のお祭りです。 テーマ: Backend、Architect、SRE、Data Platform&Management、Machine learning、Frontend、iOS、Android、QA/テスト、 組織づくりなど 参加費:無料 場所:オンライン 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @mercaridevjp でお知らせしますので、気になる方はぜひフォローをお願いします。
こんにちは!Merpay Engineering Enagement Team の@mikichinです。 来たる8月22日(火)から8月24日(木)までの3日間にわたり、「Merpay & Mercoin Tech Fest 2023」をオンライン開催します! テーマは「Unleash Fintech」。メルペイ・メルコインのこれまでの技術的な取り組みはもちろん、メルカリグループのFintech事業における新たな挑戦をお伝えします。メルペイ・メルコインが今後どのように“Unleash(解放)“していくのか、ぜひご自身の目と耳で確かめてください!! 肝心なトークセッションは、昨年全20セッションだったところ、今年は全33セッションにパワーアップ! 本記事では、22日のトークセッションの見どころをご紹介!1日目はKeynoteからはじまり、Client and Anti-Fraudを中心としたテーマをお届けします! まだ申し込みをされていない方も、興味のあるセッションがあるはずです。お申し込みは こちら からお願いします。 [12:10〜13:10] Keynote & How to Unleash Fintech 新たな体制となったCTO、VPoE3名によるメルカリグループのFintech事業における プロダクトや組織についてざっくばらんにお話します。わくわくする未来の話とFintechサービスならではの信頼性高いシステムを開発する上での「あんしん・あんぜん」な取り組みなど、メルペイ・メルコインのエンジニアリング組織の魅力をお届けできれば幸いです!ぜひ、Keynoteとあわせてお気軽にご視聴ください。 [13:10〜13:40] 1週間リリースを支えるAndroid自動テスト運用のその後 大規模なアプリのテスト保守をチームで解決しようとしている話です。常に変化し続けるアプリのリリースコストを削減すべく、有志で集まってテスト作成に励んでいる様子をご紹介します。 以前公開した「1週間リリースを支えるAndroid自動テスト運用」を事前にご一読いただくと、本セッションをよりお楽しみいただけると思います! https://engineering.mercari.com/blog/entry/20211210-merpay-android-test-automation/ [13:40〜14:10] Merpay iOSのGroundUp Appへの移行 既存のメルペイのコードを新しいメルカリのコードベース上に確実に移植するために、段階的なアプローチで作業を進めてきた様子を具体的なモジュール構造の解説を交えながら紹介します。既存のコードを壊すことなく新しいコード上に安全・確実に移植するという、まるで渋谷駅山手線線路切り替え工事のようなプロジェクトをいかにやり切ったか。お楽しみください。 [14:10〜14:25] Merpay iOSにおけるSwift Concurrency対応の挫折と今後 本セッションではプロジェクト失敗の経緯を説明します。失敗の理由はさまざまありますが、Swift Concurrencynoの特性からすべてのコードを一気に書き換える判断をしたことや、メルペイiOSコードの移植作業によって元のコードを変更する動機がなくなったことが挙げられます。 Swift Concurrencyの特性や組織のコードベースの変更の中でどうプロジェクトを判断したのかを示す予定です。 Swift Concurrency対応や大規模なコード変更のプロジェクトを考える上の参考になればと思います。 [14:35〜15:05] SwiftUIでビットコインの価格チャートを改善・再実装した話 本セッションではSwiftUIを使った実装の技術的な側面だけでなく、再実装決定までの経緯やデザイナーと改善サイクルを回していく流れについても触れます。SwiftUIでアニメーション付きのチャートの実装についてや、チームでの運用の話に興味がある方はぜひセッションをご視聴ください。 [15:05〜15:20] フロントエンドチームのスキルテスト評価システム改善の取り組み メルペイのフロントエンドチームの採用フローの一つにスキルテストがあります。スキルテストの評価観点や評価方法をどのように作成し、改善し、運用しているのかを紹介します。 [15:20〜15:50] WYSIWYGウェブページビルダーを支える技術的マジックの裏側 We will share our journey on how we built a WYSIWYG Webpage Builder, from concept to launch. With a flexible component system and conditional rendering functionality, our WYSIWYG page builder streamlined workflows, eliminated the need for coding and technical skills to create beautiful and responsive webpages, and allowed our company to create 150% more webpages than without it. We will describe our practices for building a WYSIWYG page builder, such as finding a balance between versatility and complexity. Attendees will leave with a deeper understanding of how to leverage shared knowledge to create an efficient and effective page builder. [15:50〜16:20] メルカリのユーザージャーニーにおける不正防止の取り組み As part of Trust and Safety [ TnS ] backend team, it is our goal to provide a safe environment for transactions to mercari customers. So I would like to focus upon some architectural designs and discussions in choosing certain components in our fraud-prevention system and want to provide a glimpse into real-time-fraud-detection work we are doing with Apache Flink. [16:20〜16:50] 日本におけるお客さま本人確認と今後の技術的課題 In this talk, Mann, Chris and Tim of the KYC Team, in charge of Mercari customer identity verification services, will discuss identity verification history in Japan, its most recent and biggest evolutions through the 2018 amendment of the “Act on Prevention of Transfer of Criminal Proceeds” and the potential incoming challenges that Japan might have to face in the near future due to innovative technologies such as Deepfake. [16:50〜17:20] メルカリへのFIDO導入の経緯とこれからの展望、課題から得た学び フィッシング耐性のある認証として注目されているFIDOやパスキーの導入にメルカリがどのように取り組んでいるかを知っていただき、実際に実装を進めた中で感じた苦悩や課題、そこから得た学びをLiveディスカッションの中でお楽しみいただけます。 「Merpay & Mercoin Tech Fest 2023」のお申し込みは こちら から。 イベント詳細 開催日時: 2023年8月22日(火)〜24日(木)12:00-17:30 概要: IT企業で働くソフトウェアエンジニアおよびメルペイ・メルコインの技術スタックに興味がある方々を対象にしたオンライン技術カンファレンスです。事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングについて知ることができる、メルペイ・メルコインにとってこの夏一番のお祭りです。 テーマ: Backend、Architect、SRE、Data Platform&Management、Machine learning、Frontend、iOS、Android、QA/テスト、 組織づくりなど 参加費:無料 場所:オンライン 参加方法:こちらの ページ にてお申し込みください。 【 公式サイト 】 本イベントに関する追加情報があれば、随時 @mercaridevjp でお知らせしますので、気になる方はぜひフォローをお願いします。
この記事は、 Merpay Tech Openness Month 2023 の20日目の記事です。 はじめに こんにちは。メルペイ VP of Platform Engineering の @nu2 です。 私は2023年5月に入社したばかりのNew Memberです。 入社後すぐに本企画への参加を @mikichin さんから打診され、お伝えするテーマに困りましたが「OPENNESS」マインドで今まで外から媒体を通して感じていたメルペイの技術アセット(Culture, Technology Stack, People)に対し、実際に肌で感じ取ったことを今回お伝えします。 Culture 「Go Bold, All for One, Be a Pro」 メルカリのバリュー(特にGo Boldについて)は、一度は聞いたことがある言葉ではないでしょうか。 これらのバリューを体現するための取り組みが本当に浸透しているとオンボーディングで感じますし、その成果として実際にメンバーの皆さんから無意識的にバリューを発揮している場面も見受けられました。 またメルペイのミッションである「「信用を創造してなめらかな社会を創る』を実現するために「なめらかな社会」の一部である企業内活動でもなめらかさを意識した行動を実践している方々がとても多いと感じました。 記事にあるやさしいトレーニング は日本語話者、英語話者間の分断を抑制する主たる行動だと思います。 日本語話者、英語話者が共に参加する会議体ではプレゼン資料もしくはドキュメンテーション内に「やさしい日本語」や「やさしい英語」と文面で注意喚起を促しています。 更にその会議体は書籍「amazonのすごい会議」で語られるようなテキスト中心の内容であり、MECE フレームワークに近い漏れのない議論が展開されます。 (「amazonのすごい会議」の内容が気になる方は是非メルカリをご利用ください :-)) 私も入社時に自分のUser Manual を英文で準備し、メルペイのミッションを達成するための自分の内なるミッションを公開しています。 Technology Stack 基本的には公開されている 情報 の通りです。 これらを使いこなすメンバーは「全員 Be a Pro」です。また、プロフェッショナルであろうと日々業務に向き合っている姿は尊敬します。 特筆すべきはScalability の元で各要素技術による品質が担保されていることです。 そのScalability を支えるArchitect チームが独立した組織として存在し、非機能要求グレード、非機能要件をなめらかに設計していくチームの存在はとても頼もしいと感じています。 後述するTech Fest でもArchitect チームからメンバーが登壇予定ですので是非視聴してくだされば幸いです。 また公開されている要素技術を使い倒すTechnique 指向だけではなく、要素技術を生み出すTechnology 指向も持っているメンバーも多いです。 またメルペイに限った話ではありませんが、グループ全体の社内業務におけるChatOps の活用がかなり進んでいると感じました。 COVID-19 の流行以降バーチャルオフィスと化しているSlack 上のオペレーションで業務が成立することは効率面で非常に有用です。 入社以前は会社全体の生産性を向上する為に技術選定や導入を推進する役割を担っていたので、追い求めていたChatOps がここにありました! People 行動をバリューに照合し評価する文化があるので、特にその人にとっての挑戦点が共有されていれば周囲が本当にサポートしてくれます。 英語を話す場合に私のCEFR(英語をはじめとした外国語の習熟度や運用能力を同一の基準で評価する国際標準)レベルがまだ低い状態なので、日々挑戦の連続なのですが特に英語話者の方々がサポートしてくださり最初の1on1 でもきちんとコミュニケーションが成立する成功体験を手助けしてくださいました。 また課題を設定し、それに対し自律的な行動や実践を行なっているメンバーが多いのは、連日更新される連載記事の内容からも感じ取れるのではないでしょうか。 改めて、「Merpay Tech Openness Month 2023」で公開されている記事を確認してみてください。 https://engineering.mercari.com/blog/entry/20230531-notice-merpay-tech-openness-month-2023/ まとめ 個人の感想をまとめており大変恐縮していますが、私は今後 VP of Platform Engineering として事業成長につながる取り組みをエンジニアリングから支えていきたいと考えています。メルペイでは事業を的確なタイムラインで成長させるモメンタムを描いており、エンジニアリングへの要求は成長に応じるScalability、それに伴うコストを最小限にとどめること、インシデントを抑制することなど総じて高いです。継続的かつ安心安全なサービスデリバリーを実現するためにブロッカーとなる要素を除きメルペイのミッションを達成するためにひとつひとつ取り組んでいきます。 最後になりますが、8月22日(火)から8月24日(木)までの3日間にわたり、「Merpay & Mercoin Tech Fest 2023」をオンライン開催します!本イベントにてより解像度の高い内容の話を公開予定となっています! 是非とも参加登録の上、ご視聴ください。 https://events.merpay.com/techfest-2023/ 明日の記事は CTOの@kimuras さんです。引き続きお楽しみください。
この記事は、 Merpay Tech Openness Month 2023 の19日目の記事です。 こんにちは。メルペイのバックエンドエンジニアの @youxkei と@fivestarです。 前回の記事 「Goでテスト用のフィクスチャをいい感じに書く」 では、fixtureパッケージを導入することで、テスト用のデータベースのフィクスチャを以下のような点で「いい感じに」記述できるようになりました。 モデルのIDのセットなどの自明な処理が暗黙的に行われる 記述した際のコードのネストがモデルのリレーションを表す その際、マッピング用のモデルが必要な場合は暗黙的に用意される fixtureパッケージを使用することで、テストケースに必要な値をモデルにセットしつつ、モデル間のリレーションがわかりやすい形でフィクスチャを記述することができます。 各モデルに対応するマッピング用の関数はほぼ定形なので、これを自動生成することで汎用的に使うことができそうです。 そこで、モデルとなる構造体一覧からfixtureパッケージを生成するツールyofixtureを作成しました。 yo のジェネレータシステムをベースに実装したので、yoにあやかってツールの名前をyofixtureとしました。ただ、yofixtureはyoで生成したモデル以外でも使用することができます。 yofixtureによるfixtureパッケージの生成 前回の記事と同様に、具体例として以下のような図書館蔵書モデルを考えます。 package models type Library struct { LibraryID string Name string } type Book struct { BookID string Name string LibraryID string } type Author struct { AuthorID string Name string } type BookAuthorMapping struct { BookID string AuthorID string } yofixtureでは、CLIで以下のようなyamlの設定ファイルからfixtureパッケージのソースコードを生成することができます。 models: - name: Library relations: - Book: { LibraryID: LibraryID } - name: Book - Author: {} - name: Author - name: BookAuthorMapping 設定ファイルでは、モデルとそのリレーションを設定することができます。 ここでは、前回の記事の具体例で使用した図書館蔵書モデルと、LibraryとBook、BookとAuthorのリレーションを定義しています。 LibraryとBookのリレーションについては「Book.LibraryIDにLibrary.LibraryIDをセットする」という形で定義しています。フィールドの値をセットする形であれば、設定ファイルでリレーションを定義できます。 BookとAuthorのリレーションについては、BookAuthorMappingを介したリレーションのため、設定ファイルでは定義できません。 このような複雑なリレーションを実現するために、yofixtureはプロトタイプパターンを用いて既存のリレーションの挙動を変更できるようなコードを生成します。 BookとAuthorのリレーションは、以下のように生成したfixtureパッケージ内でリレーションを定義できます。 package fixture import ( "testing" "path/to/models" ) func init() { prototype.ConnectToBook = func(tb testing.TB, fixt *Fixture, book *models.Book, connectingModel any) { tb.Helper() switch connectingModel := connectingModel.(type) { case *models.Author: // BookとAuthorのリレーションの場合、BookAuthorMappingを追加する fixt.AddBookAuthorMapping(tb, fixt, prototype.CreateBookAuthorMapping(func(m *models.AddBookAuthorMapping) { m.BookID = book.BookID m.AuthorID = connectingModel.AuthorID }), ) } // デフォルトの処理 connectToBook(tb, fixt, book, connectingModel) } } このように、fixtureパッケージに生成されるデフォルトのprototypeを拡張することで、BookからAuthorへのリレーションを張る際の独自の処理を定義することができます。 さらに、prototypeの拡張によって、以下のようにモデルを作成した際のフィールドのデフォルト値を定義することができます。 package fixture import ( "testing" "github.com/google/uuid" "path/to/models" ) func init() { prototype.CreateLibrary = func(setters ...func(l *models.Library)) *models.Library { l := &models.Library{ // デフォルト値をセット LibraryID: uuid.New().String(), } for _, setter := range setters { setter(l) } return l } } yofixtureで生成したfixtureパッケージを使う 生成したfixtureパッケージは、前回の記事と同様に使うことができます。 import ( "testing" "path/to/fixture" "path/to/models" ) func TestListBooksByAuthor(t *testing.T) { author := fixture.Author(func(a *models.Author) { a.Name = "夏目漱石" }) f := fixture.Build(t, fixture.Library(func(l *models.Library) { l.Name = "ほげ図書館" }).Connect( fixture.Book(func(b *models.Book) { b.Name = "吾輩は猫である" }).Connect(author), fixture.Book(func(b *models.Book) { b.Name = "こころ" }).Connect(author), // 同じauthor ), ) setupDB(t, f.Collect()) // 以下テストコードが続く } まとめ fixtureパッケージを生成するyofixtureを作成しました。 yofixtureは現在社内ツールとして使われていて、オープンソース化も検討しています。ご期待ください! 明日の記事は @nu2 さんです。引き続きお楽しみください。
この記事は、 Merpay Tech Openness Month 2023 の18日目の記事です。 はじめに メルペイでBackend Engineerをしている @champon です。 普段はApache Airflow(以下、Airflowと呼ぶ)を用いた与信枠計算パイプラインの運用をしています。 この記事では、Cloud Composer(以下、Composerと呼ぶ)を用いたAirflowからSlack通知を行う実装例について紹介します。 AirflowにおけるSlack連携 メルペイの与信枠計算では、データパイプラインとしてComposerを用いたマネージドなAirflowを採用しています。Airflowでは、有向グラフ上に定義したタスクを順次実行していくワークフロー(DAG)を構築することができます。自分のチームでは、Airflowを運用する上で主にアラートの用途として、DAGが失敗したときにSlackに通知が送られるようにしています。これにより、DAGの失敗にチーム全員が気付けるようになり、またより早く修正対応に取り組むことができるため、総合的に運用コストを下げることができます。 以降では、AirflowのSlack連携において、Secret Managerを導入したよりセキュリティの高い実装例について記載します。 Secret Managerについて Secret Managerは、APIキーなどの機密性の高いシークレットデータを暗号化して保存することができるGoogle Cloud Platform(以下、GCPと呼ぶ)上のサービスです。シークレットデータのバージョニングも行えるため、汎用性高く使用することができます。 さて、Slack連携をするためにはSlackで発行したトークンが必要になります。このトークンは機密性の高い情報であるため、露出した場所に保管するのはリスクがあります。例えば、Composerでは環境変数を設定することができますが、設定した値はGCPコンソール上で直接確認できるようになっています。該当するGCP Projectのコンソールにアクセスできるユーザーは限られてはいますが、暗号化されてない上に露出した形で保管されているのは良くないです。 また、環境変数への設定はシークレットデータのローテーションにおいても不都合が生じます。万が一シークレットデータが漏洩してしまった場合、以前まで使っていたシークレットデータを失効し、新しいものに設定する必要があります。しかし、Composerでは環境変数の更新に際してComposer環境が再起動されます。Composer環境の再起動には数十分の時間を要するため、開発の遅延やスケジュール実行との競合などが発生する恐れがあります。 そこで、SlackのAPIトークンをSecret Managerで管理することで、Composerと切り離した形で運用することができ、より安全かつ柔軟性を高めることができます。 Cloud ComposerからSecret Managerにアクセスする ComposerからSecret Managerにアクセスするには、terraformにおいて以下のように定義し、Composerのサービスアカウントに対してRoleを付与します。 resource "google_service_account" "composer_service_account" { project = “my-project” account_id = "composer-service-account" display_name = "A service account for composer" } resource "google_secret_manager_secret" "slack_api_token" { project = “my-project” secret_id = "slack-api-token" } resource "google_secret_manager_secret_iam_member" "composer_service_account_is_secret_accessor_to_slack_api_token" { project = “my-project” secret_id = google_secret_manager_secret.slack_api_token.secret_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${google_service_account.composer_service_account.email}" } Secret Managerからシークレットデータを取得するためには、GCPのClient Libraryを用いることで実現可能です。Pythonでは、SecretManagerServiceClientのaccess_secret_versionメソッドを用いてSecretのIDおよびVersionを指定することで、シークレットデータを取得できます。 client = secretmanager_v1beta1.SecretManagerServiceClient() name = client.secret_version_path(“my-project”,”slack-api-token”,”latest”) response = client.access_secret_version(name=name) secret_data = response.payload.data.decode(“utf-8”) AirflowではPythonOperatorを使用することでPythonでDAGのタスクを実装できるため、タスク単位でAPIトークンを取得してSlack通知を行うことも可能です。 Airflow Connectionを使う方法 先の節では、GCP Client Libraryを用いてSecret Managerからシークレットデータを取得しました。しかし、Airflow Connectionという機能を用いることで、Secret ManagerとAirflowを直接連携できます。 まず、Airflow ConnectionでSecret Managerをbackendにするために、terraformにおいてgoogle_composer_environmentのairflow_config_overridesを設定する必要があります。また、Slack通知との連携を行うためのパッケージを別途インストールするようにします。 resource “google_composer_environment” “my_composer” { config { software_config { airflow_config_overrides = { secrets-backend = "airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend" } pypi_packages = { apache-airflow-providers-slack = "" } } } } ※基本的な設定項目は省略しています また、Airflow Connectionを使用するためには、Secret ManagerのSecret IDのprefixを’airflow-connections’に指定する必要があります。 resource "google_secret_manager_secret" "slack_api_token" { project = “my-project” secret_id = "airflow-connections-slack_api_token" } 次に、Secret ManagerにJSONフォーマットでデータをアップロードします。 { “conn_id”: “slack_api_token”, “conn_type”: “slack”, “password”: “<YOUR SLACK API TOKEN>” } ※JSONフォーマットを使用する場合はapache-airflow>=2.3.0である必要があります。代わりにURIフォーマットも使用可能です ※conn_idはSecret IDからprefixを取ったものとなります あとは、SlackAPIPostOperatorを用いて、Slack通知を行うOperatorを簡単に実装することができます。 from airflow.providers.slack.operators.slack slack = SlackAPIPostOperator( task_id=”slack-notification”, channel=”#test-channel”, conn_id=”slack_api_token”, text=”Hello World”, ) まとめ 本記事では、Composerで構築したAirflowにおいて、Secret Managerを用いたSlack連携の実装例について紹介しました。GCPのドキュメントを読むとAirflow Connectionを用いる方法が推奨されていますが、同じSecretを別のサービスにも用いておりSecret IDを変更したくない(後からprefixを付けたくない)等の理由があれば、より柔軟に対応できるClient Libraryを用いる方法が良いかもしれません。 明日は @youxkeiさんと@fivestarさんの記事です。引き続きお楽しみください。
この記事は、 Merpay Tech Openness Month 2023 の16日目の記事です。 こんにちは。メルペイのバックエンドエンジニアの @panorama です。 今回はメルカードのバックエンドにおいて「外部APIへのリクエストの流量制御を実現するためにCloud Tasksを導入した話」をご紹介します。 背景 メルカードのバックエンドでは提携している企業さまのAPIをさまざまな処理で呼び出しています。(以降このAPIを外部APIと呼びます。) メルカードをご利用いただいているお客さまが増えるにつれ、通常のご利用時やカスタマーサポートでこの外部APIを呼び出す処理も増え、急激に負荷がかかることも発生するようになりました。 もし、時間当たりの処理件数が外部APIの処理速度を上回ってしまうと処理が失敗してしまいます。 しかし外部APIは自社内のマイクロサービスとは異なり、自分たちで自由にスケールすることはできません。 対策 外部APIの呼び出しは同期的でなくても良いケースがあります。 また今回の高負荷時の調査で「同期的でなくても良い呼び出し」が同時に複数起こっているケースを観測していました。 これらを非同期の呼び出しに変更し、処理レートを設定することで、非同期化できた部分の負荷を一定以下に制御することができます。 今回の課題は瞬間的な高負荷(スパイク)への対処です。 負荷が上がっている場合の最もシンプルな対策は外部APIのスケールを依頼することですが、平常時は現在の処理速度で問題なく、一瞬の高負荷な状態さえなだらかなものに変えることができれば解決できます。 実現手段 上記の実現方法としては、例えば以下のような案が考えられます。 アプリケーションレイヤーで非同期化する 定期実行バッチで非同期化する 流量制御が可能なキューイングのマネージドサービスで非同期化する それぞれ 言語の並行処理・並列処理の機能を用いて非同期化し、非同期化された処理全体のレートが一定以下になるように連携する 処理対象をデータベースに一時的に記録し、その記録をもとにバッチ処理で回収する マネージドサービスがサポートする設定項目で自サービスの求める流量制御を実現する ことによってその処理レートを設定します。 メルペイではGo/k8s/GCPを使用しているので、1はgoroutine、2はCronJob、3はCloud Tasksが該当します。 1に関して「複数のpodで複数のgoroutineが動く環境全体の外部API呼び出しのレートを一定以下にする」ということをアプリケーションレベルで実現するのはかなり実装コストが掛かります。また「非同期化の対象が増えたときに容易に追加できる」「対象毎に処理レートの設定が可能な」汎用的な仕組みである必要があります。 2の方法はシンプルですが、高負荷時以外の多くの場合でバッチに拾われるまでに無駄な遅延が発生します。(CronJobのスケジュールの間隔は最短でも1分) 一時的なアクセス増においてのみ外部APIの呼び出しをなだらかにしたいという目的だったので、それ以外ではほとんど即時に処理されてほしいです。 3のCloud Tasksを選択した場合はその特徴から上記1、2の問題点は解消されます。 フルマネージドサービスなのでキュー管理を意識する必要がない メルペイではGoogle CloudのリソースをTerraformで管理しているため、キューの追加やレートの変更はtfファイルの変更で容易にできる 一定のレートを超えないように流量制御するが、それ以下のときはほとんど即時実行される(つまりスパイクのみなだらかにしてくれる) また標準でリトライ機構があるため、一時的に外部APIが不安定になり失敗した場合でも、自前でリトライ処理を実装する必要がありません。 今回は使用していませんが、タスクを実行する時間を指定するスケジューリングの機能や重複排除などもサポートしています。 一方で、今回は非同期化対象が外部APIなので、 外部APIの認証情報をCloud Tasksに持たせたくない リクエスト/レスポンス時のログを自社サービス内で落としたい(ロジックに通したい) という事情がありました。 よってこれらを解決しつつ、Cloud Tasksの利点を活用することにしました。 前提知識 先程の「実現手段」でCloud Tasksの特徴を挙げましたが、ここでCloud Tasksについて説明しておきます。 Cloud Tasks Cloud TasksはGoogle Cloudが提供する非同期タスク実行を行うためのフルマネージドサービスです。 タスクと呼ばれる単位をキューに送信すると、非同期に取り出されてワーカーに送信されます。(タスクをワーカーに割り当てることをディスパッチと呼びます。) ディスパッチのレートにはトークンバケットアルゴリズムという流量制御のアルゴリズムが使われており、大量のトラフィックが来てもバケットサイズ、レート設定で定めた基準以下に抑える(均一にする)仕組みになっています。 ディスパッチ後、ワーカーから2xxのHTTPレスポンスが返ってくるとタスクは完了されたとして消去されます。2xx以外のレスポンスコードが返ってきた場合やリクエストがタイムアウトした場合はリトライに移行します。 Cloud Tasksのユースケースはたくさんありますが、 公式のガイド には”Managing third-party API call rates”が含まれています。 このようなキューイングのサービスは他にもあり、AWSだとAmazon SNS、AzureだとAzure Queue Storageなどがあります。 今回の構成 通常であれば以下のように直接外部APIを呼び出す構成になると思います。 しかしこの場合はCloud Tasksが外部APIの認証情報を持ち、ログはCloud Tasksの実行ログとして落ちます。 そこで今回は次のように一度自分のサービスをproxyのように経由させて外部APIの認証を乗せています。 これによって 外部APIの認証情報をCloud Tasksに入れる必要がない リクエスト/レスポンスをロジックにかけて処理することができる ログを自サービスに落とせる 失敗した場合に記録したり、失敗の詳細をSlackに通知したりできる などのメリットがあります。 つまりCloud Tasksを純粋にタスクの非同期タスク実行管理の目的で使っています。 このやり方のデメリットとしてはCloud Tasksからの呼び出しで自サービスを経由する分だけ、自サービスのトラフィックは増加します。 今回非同期化の対象となった部分は全体を通してリクエスト数はそこまで多いわけではなく、平常時と高負荷時の差がかなり激しいケースだったためこの部分はあまり大きな問題ではありませんでした。 また副次的な効果としてリトライ機構があるので、サービスが不安定になったりメンテナンスに入ったとしても非同期タスクが失われることを考慮する必要がありません。 まとめ 今回は非同期化可能な外部API呼び出しの流量制御においてCloud Tasksを使った例を紹介しました。 一般的なユースケースに比べて少し特殊な例だったかもしれませんが、今後非同期タスク実行を検討するときの選択肢として本記事の知識がお役に立てば幸いです。 私は今まで非同期実行についてそこまで深く考えることはなく、Cloud Tasksを使用するのも初めてだったのでとても勉強になりました。 こういうパターンで他に良い方法や面白い知識があれば、教えていただけるとうれしいです👀 それでは、ありがとうございました。 明日の記事は@krisさんです。引き続きお楽しみください。 ※ 追記: Cloud Tasksからメルカードバックエンドへの通信経路や認証については省略しています
はじめに この記事は、 Merpay Tech Openness Month 2023 15日目の記事です。 こんにちは。メルペイ加盟店精算チームのバックエンドエンジニア @r_yamaoka です。 今日は現在自分がリードして取り組んでいるテストコードの改善について紹介したいと思います。 抱えている課題 私が所属している加盟店精算チームのマイクロサービスは加盟店さま向けサービスとして欠かせないものであり、メルペイ最初期から存在するサービスです。他のマイクロサービスにあまり無い特徴として多数のバッチ処理を行っている点が挙げられます。 お客さま(メルペイユーザー)がお店で行った決済は、一定の頻度で集計し決済手数料を差し引いた上で加盟店さまの銀行口座へ振り込むことになります。 最終的な振込金額を算出するまでの流れとしては 個々の決済金額のリコンサイル(会計マイクロサービスとの金額照合) 日次集計 締日集計・返金分相殺・振込データ作成 振込指示 といった複数の処理を順に跨ってデータが処理されていきます。またこれら決済金額を直接集計するもの以外にも実行された振込の結果を取得してシステムに反映させたり、各バッチが作成したデータに誤りや矛盾が無いかをチェックしたりするバッチがあり、そのデータの流れは極めて複雑です。 こうした複数のデータ集計を伴う処理は前提条件が複雑になりがちで通常のテストだけでは動作を担保することが難しく、時折トラブルにより集計データの修正や整合性の確認をエンジニアが手作業で行うケースが発生し、品質面の改善が必要な状況となっています。 また長い時間を経てデータ構造やアーキテクチャーが最善とは言えない状態にもなっておりその解消のためにリアーキテクチャーを検討しています。この場合、変更したコードが既存の動作を破壊していないことを担保するテストコードは非常に重要ですが、前述した複雑さによりテストの網羅性が低くまたテストの可読性が低いことも相まって安全なリアーキテクチャーに自信を持てていないのが現状です。 解消のためのアプローチ テスト粒度とその責務を分類する テストの粒度は一般に「単体テスト」「結合テスト」等と2つ程度に別けられることが多いかと思いますが、これらは実質的に大小関係の定義のみで実際に何をどこまで担保するのかについては人・組織によりバラつきがあります。 私のチームのテストコードも例に漏れず主に「ユニットテスト」「E2Eテスト」が存在しますが、ユニットが簡素な代わりにE2Eで非常に多くのパターンを実装して網羅していたり、反対にユニットは充実している代わりにE2Eが非常に簡素であったりと統一感がありません。 このためテストケースの認知負荷が高く日々の開発で苦慮しており、まずは粒度の分類とその責務を定義しコードを整理するための基準を作ることにしました。 この問題に対する解の一つとして とあるGoogle Testing Blogの投稿 ではSmall, Medium, Largeと3つに分類しそれぞれでどの機能をどこまで使うのかについて定義されています。 (注: 13年前の記事なので現在もこのような分類を運用しているかは不明です) 当初はこれに倣ったテスト構成を考えていたのですが、SMLでは規模の分類に絞った命名であり大分類として何をテストするのかが依然として分かりづらく感じました。そのためSMLを参考にしつつテスト範囲が狭い順に「ユニット」「コンポーネント」「インテグレーション」という説明的な命名を採用し、解釈のバラつきはドキュメントの作成と丁寧な説明でカバーすることとしました。 ユニットは個々の関数やメソッドを対象としたテストで、データや条件分岐の面で高い網羅性を持たせることを主眼においています。コンポーネントは各種APIやバッチ単体を対象とし、マイクロサービスを構成する個々のコンポーネントが正しく動作するか確認します。インテグレーションは複数のバッチを跨いで最終的に正しいデータが得られるかを確認します。 基本的な考え方としてはカバーする範囲が狭い低コストなテスト(個々の関数・メソッド等の粒度)ほど網羅性を高くし、反対に範囲が広く高コストなテスト(API・バッチ等の粒度)ほど網羅性を低くするピラミッド型としています。 参考(Testing Pyramid): https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html 範囲が広いテストで網羅性も担保しようとするとコードの複雑性が増してメンテナンスが困難になるだけでなく実行時間が伸びます。また安定性を欠いた所謂FlakyTestになりやすく逆に開発の足を引っ張りかねないため、どの粒度でどこまでを担保するのかを明確にするのが重要です。 各分類にどの程度労力をかけるべきかについては様々な議論があるかと思いますが、 Google Testing Blogの記事を参考に 概ね以下のように考えています。 ユニット: 5 コンポーネント: 3 インテグレーション: 2 コンポーネントとインテグレーションテストの割合が増えていますが、これは前述の通り複数の処理をまたがって行われる複雑な処理を検証しなければならないという特性をカバーする意図です。 以下に3つの分類とその責務をまとめます。 ユニットテスト 責務: コードの細部において高い網羅性を持った検証を行う 条件分岐や投入データのパターンを可能な限り網羅する レイヤー内に閉じたテストを指す レイヤーを跨ぐコード(usecaseからrepositoryの呼び出し等)はモックorスタブで対応する 外部コンポーネント(マイクロサービス、Pub/Sub、GCS等)との通信もモックorスタブで対応する ※コードのアーキテクチャーとしては、概ね一般的なレイヤー分けをしたクリーンアーキテクチャーと考えて頂いて差し支えありません。 コンポーネントテスト 責務: サービスのコンポーネント単体として一気通貫な動作(各APIのリクエスト〜レスポンス or バッチ単体での起動〜終了まで)を検証する 仕様書を網羅すること 試験環境(各個人の端末やCI環境)内で加盟店精算サービスを稼働させるテストを指す 外部マイクロサービスとの通信を要する箇所は極力 bufconn と社内テストフレームワークでエミュレートする 参考: https://engineering.mercari.com/blog/entry/gears-microservices/ インテグレーションテスト 責務: 複数のバッチを通して行われたデータ処理の正当性を検証 基本的な動作環境はコンポーネントテストに準ずる バッチAで処理したデータをバッチBで処理しその値をチェックする、というようなテスト 網羅性は追求せず主に正常系と重要な異常系のみに絞る 記述スタイルを統一する 粒度の分類ではテストコードを整理し認知負荷を下げることを目指していますが、個々のテストの記述方法を統一することで更にその効果を高めることができます。そのためテスト実装の細かいスタイルについても話し合い、これもチームとして合意しました。 参考として以下にいくつか例を挙げます。 値の検証にはアサーションを使用する Goでは標準でテスト結果のアサーション機能が提供されていません。これは「エラーメッセージは重要なので自ら考えて書くべき。記述のコストは高いがエラー分析やオンボーディングが楽になるので回収できるはず」というGoの思想によるもので、標準提供の関数とif文等の条件分岐を使い素朴な形で実装することが推奨されています。 参考: https://go.dev/doc/faq#assertions しかし、自分が経験した限りでは手動ではどうしても手間がかかることと複数のエラー要因について配慮したメッセージを記述しようとすると冗長になることが多く、結局のところ t.Errorf(“want %v, got %v”, want, actual) というようなあまり中身の無いエラーメッセージになりがちです。またerrorやstructの検証のようなコードはそれなりに難解な記述になってしまい、あまり恩恵を感じられていません。 それであるならいっそアサーションライブラリをを利用する方が簡便に記述でき、エラー分析はデバッガー等を駆使することでカバーすればよいというのが今のところの自分の考えです。 ライブラリには testify と go-cmp を採用しています。基本的には前者でチェックしますが、主にstructやproto messageはエラーメッセージの可読性や記述の容易さから後者でチェックしています。 未だ議論の余地がある事柄と思いますので、これが絶対の正解というわけではないですが少なくとも我々のチームとしてはこちらの方が合理的であるという判断のもと採用することにしました。 原則としてテーブル駆動で記述する 既存のテストコードには以下のような記法が散見されています。 TestXXX(t *testing.T) { t.Run(“test pattern1”, func(t *testing.T) { // do something }) t.Run(“test pattern2”, func(t *testing.T) { // do something }) } 前述の通り、加盟店精算サービスのテストは前提条件が複雑でモックやデータベースのセットアップの記述が難しいため、この記法にも一定の合理性があると言えます。しかし、このまま網羅性を向上しようとすると重複部分が多く保守性に難が生じることが予想されます。また再利用部分が無いため個々のテストケースを最後まで読まないとどのような検証が行われているのかわからなく認知負荷が高いことも欠点です。 そこで基本に立ち返りテーブル駆動で統一することに決め、複雑なセットアップは以下のように各ケース毎にfuncで定義することにしました。 参考: https://github.com/golang/go/wiki/TableDrivenTests setupMock func(ctrl *gomock.Controller) (*mock.MockXXXService, *mock.MockYYYService) prepareQueries func(ctx context.Context) []*spanner.Mutation こうすることでパターンの記述は少々長くなってしまいますが、ケースが増えても重複が膨れ上がることがなく検証内容とパターンを別けて読み込め認知負荷を下げることができます。 テストでも命名を省略しない まず最初のケースですが下記サンプルのk, vとは何でしょうか?testCasesはテーブル駆動のケース定義と考えられるので、大概map[string]struct{ … }型と類推はできますが必ずしもそうとは限りません。vという変数は生存期間が極短い使い捨て変数として使いたくなる名前なので、下に続く検証部分が長くなった中でうっかり別の用途として使ってしまうと混乱を引き起こすかもしれません。 for k, v := range testCases { t.Run(k, func(t *testing.T) { …. 代わりにname, tc等とするとどうでしょう。明らかに理解が容易になったことがわかるかと思います。k, vとタイプの手間はほぼ変わらないのでこの僅かな手間は惜しまない方がよいです。 なお、必ずしも直接的な命名を採用する必要は無く、可読性が担保できるのであればどのようなものでも問題ありません。IDEやVSCodeの自動生成の場合テストケースは tt とされることが多いようなのでこういった慣例やチームの標準に倣うのもよいでしょう。 for name, tc := range testCases { t.Run(name, func(t *testing.T) { …. 次のケースです。このretはreturn(戻り値)から命名されたのだと思いますがさて何が入っているのでしょうか?errorかもしれませんし新規発行されたユーザーIDか、はたまたUser型のstructのポインターかもしれません。 ret := createUser(ctx, userName) assert.NotEmpty(t, ret) これもやはり説明的な変数を採用し、何が入っているか一目でわかるようにするべきです。 userID := createUser(ctx, userName) assert.NotEmpty(t, userID) 流石にプロダクションコードでこういった命名がされることはないのですが、特に小規模なテストではついやってしまいがちです。しかし、書いた時点では正しく認識できていても2,3日もすれば書いた当人すら忘れてしまいますし、コードは日々成長していくものなので少々の手間は惜しまず、将来に渡って理解容易性を損ねないよう常に細部まで気を配るべきです。 自らサンプルを実装する これまでの取り組みによってテスト改善のための方針をまとめ、チームのエンジニアに認識してもらうことはできたはずですが、本件をリードしているエンジニア(私)以外のメンバーの頭にある姿は微妙に異なっている可能性が高いです。また0から書いたコードをレビューに出すのは少々勇気が必要かもしれません。 そこで既存テストが無い部分については、最初にサンプルとなる実装を行い他のエンジニアが参照できるようにしておき、既存のものがある場合でもいくつか新しい形への移行を行います。こうすることで全員の認識を揃え、バラつきをより抑えることができるでしょう。その後は積極的にコードレビューに参加し、あるべき形へ誘導していくことも重要です。 おわりに 変化の激しい今日ではシステムは常に改善されていくものであり、その礎となるテストコードは決して軽視できません。既存のテストが膨大なためこの取り組みはまだ完了していません。しかし、一部新しい書式で書かれている部分については良好な感触を得ており、品質の向上とリアーキテクチャーの遂行に貢献できると確信しています。 今回の記事が皆様のテストコード改善の参考となれば幸いです。 明日の記事は @panorama さんです。引き続きお楽しみください。
はじめに こんにちは、mercari.go スタッフの monkukui です。 6月15日にメルカリ主催の Go 勉強会 mercari.go #22 を YouTube でのオンライン配信にて開催しました。 この記事では、当日の各発表を簡単に紹介します。動画もアップロードされてますので、こちらもぜひご覧ください。 Goの標準ライブラリに学ぶジェネリクス 1つめのセッションは tychy16 さんによる「Goの標準ライブラリに学ぶジェネリクス」です。 発表資料: https://speakerdeck.com/tychy/gonobiao-zhun-raiburarinixue-buzienerikusu Go1.18 でリリースされたジェネリクスの機能に関して、標準ライブラリでの使用例を題材に紹介しました。ジェネリクスの使い所や、使うことで得られる恩恵などを掘り下げたあと、ジェネリクスを使うことが難しいユースケースなどにも触れました。 Go1.21 で標準パッケージに追加される slices/map の紹介や、Go におけるジェネリクスの今後の展望などの話もあり、非常に興味深い話が盛りだくさんでした。 業務でジェネリクスの導入を検討している方にはとても参考になる発表になっているかと思いますので、興味がある方はぜひご覧ください。 Hashicorp/raftからraftを学ぶ 2つめのセッションは toshinao_ さんによる「Hashicorp/raftからraftを学ぶ」です。 発表資料: https://speakerdeck.com/t10471/hashicorp-raftkararaftwoxue-hu raft とは、複製されたログを管理するための分散合意アルゴリズムであり、etcd や cunsul などで用いられています。発表の前半では、raft に関する 2 つの論文を要約し、raft アルゴリズムの詳細な説明がされました。発表の後半では、Hashicorp/raft パッケージの具体的なコードに触れながら API の仕様や実装の詳細についての説明がされました。 raft に関する理論的な特徴から、Hashicrop/raft の具体的な実装まで広く深く紹介されており、非常に興味深い発表でした。 raft に関する論文や、参考書籍などは以下を参照してください。 https://github.com/ongardie/dissertation#readme 最初に公開された博士論文 https://raft.github.io/raft.pdf ↑ の論文からコンセンサスアルゴリズムの部分を抽出した論文 https://www.oreilly.co.jp/books/9784873119977 raft を使ったシステムのハンズオンが記載されている Go再入門 3つめのセッションは ques0942 さんによる「Go再入門」です。 発表資料: https://speakerdeck.com/ques0942/golangzai-ru-men 元々 Go メインで開発を行っていたが、一度 PHP 使いに転向し、再度 Go に入門した経験を持つ @ques0942 さんによる、 Go を学び直す上で得られた知見や、考え方の変化について紹介します。 発表の前半では、Go のインターフェースの使い方について紹介しました。他の言語と比較しながら、その使い方について掘り下げました。発表の後半では、Go のエラーハンドリングについて紹介し、標準ライブラリと、よく使われていましたがアーカイブされてしまった pkg/errors や、サードパーティライブラリの morikuni/failure について、それぞれの特徴に触れながら説明が行われました。 他言語を用いた経験が豊富な ques0942 さんだからこそ見えてくる Go の特徴などが語られており、非常に興味深い発表でした。 おわりに 今回は、Go 言語の様々なライブラリを題材として、Go を用いて開発する人にとって幅広く有用な内容をお送りしました。内容はどれも奥深く、運営としても非常に勉強になりました。 ライブで視聴いただいた方も録画を観ていただけた方も本当にありがとうございました! 次回の開催もお楽しみに! イベント開催案内を受け取りたい方は、connpassグループのメンバーになってくださいね! メルカリconnpassグループページ