Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12768] ファイルの概要

このコミットは、Go言語の公式ドキュメントに「JSON-RPC: a tale of interfaces」という新しい記事を追加するものです。この記事は、Goのインターフェースがどのように既存のコードをより柔軟で拡張性の高いものにするのに役立ったかを示す具体例を提供しています。具体的には、標準ライブラリのRPCパッケージが、元々使用していたGobエンコーディングからJSONエンコーディングへ、Goのインターフェースを活用して容易に切り替えられるようにリファクタリングされた経緯を解説しています。

追加されたファイルは doc/articles/json_rpc_tale_of_interfaces.html であり、この新しい記事をドキュメントサイトに組み込むために doc/Makefiledoc/docs.html が更新されています。

コミット

  • コミットハッシュ: a786fe8e13d4cb9192ee98864ea4df91321a8665
  • 作者: Francisco Souza franciscossouza@gmail.com
  • コミット日時: 2012年3月27日 火曜日 13:35:40 +1100

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/a786fe8e13d4cb9192ee98864ea4df91321a8665

元コミット内容

doc: add JSON-RPC: a tale of interfaces article

Originally published on The Go Programming Language Blog, Abril 27, 2010.

http://blog.golang.org/2010/04/json-rpc-tale-of_interfaces.html

R=adg, r
CC=golang-dev
https://golang.org/cl/5920044

変更の背景

この変更の背景には、Go言語の標準ライブラリである net/rpc パッケージの柔軟性を高めるという目的がありました。元々 net/rpc パッケージは、Go独自のシリアライゼーションフォーマットであるGob(Go Binary)を使用していました。しかし、特定のアプリケーションでは、より汎用的なデータ交換フォーマットであるJSONを使用したいという要望がありました。

このコミットで追加された記事は、Goのインターフェースがどのようにこの課題を解決し、既存のRPCパッケージのコードを最小限の変更でJSON-RPCをサポートするようにリファクタリングできたかを示すものです。これは、Goのインターフェースが提供する強力な抽象化能力と、継承ではなくコンポジションを重視するGoの設計思想の優位性を示すための事例として公開されました。

前提知識の解説

Goのインターフェース

Goのインターフェースは、メソッドのシグネチャの集合を定義する型です。Goのインターフェースの最大の特徴は、型がそのインターフェースで定義されたすべてのメソッドを実装していれば、そのインターフェースを「暗黙的に」実装するとみなされる点です。明示的な implements キーワードは不要です。これにより、コードの結合度を低く保ちながら、柔軟な設計が可能になります。

RPC (Remote Procedure Call)

RPCは、ネットワーク上の別のコンピュータにあるプログラムのサブルーチンやプロシージャを、あたかもローカルにあるかのように呼び出すための技術です。クライアントはリモートの関数を呼び出し、その結果を受け取ります。RPCシステムは、データのシリアライズ(直列化)とデシリアライズ(非直列化)、ネットワーク通信、エラーハンドリングなどを抽象化します。

JSON-RPC

JSON-RPCは、RPCプロトコルの一種で、メッセージのエンコーディングにJSONを使用します。HTTPなどのトランスポートプロトコル上で動作することが多く、WebアプリケーションやAPIで広く利用されています。人間が読みやすい形式であり、多くのプログラミング言語でサポートされているため、異なるシステム間の相互運用性に優れています。

Gob (Go Binary) エンコーディング

Gobは、Go言語の標準ライブラリ encoding/gob パッケージで提供される、Goのデータ構造をシリアライズおよびデシリアライズするためのバイナリエンコーディングフォーマットです。Goの型システムと密接に連携しており、Goの構造体やプリミティブ型を効率的にエンコード・デコードできます。ただし、GobはGoに特化しているため、Go以外の言語との相互運用性はありません。

技術的詳細

このコミットで追加された記事が解説している技術的詳細は、Goのインターフェースを活用して net/rpc パッケージのエンコーディングメカニズムを抽象化し、GobからJSONへの切り替えを容易にした点にあります。

元の net/rpc パッケージは、エンコーディングにGobを直接使用していました。JSONをサポートするためには、Gobに依存する部分を汎用的なインターフェースに置き換える必要がありました。

具体的には、以下の2つのインターフェースが定義されました。

  1. ServerCodec インターフェース: サーバー側でのリクエストの読み取り、レスポンスの書き込み、接続のクローズといった操作を抽象化します。
    type ServerCodec interface {
        ReadRequestHeader(*Request) error
        ReadRequestBody(interface{}) error
        WriteResponse(*Response, interface{}) error
        Close() error
    }
    
  2. ClientCodec インターフェース: クライアント側でのリクエストの書き込み、レスポンスの読み取り、接続のクローズといった操作を抽象化します。

これらのインターフェースを導入することで、net/rpc パッケージの内部関数(例: sendResponse)は、具体的なエンコーダ(*gob.Encoder)ではなく、ServerCodec インターフェースを受け取るように変更されました。

// 変更前
func sendResponse(sending *sync.Mutex, req *Request,
    reply interface{}, enc *gob.Encoder, errmsg string)

// 変更後
func sendResponse(sending *sync.Mutex, req *Request,
        reply interface{}, enc ServerCodec, errmsg string)

この変更により、Gobエンコーディングをラップする gobServerCodec や、JSONエンコーディングを実装する jsonServerCodec のような具体的な型が、ServerCodec インターフェースを満たすように実装されれば、net/rpc パッケージのコアロジックを変更することなく、異なるエンコーディングをサポートできるようになりました。

