見出し画像

Buf Connectを選んだ理由と開発現場での活用

GOGEN のCTOの楠本(@zabio3)です。僕らは、Go言語を使い、スキーマ駆動開発でコードを自動生成をしながら、日々プロダクトのデリバリーを行っています。
その中で、僕らはBuf Technologies社が開発したRPCフレームワークであるConnectを採用しています。Connectを選択した理由と、実際の開発現場での使用感をお伝えします。


Connect とは?


Connectは、Buf Technologies社が開発した次世代のRPCフレームワークです。Protocol Buffersを使用してAPIを定義し、効率的なサーバー/クライアント間通信を実現します。

特徴① シームレスなスキーマ統合

  • Protocol Buffersとの完全な互換性

  • 既存のプロトコル定義をそのまま活用可能

特徴② マルチプロトコルのサポート

  • gRPC、gRPC-Web、Connect独自プロトコルをサポート

  • サーバーサイド、クライアントサイド、ブラウザ環境での一貫した使用が可

特徴③ Connect独自プロトコルの優位性

  • HTTP/1.1 と HTTP/2 の両対応

  • 標準的なHTTPセマンティクスの活用

  • 双方向ストリーミングのサポート

  • JSONとバイナリ形式の両サポート

  • ブラウザとの直接通信が可能

双方向ストリーミング、ブラウザとの直接通信が可能(HTTP/1.1対応などの点)が利用でき、高度なRPC機能を持ち合わせている点が非常に大きなメリットだと感じています。

特徴④ エコシステムの充実

  • Bufのツールチェーンとの統合

  • gRPCの優れたエコシステムとの互換性

僕らがConnectを選択した背景


レリーズは、煩雑な不動産売買取引をデジタル化し、エンドユーザー(買主・売主)と不動産事業者の「体験」を軸に、売買取引プロセスを「なめらか」にするサービスです。

Release

この「体験」を実現するためには、効率的なデータの集積と活用、そして業務に特化した複数サービス間の連携が不可欠です。これらの課題に対応するため、僕らは以下の要件を重視して技術選定を行いました。

1. データの集積とサービス間連携


要件:長期的なデータ蓄積と複数サービス間での効率的な情報共有ができる

▼ 採用理由

  • Protocol Buffersを用いたスキーマ駆動開発により、一貫したデータ構造と効率的な通信を実現

  • マイクロサービスアーキテクチャとの高い親和性

  • サービスの拡張性と再利用性の向上

2. 柔軟性とパフォーマンス


要件:多様なクライアント(ブラウザ、モバイルアプリ、サーバー)への対応ができる

▼ 採用理由

  • gRPC、gRPC-Web、独自プロトコルのサポートによる多様な環境への適応

  • Go言語向けのサーバーおよびクライアント実装(connect-go)、TypeScript/JavaScript向けのクライアント実装(connect-web、connect-query)の提供

  • バイナリシリアライゼーションとストリーミングサポートによる高速通信

  • 型安全性による複雑な取引データの整合性確保

  • HTTP/1.1およびHTTP/2との互換性による既存インフラとの統合しやすさ

  • gRPC-Webのような中間層を必要とせず、HTTP/2を直接利用可能

3. 開発効率とメンテナンス性


要件:複数サービスの迅速な開発と長期的な保守性

▼ 採用理由

  • 効率的コード生成とシンプルなAPI設計による開発速度が向上

    • gRPCと比較してより簡潔なコードを生成

  • 開発者間のコミュニケーションを大幅に削減できる

    • クライアントが自動生成される為、クライアントのバージョンアップで最新のインタフェースの型定義を得ることが可能

    • protoのコメントで、ドキュメントが自動生成される為、一元管理可能(yamlでインタフェースのメンテをしなくて良い)

  • proto側で、バリデーション定義を一元管理ができる

  • gRPCの優れたツール群(evans、grpcuiなど)に加え、Bufのエコシステムも利用可能

Connectの採用により、無駄な作業に追われることなく、価値のデリバリーにフォーカスして開発が出来ていると感じています。

開発現場でのConnect使用感


少人数チームでの開発効率化

