Gaudiy Tech Blog

Gaudiyの技術、開発組織、カルチャーについてお伝えするブログです

GoとCobraを用いた新規マイクロサービス用ボイラープレートの自動生成CLIツールでコスト削減した話

こんにちは。ファンと共に時代を進める、Web3スタートアップ Gaudiy でソフトウェアエンジニアをしている ryio1010です。

私は弊社が提供するファンコミュニティプラットフォーム「Gaudiy Fanlink」の開発において、フィーチャーチームの一員として、主にバックエンド開発を担当しています。

バックエンドのアーキテクチャにはマイクロサービスを採用していますが、会社のフェーズ的に試行錯誤の段階であることや、それに伴うチーム体制の変更がよく起きていることもあり、新しいマイクロサービスの立ち上げも頻繁に行われています。

私自身もこれまでの業務で2〜3つの新しいマイクロサービスを立ち上げる経験をしてきました。

今回は、これらのマイクロサービスの立ち上げと運用の経験から、特に立ち上げフェーズにフォーカスし、改善を行った事例をご紹介したいと思います。

1. マイクロサービスの概要とGaudiyのシステム構成について

本記事をお読みの皆さんにとって、マイクロサービスの概念はすでにご存知の内容かもしれません。しかし、後続の内容をより深く理解していただくために、まずはマイクロサービスの基本的な概念と、Gaudiyにおけるシステム構成の現状を簡潔にご説明します。

1-1. マイクロサービスとは?

マイクロサービスは、大規模なアプリケーションを小規模かつ独立したサービス群として構築する設計手法です。このアーキテクチャスタイルでは、各マイクロサービスが特定の機能やビジネス要件に特化し、独立して開発、デプロイ、運用されます。

例えば、Gaudiyでは、ユーザー関連の処理を担う「user-service」、投稿関連の処理を担う「post-service」などが存在します。

マイクロサービスはそれぞれ独立しているため、Go、Kotlin、TypeScriptなど、異なるプログラミング言語での開発も可能です。

実際にGaudiyでは、これらの言語を使用したマイクロサービスを運用しています。

主なメリットは以下の通りです:

  • 開発とデプロイメントの迅速化: 各マイクロサービスは独立して開発・デプロイできるため、迅速な更新が可能。
  • 耐障害性の向上: サービス間が疎結合になるので一つのサービスに障害が発生しても、他のサービスには影響が少ない。
  • 複数技術スタックの利用: 異なるサービスで異なる技術スタックを採用できる。

一方でデメリットも存在するため、考慮に入れておく必要があります。

  • 通信の複雑さ: サービス間の通信が多く、複雑になる傾向がある。
  • データ管理の難しさ: 分散したサービス間でのデータ一貫性の維持が課題。
  • 運用コストの増加: 個別サービスの監視・管理には追加の労力とリソースが必要。

多くのメリットがあるマイクロサービスですが、上記のようなデメリットもあります。 この記事では、マイクロサービスの運用におけるコスト増加の部分、特に新規マイクロサービスの立ち上げコスト削減に焦点を当てています。

1-2. Gaudiyのシステム構成

現在のシステム構成は下記のようになっています。

Fanlinkシステム構成

フロントエンドではReact(Next.js)とTypeScriptを用い、BFFとしてApollo ServerとTypeScriptを採用しています。バックエンドではGoとKotlin・Pythonを使用したマイクロサービス群を構築しています。 これらの技術スタックを基に、ブロックチェーン技術やAI・LLM(Large Language Models)技術を取り入れながら、当社のプロダクト「Fanlink」の開発を進めています。

バックエンドに焦点を当てると、ホスティング環境としてGoogle CloudのGKE(Google Kubernetes Engine)を使用しています。現在、20近くのマイクロサービスをGKE上で運用しています。

2. 既存の新規構築手順と課題感

2-1. これまでのマイクロサービス構築手順

まず、弊社で新規マイクロサービスを立ち上げるために必要な要素と、従来の構築方法についてご説明します。

新規マイクロサービスの立ち上げには、大きく分けて以下の3種類が必要です。

  • マイクロサービス用のgRPCサーバーのコードベース(Go)
  • GCP環境でホストするためのGCPリソースを作成するTerraformファイル群
  • 各環境へのデプロイなどを担うCI/CDやDBマイグレーションを行うGitHub Actions用のyamlファイル群
2-1-1. gRPCサーバー用のコードベース(go)

まずマイクロサービスのサーバー本体となるコードベースについては、一部はKotlinを採用していますが、新規サービスは基本的にGoを使用しています。

Gaudiyにはecho-serviceという、いわゆる新規マイクロサービスの元になるコードベースがあります。

このテンプレートには、ログクライアントの設定、DBクライアントの設定、サーバーの起動など、マイクロサービスに必要な基本機能がGoで書かれています。

これまではこのecho-serviceをコピーする形で新しいマイクロサービスのコードベースを作成していました。コピーしていく中で、コードベースの中の名前を新しく作成するマイクロサービスのドメインに合わせるように手作業で修正していくという形でした。

手作業で修正する必要があり、その量もそれなりになるため、細心の注意を払っていたとしてもヒューマンエラーが発生したり、そもそもecho-serviceからの新規サービス作成が初めてな人も多いので必要以上に時間がかかってしまうことも少なくない状況でした。

2-1-2. terraformファイル

GCP環境でマイクロサービスを動作させるためには、Service AccountやSpanner InstanceなどのGCPリソースが必要です。

これらのインフラ管理はTerraformを用いて行っており、既存のファイルに新規マイクロサービスのリソースを追加する必要があります。

この作業に関しては手順書があるため、他の作業に比べると比較的スムーズに作業できていました。

2-1-3. cicd用yamlファイル

各マイクロサービスには下記のためのgithub actions用のyamlファイルがあります。

  • 各環境へdeploy用
  • SpannerDBのマイグレーション用
  • 各PRの確認用(ユニットテスト実行・lint実行など)

これらに関しては手順書もなく、これまで新規構築したことのあるメンバーに逐一どのファイルが必要かを確認して手動で作成している状況でした。

ファイルの追加漏れなどヒューマンエラーも発生しやすい状況となっており、実際私もDBマイグレーション用のファイル追加がもれており、DBのマイグレーションが実行されず追加し直すといった手戻りが発生してしまった経験がありました。

2-2. 課題感

マイクロサービスは上記でお伝えした利点があり採用しているのですが、会社のフェーズ的にも試行錯誤をしていく中で、実績値で平均すると2-3ヶ月に1回くらいのペースで新しいマイクロサービスを立ち上げていました。

私は新規マイクロサービスの構築に多く関わる機会があり、初めて構築を行う中で以下の課題があると個人的に感じていました。

  • 初期構築手順書はあるものの、十分に更新されておらず有識者に確認する必要があり開発の手が止まってしまう
  • 手順書には書かれていない暗黙知があり、チームメンバーによっては暗黙知を持っておらず新規構築したもののなぜがうまく動かないといったことが起こりうる
  • 基本的に手作業でテンプレートとなるディレクトリをコピーする形でコードベースを作るのでタイポなどのヒューマンエラーが発生し、作業が手戻りしてしまう
  • そもそも手順が多く手作業が大変

上記の状況の中で、実際に新規マイクロサービス基盤の構築が完了しコア機能の開発に入るまでに1-2人日くらい工数がかかっているため、少なからず開発スピードを鈍化させる原因になっていることは明らかでした。

また基本的にどんなマイクロサービスを立ち上げるとしても、そのマイクロサービスが扱うドメインの名称が違うだけで新規立ち上げの作業自体は定型的なものであるため、十分に自動化できうるものでした。

3. 具体的なアプローチ方法と効果

3-1. アプローチ方法

先にご紹介した新規マイクロサービス構築に必要な3種類の作業のうち、Terraformに関しては手順書通りの追記で問題なく、大きく工数を要していなかったため、GoサーバーのコードベースとGitHub Actions用のyaml群の生成を自動化の対象としました。

詳しい実装については割愛しますが、おおまかに下記のような処理を実装している「gauctl」という名前のCLIを作成しています。

  1. GitHubのリポジトリからecho-serviceをクローン(tarファイル)
  2. 取得したtarを解凍
  3. 変更が必要な箇所を新規マイクロサービスのドメイン名で置換
  4. GitHub Actions用のyamlのテンプレートを基に、新規マイクロサービス用のyamlを生成(Go言語のテンプレート機能を利用)
  5. 適切なディレクトリに生成ファイルを出力

3-2. 利用した技術について

利用した技術スタックは以下の通りです。

  • Go言語
  • Cobra(GoのCLI アプリケーションフレームワーク)

Go言語はCLIツールの作成に適しているだけでなく、Gaudiyではバックエンドに広く採用されており、多くのエンジニアが読み書きできるため、将来的なメンテナンスの観点からも採用することにしました。

またCobraはGo製のCLIフレームワークで、容易にコマンド生成やフラグ処理などを直感的なAPIで実装できるため、開発の効率やメンテナンスが容易になるという点から採用しました。

ここではより具体的な実装イメージを持っていただくためにも、yamlの生成で利用したGo言語のテンプレート機能とCLIアプリケーションフレームワークとして利用したCobraについて簡単な使い方をご紹介できればと思います。

3-2-1. Go言語のテンプレート

今回yamlの生成にはGo言語のテンプレート機能を利用しました。

この機能を使うことで動的なデータ(今回の場合は新規マイクロサービスのドメイン名)を静的テキストファイルに組み込むことができ、”text/template”パッケージから利用できます。

ディレクトリ構成は下記の感じです。(一部抜粋)

├── transform
│   └── templates
│       └── sample1.yaml
│       └── sample2.yaml
│   └── embed.go // yamlファイルをbyte配列で読み込む処理を記載
│   └── transform.go // yamlの中身を変換する処理