記事では、このリファクタリング作業全体がわずか20分程度で完了したと述べられており、Goのインターフェースが提供する設計の柔軟性と、コードの保守性・拡張性の高さが強調されています。これは、JavaやC++のような継承ベースの言語で同様の汎用化を行おうとすると、より複雑なクラス階層の設計が必要になる場合が多いことと比較して、Goのコンポジション指向の型システムが持つ利点を示しています。

コアとなるコードの変更箇所

このコミット自体は、Goのソースコードに直接的な機能変更を加えるものではなく、ドキュメントの追加と更新が主な内容です。

  1. doc/Makefile の変更: 新しい記事 articles/json_rpc_tale_of_interfaces.rawhtmlRAWHTML 変数に追加し、ドキュメント生成プロセスに含めるようにします。

    --- a/doc/Makefile
    +++ b/doc/Makefile
    @@ -12,6 +12,7 @@ RAWHTML=\
     	articles/godoc_documenting_go_code.rawhtml\
     	articles/gobs_of_data.rawhtml\
     	articles/json_and_go.rawhtml\
    +\tarticles/json_rpc_tale_of_interfaces.rawhtml\
     	articles/image_draw.rawhtml\
     	effective_go.rawhtml\
     	go1.rawhtml\
    
  2. doc/articles/json_rpc_tale_of_interfaces.html の新規追加: 「JSON-RPC: a tale of interfaces」というタイトルの新しいHTMLファイルが追加されます。このファイルには、Goのインターフェースを用いたRPCパッケージのリファクタリングに関する記事のコンテンツが含まれています。

    --- /dev/null
    +++ b/doc/articles/json_rpc_tale_of_interfaces.html
    @@ -0,0 +1,78 @@
    +<!--{
    +"Title": "JSON-RPC: a tale of interfaces"
    +}-->
    +
    +<p>
    +Here we present an example where Go's
    +<a href="/doc/effective_go.html#interfaces_and_types">interfaces</a> made it
    +easy to refactor some existing code to make it more flexible and extensible.
    +Originally, the standard library's <a href="/pkg/net/rpc/">RPC package</a> used
    +a custom wire format called <a href="/pkg/encoding/gob/">gob</a>. For a
    +particular application, we wanted to use <a href="/pkg/encoding/json/">JSON</a>
    +as an alternate wire format.
    +</p>
    ... (記事の残りの内容) ...
    
  3. doc/docs.html の変更: ドキュメントのインデックスページである docs.html に、新しく追加された記事へのリンクが追加されます。これにより、ユーザーがGoのドキュメントサイトからこの記事にアクセスできるようになります。

    --- a/doc/docs.html
    +++ b/doc/docs.html
    @@ -91,7 +91,7 @@ the Go team and guests.</p>
     
     <h4>Codewalks</h4>
     <p>
    -Guided tours of Go programs. 
    +Guided tours of Go programs.
     </p>
     <ul>
      <li><a href="/doc/codewalk/functions">First-Class Functions in Go</a></li>
    @@ -102,7 +102,7 @@ Guided tours of Go programs.
     
     <h4>Language</h4>
     <ul>
    -<li><a href="http://blog.golang.org/2010/04/json-rpc-tale-of-interfaces.html">JSON-RPC: a tale of interfaces</a></li>
    +<li><a href="/doc/articles/json_rpc_tale_of_interfaces.html">JSON-RPC: a tale of interfaces</a></li>
      <li><a href="/doc/articles/gos_declaration_syntax.html">Go's Declaration Syntax</a></li>
      <li><a href="/doc/articles/defer_panic_recover.html">Defer, Panic, and Recover</a></li>
      <li><a href="/doc/articles/concurrency_patterns.html">Go Concurrency Patterns: Timing out, moving on</a></li>
    

    注目すべきは、元のブログ記事への外部リンクから、Goドキュメントサイト内の新しい記事への内部リンクに変更されている点です。

コアとなるコードの解説

このコミット自体はドキュメントの追加であり、Go言語のランタイムやライブラリのコアコードに直接的な変更を加えるものではありません。しかし、追加された記事が解説している内容は、Goの設計思想とインターフェースの強力な活用例を示すものであり、Go言語の「コア」となる考え方を理解する上で非常に重要です。

記事で示されている ServerCodec インターフェースの導入は、net/rpc パッケージが特定のエンコーディング(Gob)に強く依存していた状態から、インターフェースを介してエンコーディングメカニズムを抽象化し、プラグイン可能な設計へと進化させたことを意味します。

このアプローチの利点は以下の通りです。

  • 柔軟性: 新しいエンコーディングフォーマット(例: Protocol Buffers, MessagePackなど)をサポートする必要が生じた場合でも、ServerCodec インターフェースを実装する新しい型を作成するだけで、RPCパッケージのコアロジックを変更する必要がありません。
  • 保守性: エンコーディングロジックがインターフェースの背後に隠蔽されるため、RPCパッケージの他の部分がエンコーディングの詳細に依存しなくなり、コードベース全体の保守が容易になります。
  • テスト容易性: インターフェースを使用することで、モックやスタブを簡単に作成でき、RPCパッケージの各コンポーネントを独立してテストすることが容易になります。
  • Goらしい設計: 継承ではなくコンポジション(インターフェースの実装)を通じて汎用性と拡張性を実現する、Go言語のイディオムに沿った設計です。

このように、このドキュメントの追加は、Go言語の設計原則と、インターフェースがどのように実世界のプログラミング課題を解決し、より堅牢で柔軟なソフトウェアを構築するのに役立つかを示す重要な教育的コンテンツとなっています。

関連リンク

参考にした情報源リンク