僕らのような少人数チームにとって、Connectの自動生成機能は特に価値があります。以下の点で大きなメリットを感じています。

  1. コミュニケーションコストの削減

    • APIの変更があっても、プロトコルバッファファイルを更新するだけで済むので、チーム内での説明や調整にかかる時間が劇的に減りました。

  2. エラーの減少

    • 手動でのコード記述が減ることで、人為的ミスが激減。チーム規模が小さくても、高品質な開発を維持できています。

  3. 迅速な機能開発

    • ボイラープレートコードの作成時間が省けるので、本質的な機能開発により多くの時間を割けるようになりました。

  4. クロスプラットフォーム開発の効率化

    • GoとTypeScriptの両方のコードが自動生成されるため、フロントエンドとバックエンドの開発者間のギャップが縮小。少人数でもフルスタック開発がスムーズになりました。


以下は、具体的な例です。

プロトコルバッファ定義

まず、プロトコルバッファファイルを定義します。

service AnkenService {
  rpc Create(AnkenCreateRequest) returns (AnkenCreateResponse) {}
}

Goの場合、次のようなインターフェースが自動生成されます。

service AnkenService {
  rpc Create(AnkenCreateRequest) returns (AnkenCreateResponse) {}
}

func NewAnkenServiceHandler(svc AnkenServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
    // 自動生成されたハンドラーコード
}

TypeScript向けのクライアントの場合、次のようなインタフェースが自動生成されます。

export class AnkenCreateRequest extends Message<AnkenCreateRequest> {
  organizationId = "";
  name = "";

  // その他のフィールドと型安全なメソッド
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Anken {
    return new Anken().fromBinary(bytes, options);
  }

  static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Anken {
    return new Anken().fromJson(jsonValue, options);
  }

  static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Anken {
    return new Anken().fromJsonString(jsonString, options);
  }

  static equals(a: Anken | PlainMessage<Anken> | undefined, b: Anken | PlainMessage<Anken> | undefined): boolean {
    return proto3.util.equals(Anken, a, b);
  }
}

サービス変更をした場合、「buf generate」コマンドを実行するだけで、最新のインターフェースとクライアントコードが自動的に生成されます。これにより、クライアントとサーバー間の一貫性が保たれ、バージョンアップ時の手動更新の手間が省けます。

結果として、僕らの少人数チームは、コミュニケーションコストを大幅に削減し、より価値のある開発タスクに時間を費やすことができるようになりました。(API更新に伴うドキュメンテーションやボイラープレートにコード修正に充てる時間を、価値の実装や既存コードの改善に充てることができる。)

効率的なエコシステムの活用

buf.gen.yaml に、pseudomuto-doc をpluginに追加することで、自動的にAPIドキュメントを生成できます。以下は、plugin設定方法です。

plugins:
  - plugin: buf.build/community/pseudomuto-doc
    out: ./gen/all/docs
    opt:
      - markdown,docs.md

また、ConnectはgRPCと互換性があり、既存のgRPCツールを活用できます。

grpcui -protoset <(buf build ../proto -o -) -plaintext localhost:8080
grpcui

.protoファイルを自動的に読み込み、API仕様を視覚的に反映してくれる点や、インタラクティブなテストが可能な点、スムーズなデバッグができる点が気に入っています。

Connectの導入で直面した課題:Interceptorの互換性

ConnectはgRPCと互換性があり、多くのgRPCのエコシステムを利用できるが、Interceptorの違いにより、一部のgRPC特有のミドルウェアやツールは直接利用できない点があります。具体的には、以下のmiddlewareなどが利用できません。

その為、僕らはライトな形でecosystemとなるloggerや、datadog(opentelemetry)、 authなどを自前実装して、複数プロダクトで利用しています。

最近、CNCFに加入したので、今後の発展に期待したいです。

まとめ


Connectの採用により、僕らは迅速なデリバリーを実現しつつ、プロダクトとコードの質を高く保つことができています。
しかし、不動産取引を真に「なめらか」にするには、まだまだ仲間が必要です。人生最大の買い物である不動産取引。テクノロジーとリアルの価値を融合し、この体験を最高のものにする。それを実現したいと考えています。

どうせ人生一度きり。不動産取引の「体験」を、一緒に最高のものにしていきませんか?

少しでも興味を持たれた方は、ぜひお気軽にご連絡ください。カジュアルに話しましょう。

注:この記事の内容は、現時点での僕らの経験と理解に基づいています。技術の進化や新しい知見により、ここで述べた点が変更される可能性があります。最新の情報については、公式ドキュメントや他の信頼できるソースを参照することをお勧めします。

この記事が気に入ったらサポートをしてみませんか?