yamlファイルの中身で変換したい部分には「{{ . }}」と記載します。

(この部分がtemplateの機能によって変換されます。)

// transform/templates/sample1.yaml
name: Check PR for {{ . }}-service

on:
  push:
    branches:
      - "main"
    paths:
      - "{{ . }}-service/**"
  pull_request:
    paths:
      - "{{ . }}-service/**"

まずembed.goで”embed”パッケージを利用して”templates内のファイルをbyte配列で読み込んでいます。そしてそれをTransform関数の引数として渡しています。

// transform/transform.go

// contentにyamlファイルのbyte配列を、replacedStrには変換したいドメイン名が入る
func Transform(content []byte, replacedStr string) ([]byte, error) {
  // New関数でテンプレートを作成して、Parse関数で文字列を解析し、テンプレート定義に追加する
	t, err := template.New("yaml").Parse(string(content))
	if err != nil {
		return nil, fmt.Errorf("failed to parse: %w", err)
	}

	var buf bytes.Buffer
    // Execute関数で、テンプレートの内容を変更し、bufに格納する
	if err = t.Execute(&buf, replacedStr); err != nil {
		return nil, fmt.Errorf("failed to execute: %w", err)
	}

	return buf.Bytes(), nil
}

上記のTransformが実行されると、sample1.yamlは下記のようになり、それを指定したディレクトリに出力しています。

(replacedStrにfooを指定した場合)

// transform/templates/sample1.yaml
name: Check PR for foo-service

on:
  push:
    branches:
      - "main"
    paths:
      - "foo-service/**"
  pull_request:
    paths:
      - "foo-service/**"

このようにtemplate機能を使うことで動的なコンテンツを簡単に作成することができます。

3-2-2. Cobra

CLIのディレクトリ構成は下記の感じです。(一部抜粋)

(cobraのコマンドをインストールして自動生成もできます。)

$ go install github.com/spf13/cobra-cli@latest
$ cobra-cli init
├── cmd
│   └── create.go
│   └── root.go
├── main.go

サブコマンドもコマンドでファイル生成できます。

(↓のコマンドを実行すると、cmd下にcreate.goが生成されます。)

$ cobra-cli add create

Cobraでのサブコマンドの実装はCommandというStructのフィールドに値を定義していく形で作成します。

基本的なフィールドの説明は下記になります。

  • Use: コマンド名とその使用方法(引数など)を定義
  • Short**:** コマンドの短い説明
  • Args**:** コマンドに渡された引数を検証する関数を定義
  • RunE: エラーを返却できる、コマンドが実行された際に呼び出される関数の定義

上記以外にも色々と設定できる項目はあるものの、基本的にRunEにサブコマンドが実行された時に実行したい処理を書くことでCLIを実装することができるようになっています。

// cmd/create.go
package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

var (
	createExample = `
* Create new micro-service from template
	`

	createCmd = &cobra.Command{
		Use:     "create [domain_name arg]",
		Short:   "Create new micro-service from template",
		Example: createExample,
		Args: func(cmd *cobra.Command, args []string) error {
			// 引数に関する処理(引数の検証など)をここに記述できる
			if len(args) != 1 {
				return fmt.Errorf("requires 1 arg(s), received %d", len(args))
			}
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			// 以下にコマンドが実行された時に実行したい具体的な処理を記述

			return nil
		},
	}
)

func init() {
	rootCmd.AddCommand(createCmd)
}

CobraはKubernetesやDockerなどでも採用されているとのことで筆者も初めて使用してみましたが、直感的で分かりやすく、素早く軽量のCLIを作成するツールとして優れていると感じました。

3-3. 実際の効果

CLIをリリースしてから、既に4つの新規マイクロサービスが立ち上がっており、全てこのCLIを使用いただいています。

以前は1-2日かかっていた環境構築作業が、定型作業を自動化することができたため、現在ではおよそ半日で完了するようになりました。

手順は以下のように変わりました。 特に時間を要していたecho-serviceのコピーとドメイン名の置換作業、およびGitHub Actions用のyamlファイルの作成作業が、コマンド一つで完了できるようになりました。

3-3-1. これまで
  1. echo-serviceをコピー
  2. echo-serviceのドメイン部分を新規マイクロサービスの名称に置換し、Goサーバーのコードベースを作成(ここに多くの工数がかかっていた)
  3. Terraformファイルに必要なリソースを追加
  4. GitHub Actions用のyamlファイル群を追加(ここも手順書がなく、工数がかかっていた)
  5. PRを出す
  6. レビューし、mainブランチへマージ
  7. CI/CDにより新規マイクロサービスの環境が構築される
3-3-2. CLI導入後
  1. CLIを実行(マイクロサービスのコードベースとGitHub Actions用のファイル群を生成)
    • 実際のコマンド例: foo-serviceを作りたい場合
      • gauctl create foo
  2. Terraformファイルに必要なリソースを追加
  3. PRを出す
  4. レビュー、mainブランチへマージ
  5. CI/CDにより新規マイクロサービスの環境が構築される

主にヒューマンエラーや経験不足(暗黙知だった部分)が原因で発生していた手戻りや、定型的な作業を自動化することで、工数を大幅に削減できたのかなと思います。

4. おまけ(CloudRun→Kubernetes移行について)

少しおまけ的な話にはなりますが、当時、マイクロサービスのホスティングはCloud Runを利用していました。そのため、初回リリース時にはCloud Runで動作するコードベースを自動生成するCLIを作成していました。

その後、全社的にCloud RunからKubernetesへのホスティング基盤の移行が行われました。この移行は、横断的なチームであるenableチームによって進められました。 それに伴い、CLIもKubernetesで使用できるように機能拡張が必要となりました。

詳しい話は別の機会に書かせていただければと思いますが、Cloud Runとは違いKubernetesで動作させるためには、deployment.yamlやservice.yamlなどの設定ファイルが必要になります。 したがってKubernetesに対応するために、これらの設定ファイルを生成するコマンドを追加し、必要なファイルの自動生成が可能になりました。

Kubernetesへの移行経緯や移行方法の詳細は、以下の記事で詳しく書かれています。興味のある方はぜひご覧いただけるとうれしいです! 

techblog.gaudiy.com

5. おわりに

この記事では、マイクロサービスを運用する中でも特に新規立ち上げフェーズにフォーカスし、改善を行った事例についてお伝えさせていただきました。

改善を行う際のコストと効果を比較して改善するべきかを熟考することは重要ですが、定型的な作業の自動化は、ヒューマンエラーによる手戻りの防止や開発スピードの改善に寄与できると思うので、積極的に改善して良い部分になるかなと思います。

また、定型的な作業は自分の所属するチーム内だけではなく、他のチームも同様の課題を抱えがちです。そのため、開発組織全体の開発スピード向上に寄与しやすい部分なのではないかと個人的には感じています。

Gaudiyでは、課題に直面した際、本人が主体的に積極的に解決に取り組む文化があります。これは一人で行うのではなく、周囲を巻き込みながら(アドバイスをもらったり、改善方針のすり合わせなどで相談に乗ってもらえる)課題解決を進めていけるので気軽に改善活動に取り組めると感じています。

今後もフィーチャーチームに在籍しながら、横断的に解決できる課題を見つけ、開発スピードの向上に寄与していければと思います〜!

今回の記事が皆さんの参考になれば幸いです。

Gaudiyでは、一緒に働くエンジニアを積極的に募集しています。当社の技術や開発スタイルに興味を持った方は、選考前のカジュアル面談も可能ですので、ぜひ採用ページからお気軽にご応募ください!

site.gaudiy.com

Kubernetes初学者が担当したGKE移行プロセスの全貌

はじめまして。Gaudiyでエンジニアをしているあんどう(@Andoobomber)です。

クラウドネイティブ全盛の世の波に乗り、この度 Gaudiy では Cloud Run から Google Kubernetes Engine (GKE) への移行を行いました。

この記事では、その移行プロセスの全体像を共有し、得られた教訓と今後の展望を探ってみたいと思います。

1. Before After: 移行の概観

1-1. Before

Before

以前までの構成は、

  • マイクロサービスの実行環境として Cloud Run を使用
  • 監視ツールにはGCPの Cloud Monitoring, Cloud Logging, Cloud Trace を使用
  • Pub/Sub→マイクロサービス間に API Gateway を経由
  • アプリケーションのデプロイは Github Actions が行う

といった感じでした。

1-2. After

現在の構成は、

  • マイクロサービスの実行環境としてGKEを採用。1つの Cluster 上で全てのサービスを動かしています。
  • 監視ツールにはDatadogを採用し、OpenTelemetry Collector経由でテレメトリーデータを流しています。
  • Pub/Sub→マイクロサービス間にESPv2を経由。
  • アプリケーションのデプロイはArgo CDが行い、Github ActionsArtifact Registryに push した Image を Argo CD Image Updater が Watch し、Cluster にデプロイしています。

といった感じに変わりました。

2. なぜGKE環境に移行したのか

移行に至った経緯は様々あるのですが、主に↓の3つが理由です。

  • クラウドネイティブな技術選択をしたい
    • CNCF Projectsをはじめとする、コンテナ技術の最新トレンドを採択したい
    • Kubernetes Controller で自由に機能拡張できる
  • Ops 起因で重要な目的があった
    • これが大きな理由だったのですが、機密情報に当たるので申し訳ないですが詳細は伏せさせていただきます
  • 機械学習関連でマシンリソースを選びたかった
    • Gaudiyではレコメンドエンジンなど、AIにも注力しており、通常サーバーとは異なるマシンリソースが必要になった

3. 移行のプロセス

普通なら移行計画を立ててKubernetes(k8s)に移行していくところですが、僕はk8s未経験であり前提知識も全くなかったので、k8sを学ぶことから始めていきました。

