2017/09/05


8/31、patch 8.0.1026 で Linux 版 Vim のとある挙動が修正されました。

patch 8.0.1026: GTK on-the-spot input has problems - vim/vim@5c6dbcb - GitHub
https://github.com/vim/vim/commit/5c6dbcb03fa552d7b0e61c8fcf425147eb6bf7d5
この修正は、Linux 版 Vim の IME (Input Method Editor) の挙動を修正する物ですが、この1つのパッチの為に多くの開発者が動いたという話です。

Vim と IME と僕

このパッチ、多い時で月に100個以上もリリースされる大量のパッチの1つに過ぎないのですが、実はこのパッチには思い入れがあり記事にせずにいられませんでした。この問題が修正されるまでに至った経緯を知っている人間には、色々な思い出が脳裏を掛けめぐるのです。

これまでの UNIX 版 Vim の IME の挙動は、正直言って使い物になるとは言えませんでした。

これは vim-dev が悪い訳でも、我々マルチバイト圏の開発者が悪い訳でもなく、Vim というモードのあるテキストエディタに IME を連携させようと戦ってきた中で、如何にしても実現出来ない問題があった、という事なのです。

UNIX の IME

僕が vim-dev にパッチを送り始めたのは、おそらく Vim に IME の実装が入ったちょっと後だったと思います。Windows に至っては香り屋さんの多大な貢献もあり既に動作は安定し始めていました。その頃の UNIX の IME の実装は、Athena や Motif、GTK1 の GUI 上に XIM の実装が行われていました。今では当然の様にある GTK IM Module がまだ無かった頃ですね。とは言っても X11 XIM (X11R6) はその頃には既に実装も枯れていて、必要と思われる機能は十分に揃っていました。

入力エージェントの選択肢と言えば kinput2 くらいしか無く、有償であれば ATOK、その他で無償で使えた物と言えば VJE Delta くらいだったかもしれません。ここは記憶違いもあるかもしれません。特殊な入力方法を X11 上に提供する skkinput が世に出回ったのもその頃だったかもしれません。エンジンの方は Wnn、Canna、Sj3 などありました。そうは言ってもエージェントとエンジンが明確に区別されている訳ではなく、kinput2 に Wnn のパッチを当てた kinput2-wnn、kinput2 に canna のパッチを当てた kinput2-canna、といった具合にそれぞれに向けたパッチがあったという UNIX らしい提供方式でした。

今から思えば UNIX の日本語入力はお世辞にも使いやすいとは言えませんでした。今の様に当然の様に日本語入力できる訳でなく、自分でインストールして設定しなければならないのです。端末から日本語を入力するには skkfep の様に常駐して FEP を提供する物を使うか、kterm (この言葉知ってるともうオッサンと呼んでいい) から kinput2 を使う方式が一般的でした。CUI 単独で IME を使う方法は皆無で、あの頃みんなどうやって日本語を入力してたんだろうと今思えば不思議なくらいでした。

そんな頃 2ch で skk.vim という Vim script だけで SKK スタイルの入力を行うプラグインが話題に上がり、Vim 界隈で一世を風靡しました。これは後に tyru さんが skk.vim を作り直して eskk.vim をリリースする事になります。

しかし SKK は癖があります。また skk.vim の様なプラグインで実現する入力機構は他の Vim プラグインと干渉してエラーになったり画面が崩れる事も多く、それを自力で回避できるユーザでないと使いこなせないのが実状でした。その頃だったでしょうか、nvi-m17n という nvi のマルチリンガル対応版が canna と直接喋る事が出来ていて、Vim 使いとしては少し悔しい思いをしたのを覚えています。どうしても CUI で日本語入力したかった僕は、vim から Wnn や canna、POBox、SKK が使える様にするパッチ im_custom という物を作って配り始めました。しかしパッチという提供方法は Vim 本体の変更に追従しなければいけません。いつしか追従する気力を失った僕は、im_custom を最新版の Vim に追従するのを辞めてしまいました。

ON/OFF 問題

