Slide 1

Slide 1 text

golangci-lint徹底入門 @sanposhiho

Slide 2

Slide 2 text

お前 is 誰 名前: Kensei Nakada / sanposhiho 所属: 京都大学 4回生 (卒業できれば)22年入社予定 期末レポートがやばい @sanposhiho @sanpo_shiho

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

目次 0. golangci-lint とは 1. golangci-lint の使用方法を学ぶ 2. golangci-lint に搭載されているlinterを学ぶ 3. golangci-lint の内部実装を学ぶ

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

後でフルバージョンをZennで公開します

Slide 8

Slide 8 text

golangci-lint とは

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

golangci-lint の使用方法を学ぶ

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

参考: デフォルトで有効なlinter達

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

基本的な設定内容(linters) - [方針1] enable-all/disable パターン
 - [方針2] disable-all/enable パターン
 どちらを使えばいいの?
 多くのlinterを使いたい → 「1. enable-all/disable パターン」 
 新しいlinterを積極的に追加する必要がなく、バージョンアップには既存のバグの修正等のみを求める →「2. disable-all/enable パターン」
 


Slide 21

Slide 21 text

[余談] enable-allは一度非推奨になっていた話 2019年10月 こちらのPRでドキュメントに > please, do not use enable-all: it's deprecated and will be removed soon. という文言が追加されました

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

nolintによる報告の無視

Slide 32

Slide 32 text

nolintによる報告の無視

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

[余談] 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の間にスペースがある )と書くこともできるがこれもスペースがあるので フォーマットに即していないことになる

Slide 37

Slide 37 text

[余談] nolintのシンタックスはGoの慣習に即していない? またnolintは”// nolint” (ただのコメント)と書くこともできる → コメントディレクティブの形で統一した方が良いんじゃないかという議論もされている

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

golint(非推奨)(archived) - メンテがされていない - 2018年から実質的な変更が加わってない - Issueも放置されているものが多い - golang orgに存在するlinterなのでGoが公式として推奨しているlinterに見える - Go が実際には保守されていないプログラムを公式として推奨しているように見えてしまう - 開発者は合理的に異なるスタイルを採用したい場合がある - Golint単体で特定の警告を無視したりするなどの機能を持っていない

Slide 43

Slide 43 text

revive Golintの代替を目指して開発されたlinter 先のGolintの課題であるカスタマイズ機能を有しているなどする。 golangci-lint上ではreviveがgolintの代替として推奨されています。 https://github.com/mgechev/revive

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

golangci-lint の内部実装を学ぶ

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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