$30 off During Our Annual Pro Sale. View Details »

golangci-lint徹底入門

sanposhiho
July 19, 2021
320

 golangci-lint徹底入門

sanposhiho

July 19, 2021
Tweet

More Decks by sanposhiho

Transcript

  1. golangci-lint徹底入門 @sanposhiho

  2. お前 is 誰 名前: Kensei Nakada / sanposhiho 所属: 京都大学

    4回生 (卒業できれば)22年入社予定 期末レポートがやばい @sanposhiho @sanpo_shiho
  3. None
  4. None
  5. 目次 0. golangci-lint とは 1. golangci-lint の使用方法を学ぶ 2. golangci-lint に搭載されているlinterを学ぶ

    3. golangci-lint の内部実装を学ぶ
  6. 目次 0. golangci-lint とは 1. golangci-lint の使用方法を学ぶ 2. golangci-lint に搭載されているlinterを(ちょっとだけ🙏)学ぶ

    3. golangci-lint の内部実装を学ぶ
  7. 後でフルバージョンをZennで公開します

  8. golangci-lint とは

  9. golangci-lint とは > golangci-lint is a Go linters aggregator. 多くのlinterを搭載しており、同時に実行することができる便利ツール

  10. None
  11. golangci-lint の使用方法を学ぶ

  12. 基本的な使い方 設定ファイルをもとに実行する auto fixに対応しているlinterに修正までやってもらう

  13. 基本的な使い方 特定のlinterを実行

  14. 設定ファイルを書く ・ファイル(.golangci.yml)を用いた設定に対応 → 設定をかけば golangci-lint run するだけ

  15. 基本的な設定内容(linters) 「linters」ではどのlinterを有効にするかを指定 ・disable-all →全てのlinterを無効にする ・enable-all →全てのlinterを有効にする ・disable → 指定したlinterを無効にする ・enable

    → 指定したlinterを有効にする
  16. 参考: デフォルトで有効なlinter達

  17. 基本的な設定内容(linters) - [方針1] enable-all/disable パターン
 - [方針2] disable-all/enable パターン

  18. [方針1] enable-all/disable パターン ブラックリスト方式で指定できる メリット 新たなlinterが自動で追加される デメリット バージョンによって実行されるlinterが変化して しまう

  19. [方針2] disable-all/enable パターン ホワイトリスト方式で指定できる disable-allはデフォルトで有効なlinterも無効 にします メリット 実行されるlinterを固定できる デメリット 新しいlinterに追従しにくい

  20. 基本的な設定内容(linters) - [方針1] enable-all/disable パターン
 - [方針2] disable-all/enable パターン
 どちらを使えばいいの?


    多くのlinterを使いたい → 「1. enable-all/disable パターン」 
 新しいlinterを積極的に追加する必要がなく、バージョンアップには既存のバグの修正等のみを求める →「2. disable-all/enable パターン」
 

  21. [余談] enable-allは一度非推奨になっていた話 2019年10月 こちらのPRでドキュメントに > please, do not use enable-all:

    it's deprecated and will be removed soon. という文言が追加されました
  22. [余談] enable-allは一度非推奨になっていた話 理由 - 新しいlinterが自動で追加されるのはいいこと - だけどCIのビルドが落ちるようになったりとか、一つ一つ新しいlinterを無効に設定 しなきゃとかめんどくさいよね

  23. [余談] enable-allは一度非推奨になりかけた話 時は流れ… 2021年6月に Un-deprecateに

  24. [余談] enable-allは一度非推奨になりかけた話 - enable-allでしか実現できないメリットがある - 新しいlinterの追加など - 「CIで落ちる」というのはenable-allの問題ではなく、「enable-allを使う」という選択 の誤り

  25. 基本的な設定内容(run) linterの実行に関する設定です。 skip-dirsとskip-filesのみ紹介します。

  26. skip-files 一致するファイルにはlinterを実行しません

  27. skip-dirs 一致するパス以下にはlinterを実行しません

  28. 基本的な設定内容(issues) linterの報告に関する設定です。例えば特定の報告を無視するような設定ができたりし ます。 excludeとexclude-rulesのみ紹介します。

  29. exclude 特定の文言を含む報告を全て無視する

  30. exclude-rules ここで設定したルールに合致する報告は無視される - 特定のlinterを特定のファイルには実行しない(path) - 特定のlinterの特定の文言の報告を無視する(text) - 特定のlinterの特定の箇所の報告を無視する(source)

  31. nolintによる報告の無視

  32. nolintによる報告の無視

  33. None
  34. nolintによる報告の無視 nolintの理由を記載する TIPS: nolintlintというlinterでnolintの理由が記載されているかどうかを確認できる

  35. [余談] nolintのシンタックスはGoの慣習に即していない?

  36. [余談] nolintのシンタックスはGoの慣習に即していない? - goのツールは//go:*というコメントディレクティブを使用することになっている - https://golang.org/cmd/compile/ - 他のツールも//^[a-z]+:[a-z]+.というフォーマットでコメントディレクティブを使用するの が一般的である -

    ちゃんと公式にアナウンスするための以下の issueがたっている - https://github.com/golang/go/issues/43776 - //nolint: hoge (nolint:とhogeの間にスペースがある )と書くこともできるがこれもスペースがあるので フォーマットに即していないことになる
  37. [余談] nolintのシンタックスはGoの慣習に即していない? またnolintは”// nolint” (ただのコメント)と書くこともできる → コメントディレクティブの形で統一した方が良いんじゃないかという議論もされている

  38. golangci-lint に搭載されているlinterを学ぶ

  39. golangci-lint に搭載されているlinterを学ぶ 全部紹介するのは時間的に厳しいので、sanposhihoが個人的に紹介したいlinterの みを取り上げます → 「後でZennに上げます」と言っていたものには全てのlinterとその一口解説が載って います。 ここで上げるlinterは勿論golangci-lint上以外からも実行できます。

  40. [ちょっとその前に]非推奨のlinterって? golangci-lintにはgolangci-lint上での使用を非推奨とされているlinterが存在します これらのlinterは将来的にgolangci-lint上から削除される予定です 具体的にどのようにdeprecation cycleをデザインするかは現在議論中。

  41. golint(非推奨)(archived) Goのorganization下でメンテナンスされていたlinterです。 今年の5月に非推奨となり、リポジトリもアーカイブされました 詳しくは→

  42. golint(非推奨)(archived) - メンテがされていない - 2018年から実質的な変更が加わってない - Issueも放置されているものが多い - golang orgに存在するlinterなのでGoが公式として推奨しているlinterに見える

    - Go が実際には保守されていないプログラムを公式として推奨しているように見えてしまう - 開発者は合理的に異なるスタイルを採用したい場合がある - Golint単体で特定の警告を無視したりするなどの機能を持っていない
  43. revive Golintの代替を目指して開発されたlinter 先のGolintの課題であるカスタマイズ機能を有しているなどする。 golangci-lint上ではreviveがgolintの代替として推奨されています。 https://github.com/mgechev/revive

  44. errorlint, goerr113 errorの比較をerrors.Isを使用していない箇所等を検出します。 (それ以外もそれぞれ色々検出します) Go 1.13からerror型はfmt.Errorf()を使用してwrapすることができ、==などで比較すると wrapされているerrorをうまく比較できない場合があります、 詳しくは→ https://golang.org/pkg/errors/

  45. paralleltest, tparallel, thelper 全てテストに関係するlinterです。 t.Parallel()やt.Helper()などが使用されているかどうかを確認してくれます。

  46. wastedassign 不要な代入を検出するlinterです。 僕が作ったので宣伝のために紹介に入れました。(正直でよろしい) https://github.com/sanposhiho/wastedassign

  47. golangci-lint の内部実装を学ぶ

  48. golangci-lint の内部実装を学ぶ 一歩踏み込んで golangci-lint のlinterを実行する様子をコードベースで追ってみましょ う。 参考にしているのはv1.41.1時点でのコードです。

  49. golangci-lint の内部実装を学ぶ 公式ドキュメントにもArchitectureの章が存在します https://golangci-lint.run/contributing/architecture/

  50. golangci-lint の内部実装を学ぶ ではみてみましょう (→sanposhihoが頑張ってGoLandで読んでいきます)

  51. 終わりに 設定の話から始まり、搭載されているlinterの話、内部実装など、golangci-lintへの理解 が少し深まったのではないでしょうか Goにおけるlinterの作成/静的解析に興味が出た人は @tenntenn さんが公開している 「プログラミング言語Go完全入門」の14章がおすすめです ↓ https://engineering.mercari.com/blog/entry/goforbeginners/