3-1. Kubernetesを学ぶ (1週間: 2023/10/01~)

Kubernetes完全ガイド 第2版を読んでサンプルアプリを作ってました。これが無かったら移行完了までのスケジュールは大きく変わっていたと思うくらい良書でした。

この時に、DeploymentやServiceなどのk8sオブジェクトを理解するとともに、ライフサイクルやエコシステムなども学んでいきました。

3-2. Dev on GKE環境作成 (2-3週間)

FanlinkのアーキテクチャはFE → Load Balancer → BFF → BE(micro services)という構成になっており、今回は Load Balancer 以降を GKE に全く同じ環境を作成して、FEの向き先を変えて移行することにしました。

GKE環境を作る際に様々な技術を使用しましたが、1つずつ書いていくと書ききれないので、以下にやったことを抜粋して記載します。詳細は割愛しますが、後に別記事としていくつか公開する予定です。

  • Cluster の作成
  • 各マイクロサービスのKubernetesオブジェクト定義
    • サービス: 27個、cronjob: 8個ほどありました。
  • External Secrets の使用
    • Secret Managerを参照するため使用。
  • OpenTelemetry Collector の使用
    • テレメトリーデータをOpenTelemetry Collectorに集約させて、まとめて Datadog にexportしています。
  • Gateway API の使用
    • つい先日GAとなったKubernetes Gateway API を使って、Load Balancerを管理しています。
  • ESPv2 の使用
    • REST から gRPC へのトランスコーディングとして、Envoy ベースの ESPv2 を使用しています。
  • Argo CD の導入
    • k8s リソース管理及びCDとして、Argo CD を採択しました。
  • etc…

3-3. Staging on GKE環境作成 (2日)

基本的には環境変数の変更で、Devで作成したyamlをStagingも同じように作っていくだけなのでそこまで難しくはありませんでした。

この時、開発チームへGKE環境に触ってもらう・受け入れテストのお願いをアナウンスしました。

3-4. Private Clusterへの移行 (1-2週間)

今まではデフォルトの設定で Cluster を作成していましたが、Private Cluster にすることでコントロールプレーンとノードに対して外部アドレスを割り当てなくする(≒よりセキュアにする)ことができると知り、Stating/Prod 環境は Private Cluster で建てることにしました。

  • GCPリソースのTerraform
    • GKE Cluster
    • Network / Subnetwork
    • Firewall
    • etc…
  • Tailscale Operator 導入
    • Private Cluster の操作を Tailscale Network 経由で行うようにしました。
  • Private Clusterでの環境再作成
    • コントロールプレーンのパブリックエンドポイントアクセスを無効にして、よりセキュアな Clusterへと変更しました。

3-5. Prod on GKE環境作成 (2日)

こちらもStaging同様にyamlを複製し、Prod用の環境変数を割り当てる程度なのでそこまで難しくはありませんでした。

ただし、cron処理やoutbox patternが存在したので現行の環境に影響を与えないように気をつけながら作業を行っていきました。

3-6. 負荷試験・受け入れテスト (1週間)

Staging環境を作成した段階で、開発チームへのアナウンスや負荷試験をProd環境作成と並行して行っていきました。

最後の大詰めとして以下のような作業をコツコツと進めていきました。

  • バグの解消
    • 環境変数や外部サービスとの通信部分で特にバグが起きました…
  • Pod/Nodeリソース・スケール値の設定
    • Grafana k6で負荷試験をして、想定負荷に必要なリソースを計算しました。幸い、瞬間的に同時アクセスが大量に走るような複雑なサービスではないので、ある程度の負荷を余裕もって耐えれる位の設定値にしました。
    • ただ、それでも単一Podだと落ちた時が怖かったので複数Podをminimumとし、負荷試験に耐えられる位をmaxとして設定しました。

3-7. リリース(2023/12/04)

2023/12/04の深夜にCloud Run環境からGKE環境にSwitchしました。移行後から1週間くらいは異常が起きないかモニタリングを続けましたが、特段大きな問題はなくアプリケーションが稼働していたのでホッとしました。

4. 移行後の感想

4-1. 良かった点

  • おおよそ2ヶ月でk8s環境へ移行できた。
    • 経験者の知見もいただきながらですが、初学者ながらわりと順調に進めることができたと思います。
  • 最新のクラウドネイティブ技術への追従ができる。
    • CNCF Projectsに登録されているプロジェクトを見て活かせそうなツールがないかみるのが最近楽しいです。
  • リソースの調整
    • 機械学習系のマシンが使えるの嬉しい。
  • レスポンスタイム向上
    • 全体約200msほど
  • Datadogに移行したこと
    • 高機能でかなり使いやすいです。今後のSRE業務に拍車がかかりそうです。

4-2. 課題点

  • k8sの学習コストが高い
    • k8sへの完全移行は達成したものの、k8s APIやらeBPFなど学ぶことがいっぱい。まだまだこれからだなと感じています。
  • 運用コストも高い
    • 学習コストに近いですが、定期的なk8sのアップデートやCSP(クラウドサービスプロバイダ)の知識がないとアプリケーションを落としかねないので、運用は簡単とは言えなさそうです。
    • また、適切なリソース設定をしないと費用面でも無駄なコストがかかってしまいます。

5. 今後の展望

現在は最小構成のk8s環境で動いているので、様々なクラウドネイティブ技術を積極的に試していきたいと考えています。

  • Ciliumの導入
  • eBPFの調査
  • Flux (GitOps)
  • Kubernetes Custom Controller 作成
  • Config Connector

6. 結論

Kubernetes移行はかなり大変でしたが、Gaudiyのビジョンに向けたソリューションと技術的な野心を反映した、意義深い変革の一歩だったと思います。

クラウドネイティブ技術の進化に伴い、より良いサービスとソリューションを提供するために、今後もアップデートを続けていきたいと考えています。

この領域に知見のある方や、Gaudiyでのプロダクト開発に興味のある方がいたらぜひお話ししましょう!

site.gaudiy.com

site.gaudiy.com

Authlete を活用して OAuth 認可サーバの構築期間を短縮した

こんにちは、Gaudiyでソフトウェアエンジニアを担当しているsato(@yusukesatoo06)です。

弊社が提供するファンコミュニティプラットフォーム「Gaudiy Fanlink」において、外部サービスにAPI提供をする必要があったことから、外部連携について色々と調べて実装しました。

そこで今回は、調査からサーバ構築までのプロセスと、そこで得た学びや気づきを共有できればと思います。

1. OAuthとは

1-1. OAuthの概要

OAuthとは、Webやモバイルアプリケーションなどのクライアントアプリが、ユーザーに代わって他のウェブアプリがホストしているリソースにアクセスできるよう設計されたプロトコルです。(みなさんご存知かもしれないですが...)
参考) OAuth 2.0 とは何か、どのように役立つのか? - Auth0

OAuthを使用することで、ユーザーはクライアントアプリに対して、自身のID/パスワードを直接提供せず、他サービスとの連携を可能にします。そのため、複数のサービス間で連携を行うために非常に重要な技術となっています。

※OAuthが解決する課題については、LayerXさんの記事が参考になります。

1-2. OAuthのフロー

OAuthには認可フローがいくつか存在し、大きく以下の4つで構成されます。

  • 認可コード
  • インプリシット
  • リソースオーナー・パスワード・クレデンシャルズ
  • クライアント・クレデンシャルズ

それぞれのフローには、異なる用途やセキュリティ要件があるため、適切なフローを選択する必要があります。ここに関しては、以下の記事が詳しいです。

kb.authlete.com

僕たちは、上記記事でも推奨されている認可コード + PKCE(※)パターンを採用しました。

※ 認可コード横取り攻撃に対する対策
参考) Proof Key for Code Exchange (RFC 7636) - Authlete

2. OAuthが必要な背景

2-1. 外部サービス連携

今回、OAuthが必要になった背景として、外部サービスからGaudiyのAPIをコールしたいという要求がありました。また実装に関しても、1, 2ヶ月程度で行う必要があり、かなりタイトなスケジュール前提でのAPI連携となりました。

(※ ただしビジネス的な要件でAPI連携が後ろ倒しになったため、まだ実運用には至っていません)

API連携を行う手段はいくつかあります。

  1. APIキーでの連携
  2. 独自方式での連携
  3. OAuthでの連携 など

今回は工期の関係や、後述する少し特殊な環境下での連携だったため、最初は1か2を選択しようと考えていました。

しかし最終的には、3のOAuth形式を採用することとなりました。その主な理由は以下です。

  • クライアントサイドの実装も独自となり、エコシステムを利用できない
  • 今後、別のサービスと連携する際の拡張性が乏しい

2-2. 他の連携方式との比較

1. APIキーでの連携

まず最初に検討にあがったのがAPIキーでの連携方式でした。

こちらはIP制限等と併用することで、一定のセキュリティを担保することができるかつ工数のかからない方式となります。

ただし今回、Fanlink APIをコールするクライアントが、サーバサイドだけではなくクライアントアプリも含まれる前提でした。そのため、早々に本手段は選択できないことが決定しました。

2. 独自方式での連携

前述した通り、今回の連携環境が少し特殊な関係で、独自方式の連携を検討していました。

具体的に説明すると、Fanlinkと連携サービスが同一のIdPとOIDC連携をしており、同じIdPのアカウントで作られたサービス間を連携する環境でした。

そのため、IdPで発行されたID Tokenを流用することでサービス間の連携ができないかを検討していました。

一般的な方式ではないですが、工期を考えるとOAuthをゼロから作ることが難しいため、本方式を検討しました。またセキュリティの監査会社に相談した結果、セキュリティホールとなる部分もありませんでした。ただし前述の通り、クライアントサイドも独自実装となるため、本手段も選択しませんでした。

