おそらくはそれさえも平凡な日々

Goでpublicである必要がないメソッドを一括でprivateにする雑Perlスクリプト

ボツネタかつ、golintが非推奨になりそうなので、急いで書きます。

golintを守ってれば、最低限Effective Goぽいコードを書くことができるので、初心者取っ掛かりのlintとしては良いよなーと個人的には思っており、非推奨には寂しい気持ちもあります。とはいえ、Goが言語自体も変化をしていく中で妥当な判断だと思います。しかし、他言語でも見られる光景ですが、lintをメンテナンスする難しさというものを感じてしまいますね…。

本題

さて、プロジェクトに途中からgolintを導入しようとすると(もはや導入すべきなのかどうか分かりませんが)、やたら警告が出てきて心が折れてしまうことで知られています。特に、 "exported $hoge should have comment or be unexported" と言うメッセージは量も多く、対応も大変なので困りものです。

これは「publicインターフェースには適切にドキュメントコメントを書くか、privateに変更しろ」というメッセージなのですが、これにちゃんと対応しようとすると、ドキュメントをちゃんと書く必要があるので大変なのです。まあ、サボってきたツケなのですが…。

以前の職場で、これを一括置換してダミーコメントで埋めてお茶を濁して、同僚に嫌な顔をされたことがあります。今では反省しております。

不必要なpublicインターフェースをprivateにする

とりあえず、まずはpublicである必要がないインターフェースはprivateにしてしまえばよいではないか、という雑なアイデアを思いつきました。プロジェクト内の別パッケージから利用されていないのであれば、privateにできるはずです。

静的解析でできればかっこいいのですが、めんどくさくてまずはPerlによる文字列置換でやってみた。アプローチは以下の通り。

golintで指摘されたインターフェース名一つ一つに対して以下をおこなう。

  1. インターフェース名をprivateにして(lcfirstして)一括置換する
  2. プロジェクトをテストコード含めてコンパイルが通るか試す
  3. コンパイルが通ったら、git commit する。通らなかったら git checkout . で戻す
  4. 次のインターフェースへ

つまり「置換してみてコンパイルが通ったら問題なかろう」という雑アプローチです。

実際のコード

これをGoのプロジェクト内で golint $(go list ./...) | perl unexport.pl とかやって使う。結構豪快なことをやっているので、実際に自分のプロジェクトで試してみたいときは、いつものコードベースとは別の場所にcloneしてから試すと良いかも知れません。結構時間かかります。

go test -c を使ってテストは実行しないもののコンパイルしているのが特徴です。

ボツになりました

手元のプロジェクトでやったところ、コンパイルは通ってビルドはできるものの、テストが全然通らなくなってしまったので諦めました。もう少し頑張ればなんとかなったのかも知れませんが…。

どうしてもreflectを使っているところで動作が変わり得てしまうので、その辺りがネックになりました。独自でreflect使ってなくても、JSON等のMarshal/Unmarshalでは内部的に使われているので。

その辺りがネックになることは事前に分かっていて、微調整で済めばワンチャン行けるかと思っていたのですがダメでした。

まあこういう雑な仕事をPerlでやるのは楽しいですね。正しい静的解析アプローチでどなたかが改めて解決してくれないか願っています。

今後のlint

社内プロジェクトに何らかのlintを入れたいんですが、staticcheck を手元で試した感じ良さそうなので、reviewdogと併せて導入しようかと考えています。

created at
last modified at

2020-06-13T19:08:31+0900

comments powered by Disqus