その頃の Vim の日本語入力も進展が無かったという訳ではなく、我々マルチバイト圏の開発者が試行錯誤を繰り返していました。その頃の Vim の日本語入力で一番辛かったのが IME の ON/OFF 問題でした。Vim は ESC でインサートモードから抜けますが、その際に IME が ON だった場合は一旦 IME をオフにしてから ESC (CTRL-[) を押す必要がありました。そうしないとノーマルモードで IME が ON の状態になったままとなり、jjj とタイプしても IME に食われて反応しないのです。Windows の IME に関しては ImmSetOpenStatus という Win32 API を使って IME の ON/OFF が実装され、シームレスなモードの行き来が行える様になっていました。しかし XIM には IME を ON/OFF させる仕組みがありません。その頃の Vim 使いは文句を言いながら IME の ON/OFF を繰り返していたに違いありません。

ところで Vim の IME がデフォルトでアクティブになる問題をご存じでしょうか。これは僕が vim-dev に参加するよりも前から実装されていた動作でした。Windows の GVim で以下を実行し、インサートモードに移るといきなり IME がアクティブになっているのです。

gvim --clean -u NONE -U NONE -N

この挙動は iminsert というオプションを使ってある程度制御が可能です。ただ、このオプションのデフォルト値が IME が使える場合には 2、つまり IM がオンという動作です。インサートモードに入ると IME が ON になるのです。デフォルト値が 2 になった経緯は我々日本人ではなく、最初に XIM の実装を始めた韓国の開発者による物でした。これは彼らの入力方法と日本人の入力方法が異なる事に起因しています。その頃に調べた所によると彼らの使う IME はアクティブになった後もローマ字が打てるらしいのです。なので iminsert が 2 であっても良いという事でした。丁度 skkinput が大文字でタイプを始めないと IME がアクティブ状態にならないのと同じと思って貰えると分かりやすいと思います。色々と葛藤はありましたが、結局のところ日本のユーザは vimrc で iminsert を 0 に設定して貰う事になっています。

我々日本人と他の IME ユーザの入力方法の違いはそれだけではありません。例えば日本人の IME 操作は、単語もしくは文節までを一度平仮名で仮入力を行い、その一部または全体を漢字に変換しながら確定して行きます。しかし中国や韓国の IME は文字単位です。特に韓国の IME ではアルファベット文字を幾らかタイプして1文字を入力し、都度確定していくらしいのです。つまりプリエディット(仮入力)が1文字という事です。

さて、話を IME の ON/OFF に戻します。これらの問題に香り屋さん取り組み、そして X11 のキーボードイベントをルートウィンドウに投げる事で IME を強制オフにするというワークアラウンド実装「imactivatekey」を思い付き、パッチとして取り込まれました。これはワークアラウンドながら実に良く動作しました。Linux デスクトップの IME 問題が一気に解決した様に見えました。

しかしそんな穏やかな日々を壊す物が現れます。GTK2 でした。GTK2 は IM Module を介して日本語入力を行います。そして GTK IM Module には IME を ON/OFF する機能が無いのです。今まで iminsert や imactivatekey というオプションで IME の ON/OFF が制御出来ていていたにも関わらず、もはやどうしようも無くなってしまったのです。uim に特化するのであれば vim から uim-fep を制御するパッチなんていうのもありました。

CustomizeUim - uim/uim-doc-ja Wiki - GitHub
https://github.com/uim/uim-doc-ja/wiki/CustomizeUim#vim%E3%81%A7%E4%BD%BF%E3%81%86

我々日本人開発者も、この頃はもう打つ手がないというのが正直な所でした。

仮入力問題

Vim の日本語入力にはもう一つ大きな問題がありました。それは仮入力の問題です。UNIX の IME には4つの入力方式がありました。

  • オーバーザスポット
  • オンザスポット
  • オフザスポット
  • ルートウィンドウ

それぞれの入力方式については以下のドキュメントに分かりやすく書かれています。

Seamonkey インプットメソッド仕様書

Seamonkey インプットメソッド仕様書 著者: Tague Griffith このドキュメントの内容: インプットメソッドの編集方式 プラットフォームのプロトコル エディターの関数 参考文献 イ...

https://www.mozilla-japan.org/projects/intl/input-method-spec.html

Windows の IME で一般的に使われるのはこのうちオンザスポットとオーバーザスポットです。メモ帳の様にキャレット上に仮入力がオーバーレイされているのがオーバーザスポット、MS Word の様に後続する文字も一緒に動きながら仮入力を行うのがオンザスポットです。Vim の実装上、本来であればオーバーザスポットが相応しいはずです。Windows 版の Vim もオーバーザスポットです。しかしながら GTK2 版においてはなぜか初回の実装からオンスポットになっており、しかもオンザスポットでしか入力出来ない様になっていました。

そしてまぁこのオンザスポット版にはたくさんバグがありました。そりゃそうです。IME からのコールバックで文字を自ら描画しないといけないのですから、IME と Vim で整合性を取らないといけません。しかも Vim 側の実装方式も良く無かった。Vim の基本実装は、文字入力と画面表示が明確に分けて実装されています。この文字入力部分に IME から貰った仮入力文字を流し込み、例えば「かんじ」という入力から「漢字」という仮入力に変換する際、「"かんじ" の3文字を消しながら "漢字" を挿入」といった実装になっていたのです。この方式を実装するにはいろいろな所に手を入れないといけません。もし仮入力をキャンセルするのであれば、現在の仮入力を全て「カーソル左」と「デリートキー」で削除しないといけないのです。しかもこの入力が map の影響を受けてしまっており、例えばカーソルキーに別のキーを割り当てていると IME の仮入力が目も当てられない状況になるです。

僕は問題が見付かる度にパッチを送りました。バグが見つかる度に ifdef XIM のコードが増えて行き、次第に Vim の開発者 Bram 氏も二つ返事でパッチを取り込んでくれなくなってしまいました。これがバージョン7の頃だったと思います。我々 vim-jp も何時しか vim-dev に XIM 関連のパッチを送る事が無くなってしまいました。

日本人にとって、Vim にとって、きちんと日本語入力を行う為には、もはやオーバーザスポットしかあり得なかったのです。 中平さんが作ってくれたオーバーザスポットのパッチは我々の一つの望みでもあったのですが、Bram 氏は取り込んでくれませんでした。

この時点で、Linux の GVim で問題なく日本語を入力する術が無くなってしまったのです。

そんな半ばあきらめムードだったのですが、一筋の光明が現れます。

terminal、お前だったのか

Vim に terminal が実装され出し、Vim のコミット量が一気に増えました。

vim-dev

そしてふと、こんな事を思いついたのです。

今のオンザスポット入力方式だと、後続のテキストが動いてしまうので今の terminal の実装では画面が壊れちゃうよなー

そんな思いで中平さんのパッチについて GitHub Issues で突いてみたのです。

Mapping backspace while typing Korean - Issue #1215 - vim/vim - GitHub
https://github.com/vim/vim/issues/1215

まぁ何時もの様に Bram 氏から返事は返ってこないだろうなと思っていた所、思いもよらぬリプライが。

Bram「それは中平が書いたパッチを k-takata が改良した奴の事かい?」

これは心が躍りました。急いで「そうだよ!」と返事を返しました。半信半疑でどきどきしながら待ちました。

そして先日の朝、patch 8.0.1026 として、1つのパッチが取り込まれました。早朝このコミットに気付いた僕は早く最新の Vim をコンパイルしたくて溜まらないくらいに心が躍ったのを覚えています。

数ある中の1コミットかもしれませんが、多くの日本人開発者が悩んで実装して壊されて、それでも戦ってきた歴史が、僕の脳裏には蘇ってきたのです。

そして時代も良い方向に動き始めました。現在の Linux デスクトップで日本語入力と言えば fcitx が一般的です。そして fcitx はコマンドから IME を ON/OFF 出来るのです。

Vimからfcitxを使う - Qiita

近頃の ibus や uim の使い勝手がイマイチなこともあり、Linux 上での Input Method として fcitx が最近ポピュラーになってきました。 我らが SKK では、その他のIn...

http://qiita.com/sgur/items/aa443bc2aed6fe0eb138

この記事の中に書かれている設定を行えば、ESC で日本語をオフに出来る様になります。

気付いたら、僕らを長年苦しめ続けて来た Linux 版 Vim の 日本語入力問題は、解決し始めていたのです。もちろん Bram 氏が動いてくれたのは、あの GitHub Issue が理由でもなく、terminal が直接の理由でもない事は覚えて覚えておかなければなりません。過去に繰り返しパッチを送り続けてくれた日本人 Vim 開発者の功績あってこそ、きちんとした日本語が入力出来る今の Vim がある事を。


追記 2017/09/16

提案したところ、なんと iminsert/imseach の値が 0 になりました!

patch 8.0.1114: default for 'iminsert' is annoying - vim/vim@4cf56bb - GitHub
https://github.com/vim/vim/commit/4cf56bbc85f77846aeb378cfb071677336dfad6d

2017/08/29


株式会社はてな さんから献本頂きました。ありがとうございます。

Mackerel サーバ監視[実践]入門 Mackerel サーバ監視[実践]入門
井上 大輔, 粕谷 大輔, 杉山 広通, 田中 慎司, 坪内 佑樹, 松木 雅幸
技術評論社 / ¥ 3,132 (2017-08-26)
 
発送可能時間:在庫あり。

書籍「Mackerel サーバ監視[実践]入門」を執筆しました | おそらくはそれさえも平凡な日々

書籍「Mackerel サーバ監視[実践]入門」を執筆しました Mackerel サーバ監視[実践]入門 やっと出せました。この本は、僕がはてなに入社してからずっと携わっている、 Mackerel と...

http://www.songmu.jp/riji/entry/2017-08-28-mackerel-book.html

僕が Mackerel を知ったのは2014年5月の事でした。

mackerel-agentをオープンソース化しました - Mackerel ブログ #mackerelio

本日、mackerel-agentを オープンソース 化しました。 リポジトリ は GitHub 上の mackerelio/mackerel-agent です。 mackerel-agentは Go...

https://mackerel.io/ja/blog/entry/2014/05/16/142556

昔からはてなの少しギーク寄りなサービスが大好きだったのと、mackerel-agent が僕の好きな Go言語 で書かれていた事もあり、いち早く GitHub からソースを git clone して眺めていました。初見から Windows に対応していない事を知った僕はすぐさますぐさま Windows porting に取り掛かり、プルリクエストを送りました。

Windows porting by mattn - Pull Request #8 - mackerelio/mackerel-agent - GitHub
https://github.com/mackerelio/mackerel-agent/pull/8

あれから3年経ちました。Mackerel はどんどん大きくなって SI 業や Web ホスティング業など色々な企業で使われる様になり、今や国内の SaaS 型サーバ監視サービスの先駆者的なポジションを確立したのではないかと思います。

Mackerel ではサービスだけでなく mackerel-agent も日々改良が加えられており、現在では僕が書いた Windows 向けのコードはほぼ無くなってしまったかもしれませんが、今思えば僕が Windows に移植した mackerel-agent が様々な企業で使われ、刻々とサーバのメトリクスを休む事なく Mackerel サーバに送り続け、問題が起きた Windows サーバのアラートを上げていると考えると「あぁ、いい仕事したな」と胸が熱くなると同時に、「あれ僕が Windows 移植したんだ」と誇らしい気持ちにさえなりました。

今回読んだ「Mackerel サーバ監視[実践]入門」はこう言った Mackerel の生い立ちだけでなく Mackerel そのものの概念、監視のイロハ、活用例など、数千のサーバを管理している彼らでないと書けない実践的な内容が包み隠さず書かれています。

Mackerel というサービスの利用者は一般ユーザではありません。インフラを管理する、どちらかと言えば開発者寄りの方達です。エンジニアである Mackerel の開発者が、開発者に向けて OSS として機能を提供しているので Mackerel には気の利いた機能が沢山あります。mackerel-agent が使用するプラグインもその一つです。サーバの監視で必要と思われる様なプラグインが既に沢山作られています。

GitHub - mackerelio/mackerel-agent-plugins: Plugins for mackerel-agent
https://github.com/mackerelio/mackerel-agent-plugins
GitHub - mackerelio/go-check-plugins: Check Plugins for monitoring written in golang
https://github.com/mackerelio/go-check-plugins

一度プラグインを作ってみられると分かると思いますが、ドキュメントもあり参考にできるプラグインも沢山あるので簡単に実装できると思います。アイデア次第では色々な使い方があると思います。例えば温度計や水位計と連動してアラートを上げたり、PC であれば Windows のセキュリティパッチが未インストールの場合にアラートを上げるなんて事も実に簡単に実装する事が出来ます。

Mackerel チェック機能の意外と知られていないテクニック集 - Qiita
http://qiita.com/mattn/items/b7099044263875ed1f73

本書ではコード例も付けて実際に mackerel-agent プラグインを作る手順が細かく書かれています。Go言語は言語仕様が難しくないので、この本片手に簡単にプラグインが作れると思います。

もう一つ僕が気に入っている Mackerel の機能が mkr です。mkr は Mackerel の設定やメトリクス値を簡単に操作できる CLI です。

GitHub - mackerelio/mkr: Command Line Tool for Mackerel
https://github.com/mackerelio/mkr

このツールを使えば監視しているホストの状態取得やメトリクス値を抜き出す事が出来ます。本書にもこの mkr を使ったテクニックが色々と書かれています。これは本書で知ったのですが、どうやら はてな社は Mackerel をホスト管理としても使っている様で、数千いるサーバのロールをうまくラベリングして運用されているとの事でした。API を直接叩いてホスト一覧を得る事もそれほど難しくはありませんが、mkr の様にコマンド一発で色々な情報を Mackerel から抜き出せる機能は、多くのサーバを管理しているエンジニアにとっては必須アイテムかと思います。Mackerel ユーザで mkr を使った事ない方はぜひ使ってみると良いです。

僕が本書で一番おもしろいと思ったのは、実は巻末部分でした。Mackerel というサービスがどの様に構成されているかが書かれています。なぜ PostgreSQL や Graphite を使っているのか、そして今後の為に Graphite から移行しようとしていると言った内容が惜しげもなく書かれており、今も進み続ける Mackerel らしさが良く分かる内容でとても興味深く読ませて頂きました。

特に Mackerel が今のアーキテクチャに至った経緯の解説をしている節では、Mackerel のサーバがどういった理由でこういう構成になっているのかが理由を交えて詳しく書かれており、「あぁ、Mackerel を大事に育ててるんだな」と凄く伝わる内容でした。

不慮の障害を避ける為には、監視は機械的でなければなりません。人間による、しかも属人的な監視は時に間違いを起こし、ミスは大きな事故に繋がります。単調な監視はシステムに任せ、我々開発者は安心して別の事に注力するのが今のあり方なのでしょうね。そしてその安心は、優秀な Mackerel 開発チームの「Mackerel 愛」があってこそ、実現されているのだろうな、と分かる1冊でした。


2017/08/25


gRPC は型の強い RPC を色々な言語を使って実装できる仕組みとライブラリです。

Big Sky :: Protocol Buffers を利用した RPC、gRPC を golang から試してみた。

grpc/grpc · GitHub gRPC - An RPC library and framework https://github.com/grpc/grpc gRPC は Google が開...

https://mattn.kaoriya.net/software/lang/go/20150227144125.htm

とても便利なのですが幾分手数が多いのが難点で、ちょっとしたサービスを gRPC で実装したいと思っていてもそう簡単に作る事が出来ませんでした。

ところが今回ご紹介する lile を使うと、とても簡単に gRPC を使った golang の実装を作れてしまいます。

GitHub - lileio/lile: Easily create gRPC services in Go

readme.md ALPHA: Lile is currently considered "Alpha" in that things may change. Currently I am gath...

https://github.com/lileio/lile

lile は gRPC のスケルトンを生成するコマンドとライブラリセットです。今日はこれを使って簡単に gRPC のサービスを作ってみます。お題は GENE95 辞書 を gRPC 経由で照会するサービスです。

まず lile をインストールするには以下のコマンドを実行します。

$ go get github.com/lileio/lile/...

Windows の人は今 pull-request を作ってるのでそちらを使って下さい。執筆時点でまだマージされてませんが。

lile をインストールしたらまずスケルトンを生成します。

$ lile new gene9go
Creating project in /home/mattn/go/src/github.com/mattn/lile-example/gene9go
Is this OK? [y]es/[n]o
yes
.
├── server
│   ├── server.go
│   └── server_test.go
├── subscribers
│   └── subscribers.go
├── gene9go
│   ├── cmd
│       ├── root.go
│       ├── serve.go
│       ├── subscribe.go
│       └── up.go
│   └── main.go
├── gene9go.proto
├── Makefile
├── Dockerfile
├── .travis.yml
└── .gitignore

git push できるくらいの物が生成されています。次に proto ファイルを編集して独自のインタフェースを作成します。元の proto ファイルは以下の様になっています。

syntax = "proto3";
option go_package = "github.com/mattn/lile-example/gene9go";
package gene9go;

message Request {
  string id = 1;
}

message Response {
  string id = 1;
}

service Gene9go {
  rpc Read (Request) returns (Response) {}
}

これを以下の様に編集しました。

syntax = "proto3";
option go_package = "github.com/mattn/lile-example/gene9go";
package gene9go;

message Request {
  string Word = 1;
}

message Response {
  string Text = 1;
}

service Gene9go {
  rpc Translate (Request) returns (Response) {}
}

辞書引きなので Translate メソッドを追加しています。編集し終えたら Makefile のある場所で make を実行します。するとこの proto ファイルから Translate メソッドのスケルトンが生成されます。

package server

import (
    "errors"

    "github.com/mattn/lile-example/gene9go"
    context "golang.org/x/net/context"
)

func (s Gene9goServer) Translate(ctx context.Context, r *gene9go.Request) (*gene9go.Response, error) {
    return nil, errors.New("not yet implemented")
}
尚、この時点でテストコードのスタブも生成されます。とても便利です。

package server

import (
    "testing"

    "github.com/mattn/lile-example/gene9go"
    "github.com/stretchr/testify/assert"
    context "golang.org/x/net/context"
)

func TestTranslate(t *testing.T) {
    ctx := context.Background()
    req := &gene9go.Request{}

    res, err := cli.Translate(ctx, req)
    assert.Nil(t, err)
    assert.NotNil(t, res)
}

さてでは Translate メソッドの中身を実装します。gene.txt ファイルを読み込んで単語にマッチする次の行を返しているだけです。gene.txt は utf-8 で保存しておいて下さい。

package server

import (
    "bufio"
    "os"
    "strings"

    "github.com/mattn/lile-example/gene9go"
    context "golang.org/x/net/context"
)

func translate(word string) (stringerror) {
    f, err := os.Open("gene.txt")
    if err != nil {
        return "", err
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)
    found := ""
    for scanner.Scan() {
        first := scanner.Text()
        if !scanner.Scan() {
            break
        }

        if strings.ToLower(first) == strings.ToLower(word) {
            found = scanner.Text()
            break
        }
    }
    return found, scanner.Err()
}

func (s Gene9goServer) Translate(ctx context.Context, r *gene9go.Request) (*gene9go.Response, error) {
    text, err := translate(r.GetWord())
    if err != nil {
        return nil, err
    }
    return &gene9go.Response{Text: text}, nil
}

あとはクライアントとサーバを作ります。といっても Register 関数が用意されているのでこちらも簡単。まずはサーバ。

package main

import (
    "log"
    "net"

    "github.com/mattn/lile-example/gene9go"
    "github.com/mattn/lile-example/gene9go/server"
    "google.golang.org/grpc"
)

func main() {
    lis, err := net.Listen("tcp"":11111")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    srv := grpc.NewServer()

    gene9go.RegisterGene9goServer(srv, &server.Gene9goServer{})
    srv.Serve(lis)
}
そしてクライアント。
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/mattn/lile-example/gene9go"
    "google.golang.org/grpc"
)