そのため、僕たちは腹を括って短期間でOAuthの仕組みを構築することにしました。

3. OAuthの提供

3-1. 提供方式

短期間でOAuthサーバを提供する必要があるため、まずはどういった方式で提供できるかを検討しました。

その中で提供方式は大きく3つ出てきました。

  • フルマネージド
    • サービスプロバイダー側で提供されるOAuthサービスを利用する方式
    • 例) Auth0
  • ハイブリッド
    • サービスプロバイダー側で提供されるAPI群を利用し、自社で認可サーバを構築し提供する方式
    • 例) Authlete
  • フルスクラッチ
    • ライブラリ等を用いて、自社で認可サーバを0から構築し提供する
    • 例) fosite, hydra など

それぞれ以下のPros/Consがありました。 (Gaudiyの開発環境に依存する理由も含まれます)

サービス Pros Cons
フルマネージド 導入までの期間が圧倒的に短い。フルマネージドでの提供のため運用工数がかからない。Auth0等であればグローバルでの実績があり、セキュリティ面の担保もされている Firebase Authをすでに導入しており、IdP機能が既存サービスと競合してしまう。
ハイブリッド OAuth/OIDCに特化したサービスで、既存のIdPと競合しない。フルスクラッチに比べ運用工数がかからない。コアな部分はAPIとして提供されており、セキュリティ監査等をクリアした機能を利用できる。 フルマネージドに比べ、一定の開発/運用工数がかかってしまう。
フルスクラッチ フルマネージド / ハイブリッドと比較し、ランニングコストがサーバ費用のみ。 開発/運用工数がかなりかかる。セキュリティ監査など周辺工数/コストもかなりかかる。実装に問題があった際に、会社として大きなリスクを抱える。

3-2. 今回の選定方式

今回は前述した3つの方式のうちハイブリッド型を選択し、サービスとしてはAuthleteを採用しました。

すでに導入しているFirebase Authと競合しない点、フルスクラッチに比べると開発工期を大きく圧縮できる点が理由となります。

また開発者向けのドキュメントが充実していることや、Goで利用するライブラリも用意されていた点も決め手となりました。

4. OAuthサーバの構築

4-1. Authleteについて

では実際に、OAuthサーバを構築した際の内容に移ろうと思います。

本来であればここで苦労話を記載したいのですが、Authleteを活用したこともあり、1 ~ 2ヶ月の工期に対して意外とすんなり構築できました笑

今回採用したAuthleteは、RFCに準拠するエンドポイントをAPIとして提供していて、利用者はクライアントからのリクエストをバイパスするのみでOAuthサーバを提供できるサービスとなっています。 (詳しくはサービス概要をご覧ください)

https://www.authlete.com/ja/developers/overview/

そのため、まずは今回必要なエンドポイント群を整理するところから始めました。

4-2. 必要なエンドポイント

今回のOAuthサーバの提供にあたり、外部向けには大きく以下のエンドポイントを用意しました。

  • 認可エンドポイント
  • トークンエンドポイント
  • リソースサーバエンドポイント

それぞれ簡単に説明していきます。

認可エンドポイント

認可エンドポイントは、連携するサービスの認証/認可処理を開始するためのエンドポイントです。一般的には連携サービスの認証画面でログイン処理を行い、OAuthの処理を開始した後に、指定したリダイレクトURLが認可コードを付与された状態で戻ってきます。

仕様についてはRFC6749 3.1に仕様が記述されており、わりと柔軟に実装することができます。

例えばパスについては、フラグメントを含めなければどのような値でも利用することができます。

詳しい仕様はAuthleteさんの記事が分かりやすいです。

トークンエンドポイント

トークンエンドポイントでは、認可エンドポイントで取得した認可コードを用いてリクエストに利用するトークンを発行します。

またリフレッシュトークンを利用してリクエストすることで、トークンのリフレッシュも行うことが可能です。

仕様についてはRFC6749 3.2に記述されています。

リソースサーバエンドポイント

リソースサーバエンドポイントは、実際に認可されたリソースにアクセスするためのエンドポイントで、提供機能に応じて用意するエンドポイントとなります。

トークンエンドポイントで発行したトークンを用いてアクセスを行い、スコープに準拠したリソースであればOAuth連携したサービスから情報取得することができます。

上記以外にも、内部で利用するためのエンドポイントをいくつか用意しておりますが、今回は割愛させていただきます。

4-3. システム構成

今回、OAuthサーバを構築した際のシステム構成は以下です。

OAuthはHTTP/1.1をベースにしたプロトコルである一方で、GaudiyのバックエンドエコシステムがgRPCベースの構成となっているため、以下の形で実現しました。

構成図の通りではありますが、ポイントは以下です。

  • API Gatewayを構築し、OAuthに関する外部通信は基本API Gatewayでハンドリングすることで、プロトコル準拠の通信を実現
  • 後続サービスとの通信に関してはgRPCベースで通信を行い、Gaudiyのエコシステムを流用する
  • Authleteとの通信は基本的にパススルー方式とし、クライアントからのリクエストをほぼ加工せず送信することで、レスポンスも可能な範囲でそのままクライアント側に返却する

また外部公開するURL仕様やバージョニングも悩む部分が多かったです。

大手サービスが提供しているエンドポイントを調査すると以下のような仕様でした。

  1. Google

     https://accounts.google.com/o/oauth2/vX/auth
    
  2. Facebook

     https://www.facebook.com/vXX.X/dialog/oauth
    
  3. GitHub

     https://github.com/login/oauth/authorize
    
  4. Twitter

     https://api.twitter.com/oauth/authorize
    

上記のうちGoogleの形式を参考に、僕たちは以下のような設計にしました。

https://<domain>/oauth/vX/<method or resource>
例) https://<domain>/oauth/v1/authorize

API仕様が変わるケースは少ないと思いますが、外部連携を行う前提に立つとクライアント側との調整/修正が必要なため、後方互換性を担保しつつ切り替え可能にしました。

5. 開発を通じて

5-1. 開発を通じた学び/気づき

今回、OAuthサーバというRFCに厳密に準拠すべきサーバを開発して、色々と学び/気付きがありました。

まずRFCの内容が意外と解釈の余地があり、何かしらの指針がないと解釈に差が生まれる恐れがあるなと感じました。そのためAuthleteという、開発するための指針があったのは非常に助かりました。その一方で、RFCに準拠した自前の認可サーバを作る選択肢を取っていたら、途方に暮れる工数がかかっていただろうなと思います。

またこのようなプロトコルを策定した過去の技術者達のすごさを改めて感じました。Webサービスを開発しているとRFCを読む機会は少ないですが、一度RFCに準拠するサービスを作ることは非常に学びが多いなと感じました。

個人/チームとしては、GitHubのやり取りの中でRFCについて触れるなど、開発者としての成長を感じた場面もありました笑

5-2. フルスクラッチとの比較

フルスクラッチで開発した場合を想定し比較すると、半分以下の工数で実装できたのではないかと思います。工数を圧縮できた大きなポイントは以下です。

  • 基本的にAuthleteの設定後、Authlete提供のAPIをコールするだけでよいため実装方針が明確
  • RFCに準拠するために必要となる知識が圧倒的に少ない(とはいえ開発者としては理解しておくべきですが)
  • 自分たちの開発範囲が少ないため、セキュリティ監査などの対象/工数も削減できる
  • シンプルなものであればすぐに構築出来るため、動くものを確認しながら試行錯誤ができる

5-3. 今後の対応

これまでAuthleteを活用したOAuthサーバの構築に触れてきましたが、冒頭でも説明した通り、残念ながら実運用にはまだ至っていません。

本来であればOAuthスコープの設計をAPI毎に行う必要があり、スコープ設計もかなり重たい内容となる想定です。ただし今回は実運用を行うエンドポイントがなくなってしまったため、スコープ設計は後ろ倒しとなりました。

OAuthサーバの実運用を行った際は、再度スコープ周りの知見を共有できればと思います。

6. まとめ

今回はOAuthサーバの実装について、その採用背景から構築方法まで紹介させていただきました。調査した内容や実際に感じたこと含めてまとめてみたので、これからOAuthサーバの実装を検討している人の参考になれば嬉しいです。

また今後の実運用に向けて、OAuthのスコープ設計周りに知見がある人がいたらぜひお話ししてみたいです。

Gaudiyに興味を持っていただいた方は、ぜひ以下のサイトも覗いてみてください!

site.gaudiy.com

不確実性や心理的安全性に向き合い自己組織化するチームを作る実践プラクティス

こんにちは。Gaudiyでソフトウェアエンジニア兼スクラムマスターをしている Namiki ( @ruwatana ) です。

チームが向き合う不確実性が大きいと手戻りが増えて価値提供のリードタイムが遅くなる
チーム内の心理的安全性の低さや認知負荷の高さによってエンゲージメントが低下して従業員がオンボード・定着しにくい
...

などなど、昨今のチーム開発はこうした課題で溢れかえっていることかと思います。

結局のところ、我々は具体的にどんなプラクティスを行うことで、こうした課題を解決できていくのでしょうか?

本稿では、筆者と筆者が4ヶ月ほど前に配属することになったチームがこうした問題に対して執ったアプローチおよびその効果をより具体的に示すことができればと考えています。

プロダクトチーム開発を行う皆様に何かしらの参考になれば幸いです。

1. チーム構成と特性

Gaudiyでは、複数のIP(知的財産)に関するコミュニティプラットフォーム「Fanlink」を提供しています。

service.gaudiy.com

現在、Gaudiyにはプロダクト開発チームは複数存在しますが、筆者が所属するチームは「特定のIP向けの連携機能やエンハンス開発に注力したチーム」となっています。

