blog.syfm

徒然なるままに考えていることなどを書いていくブログ

GoDoc を多用している

最近は設計をする際にできる限り API 仕様を正確に記述するようにしている。このことを意識し始めた大きな要因は主に次の 2 つだと思う。

1 つ目は以前、前職で働いているときに柴田さんに API 仕様の重要性を教えてもらったことから。この時に聞いたことは以下のブログ記事にまとまっているのでぜひ読んでほしい。

yshibata.blog.so-net.ne.jp

もう 1 つは、今年の頭に読み終えた A Philosophy of Software Design から。この本では、複雑さを減らすために API の仕様が限りなくシンプルで、多くの機能を提供する deep module を目指すべき、といったことが言及されている。

Go ではドキュメントシステムとして GoDoc が提供されているため、上記のような洗練された正確なインターフェースを記述するためにこれを開発時に利用している。 ローカルホストで GoDoc を起動しておいて、新しい型や関数、変数が追加されるたびに十分なコメントや Example テストを書いて GoDoc でセルフレビューしている。 GoDoc は、エクスポートされた要素のコメントのみをドキュメント化するため、客観的に API 仕様を見ることができ、その結果不必要にエクスポートされている要素や仕様漏れを探しやすい。

10 月から 3 月までは働いていなかったため、この開発スタイルを使っていたのは自作 OSS のみだった。具体的には以下の Go プロジェクト。

godoc.org

godoc.org

dept はコマンドだけど、main パッケージが依存するパッケージのドキュメントはライブラリと同じようにしっかり書いている。

本当は GitHub で Pull Request をつくるときにも変更を元に生成したドキュメントを見れるようにしてレビューできるようにしたいけど、あまり良い方法が思いつかないのでできていない。いずれ何かの仕組みをつくってやっていきたいと思っている。

gRPC における IDL と codec

codec

gRPC は非常に柔軟に設計されていて、例えば RPC でメッセージをやりとりする際に、どういうシリアライザでエンコードするかを自由に選ぶことができます。gRPC の公式ドキュメントではシリアライザとして Protocol Buffers のみが利用されていますし、デフォルトのシリアライザとなっているのであまりここを意識することはないかもしれません。

このシリアライザ機構は、codec として抽象化されています。Go の場合、google.golang.org/grpc/encoding 以下に Codec というインターフェースが定義されています。

type Codec interface {
    // Marshal returns the wire format of v.
    Marshal(v interface{}) ([]byte, error)
    // Unmarshal parses the wire format into v.
    Unmarshal(data []byte, v interface{}) error
    // Name returns the name of the Codec implementation. The returned string
    // will be used as part of content type in transmission.  The result must be
    // static; the result cannot change between calls.
    Name() string
}

Codec の実装は、encoding パッケージの RegisterCodec を利用して codec を登録します。*1
より正確で詳細なドキュメントは grpc-go/Documentation/encoding.md に置かれています。

IDL

gRPC では IDL を利用してインターフェース定義・コード生成を行います。IDL は Interface Definition Language (インターフェース定義言語) の略称で、こちらもほとんどの場合 Protocol Buffers が使われます。*2
例えば、以下のようにどういうサービスがあり、どのような RPC が属しているか、そのリクエストとレスポンスの型は何か、といった情報を独自の記法で記述します。 *3

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

普段 gRPC を触っている方であれば見慣れているかと思います。
この定義を元に protoc-gen-* を使い、クライアントとサーバのインターフェース部分のコードを自動生成することになります。

IDL と codec

普段は Protocol Buffers を使用しているため、IDL と codec という概念を意識することはないかもしれません。しかし、上に示したように、これらは明確に分離されていてそれぞれ別の実装を使用することが可能です。 例えば、IDL として Protocol Buffers を使い、codec として JSON を使うといったことができます。実際の例は以下の記事が非常に参考になります。

qiita.com

また、IDL を FlatBuffers 等に変更することもできますが、Protocol Buffers より操作が複雑であるため、codec に FlatBuffers を使いたい場合以外であまり使う理由はないでしょう。
当然 IDL を用意せずにパワーでクライアント・サーバを実装することもできますが、自動生成を使わないということは gRPC のメリットをすべて捨てていることと等価なのでやめたほうが良いでしょう。

*1:Protocol Buffers についてはデフォルトで使用されることになっているため、特別な設定は必要ありません。

*2:IDL は gRPC 固有の用語ではありません。

*3:このコードは grpc.io より引用しています。

追い出し LT で「つよくてニューゲーム」というタイトルで発表しました

卒業式の前日に会津大学の Zli というサークルの追い出し会として LT 会が開催され、そこで「つよくてニューゲーム」*1というタイトルで発表してきました。

普段は基本的に技術寄りの話ばかりしていますが、学生生活最後の発表だったので珍しく自分語りをしました。自分とコンピュータの馴れ初め、高校時代の挫折、大学での再スタートなど、今までのことをまとめています。 詳細は実際のスライドをアップロードしているのでそちらからどうぞ。

speakerdeck.com

このスライドをつくるにあたって、自分の大学生活を振り返ることができたので良かったです。

はたして自分が実践してきたことは正しかったのかは誰にもわかりませんが、高校時代に比べて想像以上の知識・経験を得ることができたため、何も後悔はありません。これで良かったのだと思っています。

4 月からは晴れて社会人となり、サーバサイドエンジニアとして働き始めることになります。これからも今まで考え続けてきたことを忘れずに心機一転、頑張っていきたいと思います。

*1:元ネタはクロノ・トリガーです