protoc-gen-lint 以外の Protocol Buffer の Linter を紹介する

Protocol Buffer や gRPC についての記事やスライドを読むと、lint ツールの紹介として **protoc-gen-lint** がよく取り上げられているのを見る。

このツールはかなり前からあるし、protoc のプラグインとして提供されていて使いやすいということもあって未だに人気があると感じる。
ただし、これは少し前の Google スタイルガイドを参考にしているためサポートしているルールが少ないのと、バグ（に近い）修正が放置されていることからも開発はあまり活発であるとはいえない。

現在では、Protocol Buffer の Linter は他にもあり、より多くのリントルール、カスタムリントルールのプラグインサポート、コメントによるリント無効化制御、互換性チェック機能、protoc 依存の排除、Google API Standard 準拠のチェック、Vim/Jetbrain/VSCode エディター統合などを備えた、より開発も活発なツールがいくつかある。
あまり、それらのツールについての紹介を見ないので、protoc-gen-lint と合わせて比較できるように紹介していきたいと思う。

ref.

- [ckaznocha/protoc-gen-lint: A plug-in for Google's Protocol Buffers (protobufs) compiler to lint .proto files for style violations.](https://github.com/ckaznocha/protoc-gen-lint)
- [Style Guide  |  Protocol Buffers  |  Google Developers](https://developers.google.com/protocol-buffers/docs/style)

### Disclaimer

- 以下は 2019.12 時点の情報を元にしている
- 筆者は後述する `protolint` というツールを開発している。そのため、それとの比較を中心に日頃からフォローしている情報が元になっている。

# protoc-gen-lint

サポートしているリントルールは次の 7 つ。
import 文の並び順を揃えるのと、Enum や Message 名のケースを揃えるルールがある。
これらのルールは後述する Linter はすべて備えている。

```
	"Sort import statements alphabetically.",
	"Use CamelCase (with an initial capital) for message names.",
	"Use underscore_separated_names for field names.",
	"Use CamelCase (with an initial capital) for enum type names.",
	"Use CAPITALS_WITH_UNDERSCORES  for enum value names.",
	"Use CamelCase (with an initial capital) for service names.",
	"Use CamelCase (with an initial capital) for RPC method names.",
```

良いところ

- 7 つのルールをチェックするという機能だけをサポートしていて、他に何か特別な機能というものはないので、**learning curve は緩やか**で使いやすい。
- protoc プラグインとして使うのでワークフローに組み込みやすい
- vim(ale) プラグインが提供されている

気になるところ

- **Google スタイルガイドは今年大きく加筆されたがそれに対応していない**ので、ルールの数が少ない
  - 具体的には、`Enum フィールドの命名規則`、`ファイル名の命名規則`、`ファイル構造規則`、`1行の文字数制限`、`インデント規則`、`パッケージ名規則`がない。
- protoc プラグインに依存しているので、protoc がローカルに必要。また、その結果、実行時間が少し長くかかる。
- リント違反の修正機能（以下、fixer）がない
- CamelCase に、つまり Message や Enum, Service 名に "H264", "C99", "S3" が使えない
- **開発がアクティブではない**。 https://github.com/ckaznocha/protoc-gen-lint/pull/18

# prototool

リント以外の機能も充実していて star 数も多いので、今回紹介する中ではイチオシの一つで考えていたが、今月に入ってすぐ以下の一文が README に追加された。

> Update: We recommend checking out Buf, which is under active development. There are a ton of docs for getting started, including for migration from Prototool.

buf については後述するとして、確かに prototool はサポートしている機能の範囲がとても広いので、リント機能だけに絞っても開発が停滞気味なのかなとは思っていた。リント周りの feature request がよく Close されていたり、カスタムリンター機能の開発は止まったままだったりしていた。

prototool は最新の Google スタイルガイドのルールをほぼ（`Standard file formatting` 以外）サポートしている。また、Uber 独自のより細かいルールを適用することもできる。format コマンドを使えば、そのスタイルに自動で書き換えることができる。vim プラグインも提供されている。また、protoc プラグインに依存していないので、簡単に実行できて処理も早い。

良いところ

- **多くのリントルールをサポートしている**
- 名前の通り、**リント以外にも互換性チェックや開発上のユーティリティツールが一緒に提供されている**
- format コマンドが提供されている
   - ただし、個別のルールに応じたものではないので特定のルール違反だけ修正するみたいなことはできない。uber スタイルや google スタイルに強制変換される。

気になるところ

- **公式で別のツールを推奨している**ので、新規で導入するのは躊躇われる
- 機能が豊富なので learning curve はそれなりにある
- 独自リントルールをカスタムプラグインの形で導入できない
- protoc プラグインが提供されていない

ref. 

- [uber/prototool: Your Swiss Army Knife for Protocol Buffers](https://github.com/uber/prototool)


# protolint


筆者が開発している Linter。
リント機能だけに絞って、そこの充実を図っている。それ以外の例えば互換性チェックは[個別のツールがある](https://github.com/jhump/protoreflect)のでそちらを併用してくださいというスタンス。

protolint は最新の Google スタイルガイドのルールをすべてサポートしている。一部（import 文のソートと、インデントの統一）だが fixer も提供している。prototool と比べると、`Standard file formatting と呼ばれる、1行の文字数制限とインデント規則のリントルールをサポートしていること`、`独自ルールを導入できるプラグインシステムがあること`（例えば suffix が Request の Message があったら対応する Response Message が必要というローカルルールを追加できる）、`コメントで特定箇所だけルールを無視することができること`、`Editor（Vim/Jetbrain IDE/VSCode）とCI（Jenkins/GitHub Action） のインテグレーションが豊富なこと`、`protoc plugin も提供している（protoc-gen-protolint）`のが特徴。

良いところ

- **Google スタイルガイドのルールをすべてサポートしている。**それ以外にも Go スタイルのコメント必須化などデフォルト無効のルールを[いくつかサポートしている](https://github.com/yoheimuta/protolint#rules)。
- Linter/Fixer としての機能以外サポートしていないので、**learning curve は緩やかに使いはじめることができる**
- この中で唯一カスタムリントルールをプラグインとして追加できる

気になるところ

- prototool のように**これ一つでリント以外のあらゆる開発ニーズを満たすようなものではない**

ref. 

- [yoheimuta/protolint: A pluggable linter and fixer to enforce Protocol Buffer style and conventions.](https://github.com/yoheimuta/protolint)
- [protolint/cmd/protoc-gen-protolint at master · yoheimuta/protolint](https://github.com/yoheimuta/protolint/tree/master/cmd/protoc-gen-protolint)

# api-linter

Google's API standards に沿っているかをチェックする Linter。他と違って、Protocol Buffer のスタイルをチェックするというよりも、Protocol Buffer で定義した API のスタイルをチェックするためのもの。[General AIPs](https://aip.dev/general) に準拠した API を書きたい場合には便利だが、それ以外で使うにはやりすぎになるかもしれない。

開発はかなり活発に行われている。

良いところ

- **Google's API standards に沿っているかチェックできる**
- ドキュメントが整っていて、開発は活発でメンテナンスされている
- protoc プラグインも提供されている

気になるところ

- Protocol Buffer のスタイルをチェックしたいだけであればやりすぎでかえって手間がかかる
- fixer/formatter は提供されていない

ref. 

- [Google API Linter](https://linter.aip.dev/)
- [googleapis/api-linter: A linter for APIs defined in protocol buffers.](https://github.com/googleapis/api-linter)


# buf

最近リリースされて一部で注目を集めはじめている Linter。互換性チェックの機能もサポートしていて、prototool からの移行手順も用意されている。独自のスタイルガイドを整備していて、全体的にドキュメントが非常に整っている。当然開発もアクティブに行われている。Vim Plugin がメンテナンスされている。

技術的には、Protocol Buffer のパース処理が特徴的で、protoc のアウトプットを使う方法と独自（= 3rd party）のパーサーを使う方法の 2 つをサポートしている。protoc-gen-lint は protoc のプラグインなので前者、prototool と protolint はそれぞれ https://github.com/emicklei/proto と https://github.com/yoheimuta/go-protoparser というパーサーを使っているので後者。

protoc はかなり柔軟な Protocol Buffer ファイルを許容する一方で、3rd party のパーサーは基本的に公式が提供している EBNF に準拠しているだけなので protoc が通すファイルをパースできないということがよくあった。ただ、protoc を使うやり方は protoc を一緒にインストールしないと使えないのでその依存の管理が面倒というデメリットがある。buf はその解決策としてどちらもサポートするというやり方をとっている。裏側では https://github.com/jhump/protoreflect をパーサーとして使うことで解決している。このパーサーが protoc のアウトプットを処理できる。ちなみに、api-linter は当初 protoc だけを使うやり方を採用していたが今では buf と同じやり方に移行している。

- とはいえ、個人的には 3rd party パーサーも時間経過とともに多くの例外に対応していっているのでパースエラーに遭遇する機会はあまり多くないと思う

良いところ

- 自他ともに認められた **prototool の後継ツール**
- **ドキュメントが豊富で整備されている**
- protoc プラグインも提供されている

気になるところ

- 独自のスタイルガイドがデフォルトのルールになっていてそれなりにボリューミーなので、カスタマイズして合わせるには **learning curve が多少ある**
- fixer/formatter は提供されていない

ref.

- [bufbuild/buf: A new way of working with Protocol Buffers.](https://github.com/bufbuild/buf)
- [Style Guide · Buf](https://buf.build/docs/style-guide)
- [Protocol Buffers Version 3 Language Specification  |  Google Developers](https://developers.google.com/protocol-buffers/docs/reference/proto3-spec)

# まとめ

同じ Linter と言っても、それぞれ小さな違いがたくさんあるので以下を参考に一つ使ってみて、問題があったら他を試してみると良いと思う。

### やりたいこと別のおすすめツールは次の通り

1 つのツールでリント以外の様々な開発支援をしてほしい

- prototool
- (buf)

protoc-gen-lint と同じような使い勝手のものに移行したい

- protoc-gen-protolint
- protoc-gen-buf

prototool と同じような使い勝手のものに移行したい

- buf

[Google's API standards](https://aip.dev/general) に沿っているかチェックしたい

- api-linter

[Google Style Guide](https://developers.google.com/protocol-buffers/docs/style) に沿っているかだけをチェックできればいい

- protolint

[Google Style Guide](https://developers.google.com/protocol-buffers/docs/style) よりも厳しいスタイルに合わせたい

- [buf](https://buf.build/docs/style-guide)
- [prototool](https://github.com/uber/prototool/blob/dev/style/README.md)

カスタムリントルールを追加したい

- protolint 

自分の Editor でチェックしたい

- protolint(Vim, Jetbrain IDE, VSCode)
- prototool(Vim)
- buf(Vim)