そのため、下記のような特性があります。

  • IPプロバイダーとの協業をより求められ、チーム開発の中でIPの影響力が大きい
  • 連携機能はリッチで新規の機能開発が求められやすい
  • マイルストーンやスコープが変化しやすい

また、メンバー構成は以下の通りです。

  • 👥 プロダクトマネージャー 1名 (+ UXデザイナー1名も兼任)
  • 👥 UI/UXデザイナー 3名
    • お試し入社者を含む ※
  • 👥 フルサイクルエンジニア 4名 ← 筆者はここに所属しています
    • お試し入社者を含む
  • (その他、BizDev・コミュニティマネージャーとも連携)

※ お試し入社の制度に関しては採用情報をご覧ください
site.gaudiy.com

ピザ2枚ルール🍕にギリギリ収まるような人数構成です(これ以上増えても減ってもバランスが崩れそうなちょうど良い状態です)。

チームの中にデザイナーも所属しており、デザイン(ディスカバリー)と開発(デリバリー)のどちらの進捗も統合的に管理するデュアルトラックアジャイルのような開発手法をとっています。

弊チームだけでなくGaudiyのプロダクト開発チームは基本的にこの構成をとっているのが特徴です。

デュアルトラックな開発チームのプロセス例

2. 特性が生み出しうるリスクや課題

さて、こうした特性が以下のような問題を生み出すと考えられます。

2-1. プレッシャーが高くストレスフルな環境に陥りやすい

IPに密着したチーム特性ということで、特定IP向けのプロダクトが生み出すアウトカムが会社というよりも特にチーム(メンバー)に直結する構造となりえます。

完全内製なプロダクトなどと比較すると、先方と握った納期・スケジュールに間に合わせなければならず、何か問題が発生した場合に社内だけでなくIPにも影響が出てしまいかねないですし、先方の要望に叶った要件を着実にデリバリーしなければならないといった外部からのプレッシャーを比較的受けやすく、一概にはいえませんがストレスフルな環境に陥りやすい構造と考えられます。

2-2. 技術的な複雑性や負債が高くなりやすい

Fanlinkは、マルチテナント(IP)向けのプロダクトですが、IPからはIP特有の要望を受けることも少なくありません(要望をいただくことは率直にありがたいことです)。

その中で、機能追加したものが特定IP専用の機能にならないように極力、汎用的に要件を落とし込むという正解があるようでない難易度の高い判断が求められることもあります。

専用の機能が増えてしまうと、固有のロジックや他チームからしたら知りもしない機能が増え、複雑性や技術的負債が増加してしまいます。もしかすると、他チームが勝手に消しにかかってしまうかもしれません。

2-3. さまざまな不確実性が高い

また、さまざまな不確実性が高いということもいえます。

Gaudiyの推奨図書にもなっている広木大地さんの「エンジニアリング組織論への招待 不確実性に向き合う思考と組織のリファクタリング」によれば、不確実性は大きく下記の3つがあるとされています。例とともに分類します。

  • 目的不確実性
    • プロダクトにおけるマーケットに何が求められているのかの正解が見えない
    • 他の競合サービスなどの取り巻く環境の変化に適応しなければいけない
  • 方法不確実性
    • スケジュールに対して要件が決まりきらずに開発を始めなければならない
    • ある大きな機能を開発中に方針・優先度が変わってペンディング・ピボットする
    • チームにプラクティスが存在しない新しい技術を用いた実現方法を求められる
  • 通信不確実性
    • PdMやデザイナーが考えた要件がデリバリーする際に適切に伝わらず手戻りを起こす
    • お試し入社者が目の前のタスクをこなす上での情報やコンテキストの不足
    • リモート主体の開発で、メンバーに聞きにくい・意見しにくい

3. それぞれの課題に対するアプローチ

ここまでは、特に目新しい情報はあまりなかったと思いますが、もしかすると「うんうん」と頷いていただけた方もいらっしゃるのかなと思います。

ここからは、より具体的なアプローチをご紹介できればと思います。

3-1. チームの成長実感や自己肯定感の醸成

もしかしたら、目的不確実性によって価値提供をしてもマーケットのアウトカムを得られないということもあるかもしれません。

そんなときもプロセスに注目し、人やチームの良かった動きやことに対してねぎらいを与えるきっかけを作ることはとても重要であると考えます。

弊チームでは、1週間1スプリントとしてスクラム開発を行っており、レトロスペクティブ(振り返り)やスプリントレビューを定期的に実施して改善を続けてきましたが、その中のHowに工夫を加えていく動きが加速しているので一部をご紹介します。

3-1-1. レトロスペクティブにSpeed boatを導入

まず、レトロスペクティブでは従来 Win-Learn-Try のようなフォーマットを用いていましたが、割と個人の内省に使われることが多く、チームや他人に対してのフィードバックが欠如してきていました。これではみんなでやる理由があまりありません。また、ずっと同じ手法を使っていると飽きも来てしまうというのもあったかもしれません。

こうした問題に気づき、チームのメンバーが立候補して、レトロスペクティブの改善のオーナーを担ってくださいました。これによって、新フォーマットの Speed boat (国内ではSail boatという方がなじみが多いかもしれません)を行うことになりました。
※ちなみに現在は、また別のフォーマットを試すなど改善がどんどん進んでいます。

Speed boatでは、そのスプリントでのチームの動きを事象別に振り返ります。

テンションが上がったアイスブレイク的な内容(太陽)、チームが進むのに助けになった要因(追い風)、逆に止めた要因(錨)、わかった潜在的なリスク(岩)を書いて内容をシェアし、最後に次に取るべきアクションをボート上に乗せて投票でネクストアクションを決めるというシンプルな内容です。

チームのSpeed boatの様子 ※抽象化してます

これによって、他者の動きを褒めたり助かったなどの声が圧倒的に増えました。また、個人よりもチームに向いた振り返りができるようになり、みんなが納得感のある振り返りの場になったと思います。

自分の成果を自分であげるよりも、他者からフィードバックをもらえる方が自己肯定感を醸成できると思いますし、何より褒められたら嬉しいですよね?

Gaudiyは評価という仕組みがない会社なため、正も負もフィードバックを他者からもらえるシチュエーションが欠如しているという特性もあり、そういった部分にもアプローチできているのかなと考えています。

3-1-2. スプリントレビューにてPdMからの今週のスポットライト選出

スプリントレビューはプロダクトマネージャーが主導していますが、ビジネス周りのメンバーも含めてディスカバリー・デリバリーのスプリント内での成果を共有する場というのが基本的な立ち位置です。

そこに、毎週チームの中で良い動きをしたメンバーにスポットライトを当て、選出の理由とともに発表いただくアジェンダを追加するという動きがありました。

こちらもレトロスペクティブの改善と同様、チームメンバーのエンゲージメントを向上する要因となっていると思います。PdMからの視点をもらえるという意味でも、たとえ選出されなかったとしても選出理由を聞けるだけで学びが大きいなと感じます。

今週のスポットライトの例 ※

※ UNIFORMな人とは弊社のクレド(行動指針)の模範となっている人のことです
note.gaudiy.com

我々は、いつもPdMの方々にスポットライトをあてていただく側なので、この場を借りて弊チームのPdMの皆様にも素晴らしいアクションをとってくださったことを改めて讃えたいと思います。ありがとうございます!

3-2. チームとしての共有知やコンテキストレベルの底上げ

特定のメンバーだけが知っていること、複数人で会話する時に相互のコンテキストの違いによって前提が合わなくてコストがかかるといったことが起きないように、短いスパンでコンテキストの共有を行っていくことが必要と考えています。特にエンジニアは4名在籍しており、ここのコンテキストレベルのズレが大きく進捗にも影響しかねないです。

下記にそれらを実現するアプローチを示します。

3-2-1. SlackのハドルミーティングやGatherに常駐する

弊チームでは地方に住むメンバーもいたりするなどリモートが主体の開発を行っています。そこで、朝から晩まで、基本的にはSlackのハドルミーティングに常駐していつでも口頭での相談や同期ができることを実現しています。

話す時以外は大体ミュート状態にしている運用で、話しかける時に「〇〇さん今いけます?」的な形で質問や相談、ペア作業などがすぐにできるような形にしています。

これには、心理的安全性を高める効果があると考えています。

最近では、試験的に Gather というサービスを用いてバーチャルオフィスを構築し、チームのミーティングなどを全てこのサービス上で行ってみるような取り組みを全社的に行なっています。

隣り合うだけでプライベートの会話空間が作り出せるのでペアプロがしやすかったり、他の人が話している場合は吹き出しマークが出て視覚的にも様子がわかるなど、会話のし始めや既に会話しているところへのジョインのハードルを下げるような狙いもありそうです。

Slackハドルミーティングとの大きな違いとして、後から会話にこっそり入室しても何もフィードバックがない(気付きにくい)ので、リアルタイム空間のような他チームのミーティングの盗み聞きみたいなこともカジュアルにできるのが斬新だなと思います(笑)

Gatherでのチームミーティングの様子
(モザイクやアバターも相まって怪しさMAXですが健全な議論をしています)

3-2-2. QAをチーム全員参加で行う

Gaudiyでは、トランクベースの開発プロセスを取っており、ほぼ毎日リリースを行なっています。そのため、前日の夕方に各チームにてデイリーQAを行って、その日にマージされた改修の品質をE2Eでチェックしています。時間としてはその日のマージした分量にもよりますが、早い場合は5分で終わる場合もあれば、30分以上かかる場合もあります。

弊チームでは基本的には、Pull Requestにスクラムのアイテム(JIRAチケットで管理)を紐づけるような運用となっていて、マージすると自動的にQAレーンに移動するようにしており、チケットに書かれた受け入れ条件に沿ってQAを行うという流れで開発を行っています。

JIRAの自動化設定

一見、エンジニアや受け入れ条件を確認するPO/PdM向けの作業に見られがちですが、ここにはデザイナーのメンバーにも参加してもらっています。