func main() {
    conn, err := grpc.Dial("localhost:11111", grpc.WithInsecure())
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    client := gene9go.NewGene9goClient(conn)
    req := &gene9go.Request{
        Word: os.Args[1],
    }
    resp, err := client.Translate(context.Background(), req)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(resp.Text)
}
後から気付いたのですが、gene9go の下にサーバコマンドも生成されてました。いたれりつくせり過ぎる。
A gRPC based service

Usage:
  gene9go [command]

Available Commands:
  help        Help about any command
  serve       Run the RPC server
  subscribe   Subscribe to and process queue messages
  up          up runs both RPC and pubub subscribers

Flags:
  -h, --help   help for gene9go

Use "gene9go [command] --help" for more information about a command.

これだけです。なにこれ超簡単じゃん。サーバを起動した状態で、クライアントに単語を付けて起動します。

$ client Go
1.〜に進行する,行く,をしに行く,動く,過ぎる,至る,及ぶ,2.〜と書いてある

これを実装するのにわずか20分程度しか掛かりませんでした。今まで gRPC を使ったサービスに興味があったけど実装難しいと思っていた方はぜひ lile を使ってみて下さい。あっと言う間に実装できるはずです。

この記事で作ったソースファイルは以下に置いておきます。

GitHub - mattn/lile-example
https://github.com/mattn/lile-example