これによって、ディスカバリーとデリバリーの認知の分断を防ぐ役割や、エンジニアが気付きにくいデザイン目線でのデザイン仕様との乖離を検出しフィードバックしてもらえるなどの効果が得られています。

また、エンジニアメンバーが有志で行なったチームのコンテキストとは関係のないバグ修正や改善などに関しても、レビューからQAをチームとして担当・チケット管理するようにしており、属人化や個人への責任を緩和できるような効果も期待しています。

ちなみにコードレビューにおいても、弊チームではすべての領域の改修に関してチームのエンジニア全員のApproveを原則もらう形としており、チームメンバーが行なった改修内容のコンテキストを必ず得られるように工夫しています。(日課として、溜まったレビューを捌いたり、連携するところから業務が開始します)

3-2-3. チームで判断しきれない問題はチーム外を積極的に頼る

チームのエンジニアメンバーにおいて、どういうアーキテクチャで価値提供するかを調査・検証しレビューするというプロセスがありますが、迷った挙げ句結論がなかなか出なかったり、そもそも判断するための確度が高くないといったことが往々にして起こります。

その場合は、積極的にチーム外を頼るようにしています。
チーム外とは、社内のEnabling Teamなどの他エンジニアはもちろん、外部のコンサルタントなども含んでいます。

例えば、チーム内で認可サーバを実装する必要が出た時は、社内に詳しい知見を持つ人がいなかったため、利用するSaaSの窓口から外部の有識者を紹介していただいて仕様のレビューを受けるなどを行なってきました。

もちろん、チーム内で考えうる方針案を複数用意しつつ比較し、最適と思う案をピックアップするところまでは行い、相手のレビュー負荷を下げてから依頼することを怠ってはいけません。

このような外からの知見を獲得するプロセスを経ることによって、チームの中にも知見やコンテキストが増えていくことを期待しています。

3-3. コンテキストフォーカスによる高速デリバリーの実現

コンテキストのレベルを底上げしたり、共有したりすることも重要ですが、フォーカスすることもとても重要です。

3-3-1. フロー効率とリソース効率を意識して使い分ける

例えば、「エンジニアが4人いるなら、半分ずつに割ってそれぞれで大きなコンテキストを抱えて並行稼働すれば、二つもアウトカムを同時に得られるのでは?」というのは誰しもが考えうるかなと思います。

果たして、本当にそうでしょうか・・・?

その2ラインのレビューやQAは誰がやるのでしょうか?お互いに1人しかレビュアーがいないと質の部分に問題が生じるリスクがあり、結局相互に行わないといけないとなると設計や要件、直面した問題の背景なども十分に理解する必要が出てきてしまいます。
それを知るための時間や不確実性(ここでは先ほど挙げた通信不確実性)が暗黙的には増えてしまうわけです。

また、2つの価値提供がともに2人月ずつかかる見積もりだった場合、どちらの機能も提供まで4人2ラインでの開発では単純計算で1ヶ月かかってしまいます。

こうした半分に分けて生産性をあげようという考え方はリソース効率と呼ばれます。

もちろん適切に使えば、この考え方も大きな成果を挙げられる手法であるといえます。例えば、だれもがやり方を熟知していて誰がやっても一定のスピードでできることであれば、ペア作業で行うよりも、それぞれが分散して並行に着手する方が効率が良いに決まっています。

しかし、実装方法も定まっていない・仕様も詳しく知らないような不確実なものでは、コンテキストレベルを合わせたり、異なる視点を入れながら検討して前に進む方が手戻りも少ない可能性があります。コンテキストスイッチも不要なので、頭がパンクせずにしっかりコトに向き合えるというメリットもあるでしょう。

こうした、一つの物事を優先的に着手から完成まで行う考え方をフロー効率といいます。

例えば先ほどの価値提供の例も、全員で取り掛かったら一つの機能は半月でリリースできるかもしれません。もう半月経つと次の機能を出せて1ヶ月後から見ると価値提供完了のスピード自体は変わらないですが、一つの機能を早く価値提供でき仮説検証できるというアドバンテージが生まれます。

リソース効率とフロー効率

デュアルトラックアジャイルを敷いている我々にはこの早く検証を回せる状態はとても相性が良いと考えています。

リソース効率とフロー効率の両者をケースバイケースで使い分けていくことが、より早いリードタイム(価値提供)を生み出せるといえるのではないでしょうか。

3-3-2. ペア/モブプログラミングをカルチャーとして根付かせる

不確実なものにはフロー効率という考え方が良さそうということが先ほどの結論ではありますが、弊チームでは積極的に2人でのペアプログラミングやさらに多い人数でのモブプログラミング(モブ作業)を行なって手戻りリスクを抑えたり、同時に把握が必要なコンテキストの量を減らしレベルを揃えやすいような取り組みをしています。

プログラミングに精通しない人からすると、ペアプロする(2人で1つのことをやる)わけだから単純に速度も1/2になるのでは?と考えるかもしれませんが、下記の理由で十分に有効であると考えています。

  • ソロだとコーディング時にわからないことが出て、調査に時間がかかるかもしれない
  • 各々が分散し目前のコンテキストに集中した結果、他のメンバーのコンテキストに対してのフォローが行き届かなかったり、あまり理解しないままコードレビューまで問題に気づかず、後から手戻りするコストが発生するかもしれない
  • 従来のペアプロのドライバ・ナビゲータという役割を超えた並行的なペアプロが実現可能になったため、何もしていない時間は実は少ない
  • お試し入社者を置いてけぼりにせず、ハマりやすい罠を共有することで、早期に立ち上がってもらえる

XP(エクストリームプログラミング)などで提唱されている従来のペアプロ手法では、ドライバとナビゲータに分かれて指示を出す人とコーディングする人がそれぞれ存在しました。

同じPC上で一つのエディタを使ってお互いに操作しなければならなかったので必ず待つ人が発生してしまうという物理的な問題もあったと思われます。

しかし現在は、Visual Studio CodeのLive ShareやJetBrains製IDEのCode With Meといった主要なエディタにて、複数のPCから同時並行作業ができるソリューションが登場したことにより、双方が手を止めずに同一のブランチを並行で修正できるようになりました。もちろん、リモートにも対応していて、ホストのローカルホストポートの共有やコマンドラインの実行なども可能になっています。

これを生かし、弊チームでもペアプロ中にある程度のやるべきことだけ最初に認識を合わせたら、あとは別れてコーディングをすることも多いです。例えば、テストケースの名前だけ先に書いてその実装を分担したりするといったイメージです。一人がミーティングになっても、コネクションを繋げておけば残りの一人が作業を続行することも可能です。

頻繁にチーム内でペアプロされている様子

Gaudiyでは、どんどん新しい仲間が増えており、ほとんどのチームがお試し入社のメンバーを迎えながら開発をしています。お試し入社者の中には、特定の技術スタックは強いけど特定のスタックは経験がない・少ないというメンバーもいらっしゃいます(何を隠そう、自分が完全にそれでした)。

そうしたメンバーと作業をする場合は特にペアプロは大きな威力を発揮すると考えています。技術スタックや既存フィーチャーの仕様・コンテキストが不足していると、その時点で心理的安全性がかなり低くなってしまいます(自分も入社時はソロタスクが多く、わからないことを聞くためにも中々人が捕まりにくいなどの問題があり不安なこともありました)。自走ができる状態に持っていくための最短手段としても素晴らしいソリューションだと思います。

一方で、常にサポートが入っている状態だとアウトプットのスピードと質は保証できるかもしれませんが、個人としてのインプットや納得感・達成感は得られにくいといった問題は大いに考えられます。

時には、「一人でトライしてみたい」や、「最近あまり技術的なチャレンジできていない」といった意思やモヤをできるだけ表明しやすくし、他のメンバーはそれを尊重できるような関係性の構築も重要だといえるでしょう。

3-4. USMからバックログアイテムを転用

主にデザイナーが行うディスカバリーの手法としてはリーンXPやMVP仮説検証などを用いており、新たな価値を提供するときはユーザーストーリーマッピングという主にエンドユーザーの行動をベースとした体験を時系列などにまとめたものを制作しています。

現在はオンラインホワイトボードツールのMiroでUSM(ユーザーストーリーマップ)を作っていますが、JIRA連携の機能を利用してディスカバリーフェーズで作成されたユーザーストーリーをそのままデリバリーのバックログアイテムとして転用しています。

Miroで作ったUSMとJIRAチケットを連携し可視化するイメージ

これによって、わざわざスクラムにおけるプロダクトオーナー(PO)がバックログアイテムを作るという作業をスキップできるようになりました。

さらに、USMがユーザの行動ベースかつ比較的粒度自体も小さく設計されているため、チケットの要件記述も非常にシンプル(時にはタイトルで自明なので詳細不要)になり、要件の手戻りもしにくくなりました。

USMの例としては「ログインしていると〇〇が表示される」、「〇〇を押したら〇〇に遷移する」といった非常に小さな粒度となっています。

チーム構成のところでも紹介しましたが、メンバー数も比較的多く、デザインと開発をチーム内で抱えており、IPと密着したチーム特性もあることで、特にPdMの負荷が高くなっており、ビジネスなどのより本質的な仕事にフォーカスできるようにすべく、この手法を取り入れたという背景がありました。

チームの声としては、「チケットがわかりやすくなった」などのポジティブな反応もあったため、やって良かったと思います。

この取り組みに関しては、絶賛PDCA中になりますので、それなりに形になったタイミングでまたその内容を詳しく共有できればと考えています。

4. まとめ

いかがでしたでしょうか。最後に抽象的にはなってしまいますが、まとめです。

  1. チームの取り巻く状況や環境、特性を理解する
  2. 生まれうる/生まれた課題をしっかりと捉える
  3. 課題に対して適切なアプローチと改善のサイクルを早期に回す

この特性や課題の設定は、設定をする人のスキルセット(いわゆるメタ認知と構造化する力)に依存してしまうとは思います。そのため、その設定自体がブレていると、ただ自分がやりたいことを改善しているだけになってしまう可能性があり、本質を解決できていないことがあります。

ブレていないかは、チーム内外のメンバーに雑談ベースでも良いので壁打ちしてもらい、ブラッシュアップするのが良いかなと感じています。

筆者も、チームへのジョイン時に既存メンバーと1on1を設定させていただき、チームが置かれている状況や課題などの解像度をより鮮明にするところからアプローチしました。

この課題設定の確度を上げることが、結果的に短期での解決や改善を生む要因になったのではないかと考察しているので、非常に重要なステップだと考えています。

また、こうした取り組みがどんどん回せているのは、筆者が主導・管理したからというわけでもなく、チーム全体で一人ひとりが問題に向き合い、自律的に改善することができている結果だと考えています。

一人が主導するよりも、このように自己組織化するチームになる方が、並行してたくさんの改善が回せると思うので、チームのカルチャー創りというのも非常に重要かなと思います。

--

以上になります、お読みいただきありがとうございます!

ぜひこの記事に対しても感じたことなどありましたら、率直なフィードバックをいただけますと幸いです 🙏 

site.gaudiy.com

11/16(木)の自社イベントでも開発組織についてお話しするので、ご興味ある方はぜひ!

gaudiy.connpass.com

ウォレットを ERC-4337 の Account Abstraction で実装して感じた課題と展望

こんにちは。ファンと共に時代を進める、Web3スタートアップ Gaudiy で、ブロックチェーン周りの開発をリードしているDoi(@taro_engineer)です。

「2023年は、Web3 のマスアダプションに向けて躍進する年だ」と昨年の後半くらいから言われていましたが、実際に、技術的にも法規制的にも進展があった一年だったと思います。

GaudiyもWeb3のマスアダプションに対して、長らく課題意識を持ってきましたが、今年は事業としても大きな転換を迎える年となりました。(このあたりの Gaudiy の事業背景や変遷は、ぜひ以下の記事をご覧いただければと思います。)

techblog.gaudiy.com

中でも、大きな進展として注目すべきポイントの一つが、ERC-4337 の Audit です。Gaudiy としても Account Abstraction、特に ERC-4337 には注視していたので、大きなニュースでした。

ERC-4337 は Draft ですが、OpenZeppelin による ERC-4337 Core チームのコントラクト Audit のニュースを見たときに、今後 ERC-4337 を開発していく流れを止めることはできないと確信しました。

これを受けて、実際にGaudiy のプロダクトに適用するにはどうするか?を考え、実装してみたため、今回は ERC-4337を実装する上で感じた課題や今後の展望について書いてみたいと思います。

1. Web3のマスアダプションに向けた課題

Web3 ひいてはブロックチェーンの世界に、一般ユーザーも参加してもらうには、まず大きな課題が2つあります。

  • ウォレット(EOA)という新しい概念のアカウントを管理しないといけない
  • ガス代という手数料の存在

それぞれの課題に対して単独での解決策はあり、それらを組み合わせることで、一般的なアプリに慣れているユーザーにもブロックチェーンの世界に足を踏み入れてもらうことはできました。

一方で、完全に自由な活動をユーザーが実現するのは難しく、その解決にはスマートコントラクトのアップデートが必要など、一部のユースケースにしか対応できないという難点もありました。

すべてのオンチェーン活動に対して自由に活動できて、ユーザーが余計な学習を必要としない状態にするには、まだ一歩足らない部分があったように感じます。

2. ERC-4337 とはなにか?

上記の問題を解決するために、Account Abstraction という技術でウォレットを作ることが考えられます。これは、ブロックチェーン上のスマートコントラクトをウォレットとし、EOA と同じ振る舞いができるように、署名とガス代の抽象化を実装するシステム全体のことを指します。

そして ERC-4337 は、Ethereum 系ネットワークのアプリケーションレイヤーで Account Abstraction を実装するための標準規格にあたり、Account Abstraction の最前線といっても過言ではない提案にあたります。

Ethereum 系ネットワークのコントラクト開発で標準規格化していくであろう提案ということは、つまり、どの開発者・プロバイダーでも周辺のエコシステムを利用すれば拡張できる。例えば、 Bundler・Paymaster を切り替えて利用できたりすることが、利点として考えられます。

また、トランザクションの署名に ECDSA 以外を利用するなど、署名の抽象化も実現できるため、今後の課題になるであろう暗号の強度や、署名検証の効率化などに対しても対策ができるのが特徴です。

これ以上の詳しい内容は、他の記事などを探せば出てくるので、ここでは深く言及しないようにします。

ERC-4337 を実装するにあたり、関連記事をひとつだけ紹介すると、個人的には Alchemy が出しているブログを読めば、ERC-4337 がだいたいわかると思っています。

www.alchemy.com

Account Abstraction を実装していく中で発生する課題を解決していき、最終的にERC-4337 の複雑さに行き着くまでのプロセスを紹介してくれているので、各登場人物が何を目的として存在するのか?がよくわかります。

このブログなどを参考に、実際の動きを確かめながら実装を進めました。

3. ERC-4337 実装のポイントと展望

ではここから、実際の ERC-4337 の実装について書いていきます。この章では、大きく分けて以下3つのポイントをご紹介したいと思います。

  1. アップグレードについて
  2. ウォレットのリカバリーについて
  3. 転売の防止について

まず、ERC-4337 を Production レベルで実装する際に、必ず考慮する必要がでてくる “アップグレード”“ウォレットのリカバリー” 。そして、Gaudiyの事業特性上考える必要があった “転売の防止” について言及していきます。

前提としてGaudiyのウォレット構成は、以下のようなイメージ(概念図)となります。

出典:https://speakerdeck.com/winor30/gaudiy-web3-tech?slide=15

簡単に説明すると、コントラクトの Storage に関わるデータは AccountStorage で定義して、ロジックの変更によって collision を引き起こす可能性を減らしています。各ロジックは Manager として定義し、最低限必要な機能を備えました。

SmartAccount というコントラクトが各ロジックを束ねており、これをシングルトンとしてネットワークにデプロイします。

各ユーザーごとのアカウントとして Proxy をデプロイし、ウォレットのアップグレードが必要な場合は、ユーザーからトランザクションを発行してもらい、事前にデプロイした新しいシングルトンコントラクトに向き先を変えてもらいます。

それでは各セクションについて、記載していきたいと思います。

3-1. アップグレードについて

1つめは、アップグレードです。スマートコントラクトの実装において、最も神経を使う部分の1つが Upgradeable なコントラクトの実装だと思っています。

今までの開発であれば、OpenZeppelin のコントラクトでも一般的に提供されている ERC-1967 を利用した Proxy Pattern が、一番メジャーで使用されている選択肢かなと思います。

スマートコントラクトウォレットに関しては、この通例とされる Upgrade とは少し違うアプローチを考えなければいけません。

3-1-1. モジュラーコントラクト

まず ERC-4337 は EIP ではまだ Draft であり、今後仕様が変わる可能性が大きいです。さらに、ユーザーのアカウントという性質上、セキュリティの脆弱性に対する対応や、今後ユーザーが新機能を追加したい/逆に削除したいと感じる可能性なども、NFTなどのコントラクトと比べると高いと考えられます。

そのため、コントラクトを拡張していく考え方をもつ従来の Proxy Pattern では、スケールするウォレットを提供することは難しいと感じました。

この点から、ウォレットの実装でよく見られるのは “モジュール” という概念を用いた実装です。

ざっくりしたイメージで言うと、ERC-2535 の Diamond Proxy の考え方をベースとし、各ロジックを組み替えたり、付け替えたりできるようにモジュール化する手法です。Account Abstraction のパイオニアと呼べる各プロジェクト、例えば Safe や Argent などには、この “モジュール” という要素が組み込まれています。

ERC-4337 の文脈でいくと、ERC-6900 の提案がより標準化に向けたモジューラブルなスマートコントラクトウォレットの実装につながると考えています。これもまだ Draft なので、今も Spec が変わりつつありますが、基本的な考え方はすでに長年 Account Abstraction に取り組んでいるプロジェクトでも利用されていたりします。

また、Alchemy のエンジニアが提案者なので、今後 Alchemy という大きなプラットフォーマーが ERC-6900 の標準化に向けて大きく推進させていったり、Account Abstraction の開発市場を取りに行くような動きをする可能性があると感じています。

3-1-2. どう実装したのか?

開発当初は ERC-6900 をベースにした実装を考えたのですが、実装当時はこの提案が出てからまだ半月も経っておらず、以下の懸念がありました。

  • 研究的な実装を進めたが、大幅に仕様が変更する可能性がある
  • 既に実装されているモジューラブルな実装方法で実装しても、 ERC-6900 の考え方と大幅に違ってくる可能性もある
  • 工数と期日が逼迫している

これらの懸念を考えると、変わらないコアな部分はどこかを見極めて、ポイントだけ押さえることが大事だと判断しました。

その結果、まずは ERC-1967 を応用した Upgrade の方式(結果的には OpenZeppelin v5.0.0 に含まれた ERC-7201 に近い状態になった)で、 Storage をロジックから切り離すように実装することを決めました。今はこのコアな部分のみ実装しつつ、将来的にモジューラブルなコントラクトに移行していきたいと考えています。

この実装自体は Soul Wallet から着想を得ており、開発当時は Soul Wallet チームが GitHub で水面下に開発していることに気づけなかったのですが、現在は ERC-6900 の考え方のサンプルの1つになりえるモジュールの構成になっています。

ethereum-magicians.org

チーム全体としても Empower Day を活用して知識を付けていったり、PoC をつくったりなど、より良い改善に向けた取り組みが現在進行中です。

3-2. ウォレットのリカバリーについて

2つめが、ウォレットのリカバリーです。Account Abstraction を実装する上で、今ではリカバリー手段を実装することはスタンダードになっています。

しかしながら、どの方法を選択すれば提供するユーザーにとってリカバリーが実行しやすいのか?学習コストをかけずにリカバリー手段を設定できるのか?など、実生活に反映させていくには考えねばならない観点が複雑に絡み合っていると思います。

まずは技術的に、ウォレットをリカバリーするための主な手段として以下の2つを考えました。

  • ソーシャルリカバリーを利用したオーナーの変更
  • マルチシグを利用したオーナーの冗長化
3-2-1. ソーシャルリカバリーを利用したオーナーの変更

まず、vitalik が提唱した Social Recovery は最良のソリューションのように聞こえますが、現実的にはどのアプローチをとっても一定のデメリットがあり難しいです。

また、信頼できる家族や友人などの第三者の承認を得る、文字通りソーシャルな関係でリカバリーすることは、一般ユーザーをターゲットにするウォレットでは周りの人も Web3 に精通していない可能性が高く、実現が困難です。そのため、もう少しだけ抽象化した「本人が信頼できる Guardian を用意する・用意させる」という考え方でユーザーに届ける必要があると考えます。

各種方法はありますが、例えば OIDC を利用できる IdP を Guardian とするリカバリーが、ユーザーには一番馴染みがあって、学習コストをかけずに使用できるのではないかという仮説が考えられます。

ただ、これも良い方法に見えますが、以下のデメリットはあると考えました。

  • 公開鍵の変更があった場合、ID トークン検証用のシングルトンコントラクトのデプロイが毎回必要になる
  • IdP が悪意をもてばリカバリーを実行できてしまい、実質セミカストディアルな状態になる
  • この問題を解決しようとすると、よりアーキテクチャが複雑になる

結果的に、現在の知見や開発のためのコストや可逆性、費用対効果を考えると、他の方法で進めるのがよさそうでした。

次に、よりコスト感と見合った現実的なアプローチとして、すでに実装されているソーシャルリカバリーや関連するロジック、Argent の SecurityManager や Safe の OwnerManager などのロジックをベースに、ソーシャルリカバリーを実装することが考えられます。

この方法は現時点においては一番現実的だと思いますが、Guardian は ECDSA で検証ができる署名を作成できる必要があり、リカバリー用の秘密鍵をどこで生成し、保持してもらうか?が課題になります。

これは今までの「EOA をいかに一般ユーザーに対して安全に保管してもらうか?」と同じ課題になり、ブラウザウォレットをこれから作る我々としては悩ましい問題になりました。

3-2-2. マルチシグを利用したオーナーの冗長化

別手段として、マルチシグの仕組みを利用してオーナーを複数用意する方法も当然考えられます。

これはオーナーを増やして 1/n のマルチシグウォレットにすることで、オーナーのどれかを失っても、別のオーナーでウォレットを管理できるようになり、実質ソーシャルリカバリーに近い考え方となるということです。ロジックの複雑さはなく、実装もしやすいように思います。

ただし、複数のオーナーを設定できるようにすると、適切なオーナーを設定してもらいたいがそれを制限することは難しいと考えました。後述しますが、投機目的でウォレットの転売に利用されないか?も考慮すると、すべてのオーナーが「ユーザー自身が管理するものである」ことを検証できる必要があります。

また、ユーザーが学習コストをかけずに用意できて失いにくい方法で、かつウォレットを利用するときの体験も良い方法でオーナーを用意してもらう必要があるのは、変わらずクリアしなければいけない課題だと感じました。

3-2-3. どう実装したのか?

つまり、解決せねばならない主な課題は2点あります。

  • ユーザーに学習コストをかけずにウォレットのオーナー・リカバリーの鍵を生成してもらう
  • リカバリーをするときは適切なウォレットのオーナーにローテーションできる

この2点を現時点で達成するには、ウォレットのオーナーをオフチェーンの MPC で生成するのが適切な方法ではないかと考えました。

まず、ユーザーに今までの体験と変わりなくオーナーを生成してもらうには、ソーシャルログインでウォレットを作れるのが理想的だと考えます。これは弊社のプロダクトである Fanlink のアカウントを作れば、それがウォレットのオーナーになるようにするのがベストな状態だと考えました。

また、オンチェーン上でリカバリーをするとなると、新しいオーナーをユーザーが用意する必要があります。これもユーザーにとっては、私たちから何かしらの機能を提供しないと Metamask などの EOA を用意する必要が出てくるので、オーナーは変えずに同じ Fanlink アカウントでリカバリーができるようにする、要はオフチェーンでリカバリーできるのがベストな状態だと考えました。

これらを踏まえ、現実的に取れる選択肢を考えると、Web3Auth, Lit Protocol が当時は考えられましたが、Node の監査状況やサポート状況などを鑑みて、Web3Auth の tKey MPC を選択しました。

また、リカバリーの鍵を保持してもらう手段としては、リカバリーの鍵をプログラム上で生成して、そのデータを Cloud Storage に保存させることだと考えました。

この方法では仮に Google Drive を保存先と考えると、ユーザーは Google アカウントでアプリにアクセス権を許可すればリカバリーを取れる状態になり、体験としてはソーシャルログインのフローと変わりなくリカバリーを設定できます。

これをオンチェーンの Guardian ではなく、オフチェーンの MPC で分散した鍵をリカバリーとして設定するように考えました。このスキームでソーシャルリカバリーを実装すると、オンチェーンで Guardian を設定・保持してもらうときでも同様の流れで実現できるので、オンチェーンでのリカバリーも対応できます

参考にさせていただいた Argent や World App も同様のアプローチを取っているので、費用対効果が合っているソリューションだと思っています。

ウォレットのオーナーに関して、技術的にベストな選択をするならば、BLS や Schnorr などの集約署名を取り入れたオーナーの生成や WebAuthn を取り入れた 2Factor も導入するなど、実用性がありおもしろそうな領域はあります。

ですが、まずはユーザーに提供して本当に使いやすく Web3 の体験を楽しめるのかを確かめる必要があるため、ウォレットに関する最新技術の投入は段階的に取り組んでいく必要があると感じています。

上記に挙げた方法や理論は、数ある選択肢の一端であり、どれにも一定のデメリットがあります。ウォレットのリカバリーに関しては、これが正解だという方法はいまだなく、今後も改善が必要な分野だと思っています。

3-3. 転売の防止について

さいごに、転売の防止について触れます。Account Abstraction の利点の1つは秘密鍵を失ってもリカバリーができることですが、これは見る角度を変えると、第三者にウォレットを譲渡できるようになったということです。

3-3-1. 今までは “転売” が実質できなかった

今までの EOA では、第三者に譲渡したとしても秘密鍵を変更することはできないので、秘密鍵を知っている人、つまり譲渡した人がメモなどで秘密鍵を取っておいたら、仮に売買などを通してウォレットを譲渡したとしても確実に所有者が変わるとは言えませんでした。

ウォレットという自身の資産を管理するものを他人に受け渡すことは、実生活上では考えにくいかもしれませんが、Account Abstraction によって、このユースケースが技術的に可能になった点は、Gaudiyが考える「ファン国家」を実現するには考慮する必要がありました。

例えば、IP にまったく貢献していない人でも、ファン活動を頑張っているウォレットをお金で手に入れることができるようになるとしたら、適切なトークングラフを描けなくなってしまいます。また、投機目的のユーザーも入ってきて、ボラティリティが高くなり、本当のファンに負担がかかったり、ファンとしての熱量が下がってしまうかもしれません。

3-3-2. どう実装したのか?

これを解決するために「ウォレットのオーナーを変える処理は Gaudiy の署名も必要とする」ように実装することを考えました。具体的には、EIP-712 の署名を作成して、各メソッドで署名を検証するという、一般的なアプローチで考えました。

一方の課題として、適切なオーナーに変えようとしていることをどうやって判断するのか?は、変わらず議論しなければいけません。実装方法で他に良い方法があるとは思うのですが、今のところは IP 経済圏の公式なウォレットという状態を守るためのアプローチとなっており、その点では妥当性はあるかなと思っています。

もし、何か思いつく方・気づきがある方はぜひ議論させてほしいなと思っています。

4. まとめ

実際に取り組んでみて、今までのスマートコントラクトの開発とは違うアプローチを考えることや、現実世界で使えるレベルまで解像度をあげることは、限りある時間の中ではなかなか大変な部分もありました。この点は引き続き研鑽を積んでいきたいと思います。

また事業の特性上、完全にパブリックに開かれており、ユーザーに全主権があるという訳ではなく、どこかにルールを設ける必要があり、そのルールをどうコントラクトで定義するべきなのか?そもそも本当にルールが必要なのか?は研究とユーザー検証をしていく必要があると感じています。

べき論でいくと、ウォレットの UX を高めるためには、Starknet のようにチェーンがネイティブに Account Abstraction をサポートしていくことが必要だということも理解できますが、事業を進めることを考えると、可能な限り標準化に寄せながら、今の最善策を取っていくしかないと思っています。

ERC-4337 はまだまだ事例としては多くないですし、私たちも手探りで進めているので、もし何かシェアできるものがある方は、ぜひ教えてもらえたら大変嬉しいです。

site.gaudiy.com

ブロックチェーンエンジニアも募集してます。興味ある方いましたらぜひ。

herp.careers

site.gaudiy.com

また来週 11/7(火)に、Account Abstractionをデプロイする実践形式のオフラインイベントを開催するので、興味ある方いたらぜひご参加ください!

gaudiy.connpass.com