golangCI、Code Climateで品質管理を行った話

こんにちは
最近アプリケーションエンジニアと言いつつ、サーバーだらけ触ってるキムです。
今回はPJの品質管理と、今回品質管理で投入したツールの設定と、使い方について共有しようと思ってます。

# 入る前に
- golangciとcode climateを利用した経験になります。
- 詳細設定は各自PJの状況に合わせて調整したほうが良いです。
- 無理してプッシュするよりチームメンバーが納得できる範囲内で妥協することと、メンバーとの認識合わせを通じて、メンバー自ら努力するように環境を作るのが大事だと思います。
- golangciはGo言語に特化されてるツールです。言語ごとに色んなツールが存在するので、Go言語以外の言語を使う方はそれぞれ調べtください。
- code climate以外にもウェブを利用して、PJレポジトリを管理してくれるサービスはいくつかあります。こちらも調べてみてください。
    - [Sonar Qube](https://www.sonarqube.org/)などがありますね

# 品質管理てなんでするのか
[品質管理](https://ja.wikipedia.org/wiki/%E5%93%81%E8%B3%AA%E7%AE%A1%E7%90%86)はこんな意味を持ってます。
皆さんはコードの品質を管理してますか？？
ユーザーに提供してるアプリケーションの品質を管理するのはものすごく重要なものです。　品質をちゃんと管理してないていうのは比較すると、　普段我々が使ってる色んな商品が何も品質保証無しで我々提供してると同じ意味合いになります。　そんな商品だと、皆さんは安心して購入できるでしょうか？
もちろんサービスをリリースする前には様々なテストを実装してると思います。これを専門的に行う人々をQAエンジニアと様な名前で読んでますし、彼らの存在は単純にリリース前のテストを行う人々ていう意味からはじめ、様々な役割を果たしてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/233dab26-6e9d-8e14-9b0c-0c963fc3f107.png)
この図は一番簡単に書いた、サービスがリリースされる前までのプロセスになります。省略された部分もあると思いますが、大きく見るとほとんどこのパターンで進めてると思います。
上記で話した、QAエンジニアが活躍するところは③の周りになります。
この記事で話したいのは図の①と②になります。
①はGolangCiの部分です、　②はCodeClimate部分になります。
高いレベルのテストに入る前にコードレベルでの品質管理を厳しく行うことで、QAエンジニアの負担を減らせるし（簡単な動作バグや修正のデグレはまじで疲れますね。）、自分たちのコード品質に自身を持つことができ、コードを管理する基準を作ることでチーム員たちが共通の認識を持つことができます。

# golangci について
Goには`built-in`で提供してるPackageでは[fmt](https://golang.org/pkg/fmt/)を含めていくつか有用なLintを提供してます。
このようなツールは単純にコーディングミスを探すことから、コードのインデントを整理したり(fmt)、不要なImportを消してくれたり([goimport](https://godoc.org/golang.org/x/tools/cmd/goimports))、変数や・関数を定義したけど使ってないことを教えてくれたりして、よりコードをきれいに管理できるように手伝ってくれます。
その中に、Golangを使う場合一番Publicなものがgolangciていうツールであります。　このツールは簡単なCiからはじめ、いろんなLinterを組み合わせて利用することで、プロジェクトをより簡単に管理してくれます。
[提供してくれるLinter](https://golangci-lint.run/usage/linters/)もこんなに多いので、どんな役割をするのか確認しながら、本人のPJで使えそうなものを投入しましょう。

# code climateにていて
code climateは私達が、基本的にCLIベースでチェックしてたことをウェブ画面で、数値化されてより理解しやすいようにやってくれるし、PJが持ってる潜在的なIssueを事前に対応できるように、表示してくれたりするUI/UXを提供してくれるサービスであります。
独自的な計算アルゴリズムを利用して、PJのメンテナンス数値や、該当Issuesを対応することにかかる予想時間を表示してくれたりします。
更にGithubとの連携を利用して簡単にCodeClimateのIssueをGithubのIssuesにしてわかりやすくしたり、PRにコメントを作成してくれるので、いろんなワークフローが作れます。

# ざっくり見る全体図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/e2b6140c-bce8-89ef-247b-0ab36ac9e086.png)

#### 事前準備
- CodeClimateアカウントを持ってるのか
- Code Climateと、Githubのレポジトリを連動させる。

#### 作業の流れ
1. Localで作業する
2. GitにPushする
3. Github Actionsが走って`golangci-lint` チェック、`coverage report`を作成
4. 作成したレポートをCode Climateに転送
5. Code ClimateでPJの状態を確認


## カスタム設定について
### golangci 
[公式ドキュメント](https://golangci-lint.run/usage/configuration/#config-file)を見ると、PJのRootに下記４パターンのフォーマットに設定ファイルを準備することで、ルールをカスタマイズするのが可能になります。 

- golangci.yml
- golangci.yaml
- golangci.toml
- golangci.json

```yaml
## golangci.yml
## code climate 側でチェックしてることと一番関係高い部分をカスタムで入れてます。
linters-settings:
  nestif:
    # minimal complexity of if statements to report, 5 by default
    min-complexity: 4
  gocognit:
    # minimal code complexity to report, 30 by default (but we recommend 10-20)
    min-complexity: 20
  gofmt:
    # simplify code: gofmt with `-s` option, true by default
    simplify: true
  nakedret:
    # make an issue if func has more lines of code than this setting and it has naked returns; default is 30
    max-func-lines: 100

issues:
  # Excluding configuration per-path, per-linter, per-text and per-source
  # テストコードの場合除外する。
  exclude-rules:
    - path: _test\.go
      linters:
        - errcheck
        - gocognit
        - nestif
        - gofmt
linters:
  # 利用するLinter
  enable:
    - nestif
    - gocognit
    - gofmt
    - nakedret
  fast: false

```

そして、[このページ](https://golangci-lint.run/usage/linters/)をみると、普段提供してるDefaultのLinter以外に色んなLinterを提供してるので、この設定を追加して利用できます。

### code climate 
同じく[公式ドキュメント](https://docs.codeclimate.com/docs/advanced-configuration)を見ると会のフォーマットでチェック内容をカスタマイズするのができます。
このファイルがない場合、Defaultの値でチェックを行うし、簡単にチェックのOn/Offぐらいなら、設定ファイルを準備するより、ウェブページを利用するのがより簡単にできる。

- .codeclimate.yml
- .codeclimate.json

[このページ](https://docs.codeclimate.com/docs/advanced-configuration#default-checks)を見ると、各項目ごとにどんな内容をチェックするのかが、確認でき・設定するのができます。

```yaml
version: "2"         # required to adjust maintainability checks
checks:
  argument-count:    # parameter count
    config:
      threshold: 4
  complex-logic:
    config:
      threshold: 15
  file-lines:
    config:
      threshold: 500
  method-complexity:
    config:
      threshold: 15
  method-count:
    config:
      threshold: 20
  method-lines:
    config:
      threshold: 50
  nested-control-flow:
    config:
      threshold: 4
  return-statements:
    config:
      threshold: 4
  similar-code:
    config:
      threshold: # language-specific defaults. an override will affect all languages.
  identical-code:
    config:
      threshold: # language-specific defaults. an override will affect all languages.
# 管理画面で除外するパターン
exclude_patterns:
  - "config/"
  - "db/"
  - "dist/"
  - "features/"
  - "**/node_modules/"
  - "script/"
  - "**/spec/"
  - "**/test/"
  - "**/tests/"
  - "**/vendor/"
  - "**/*.d.ts"
  - "**/*_mock.go"
```

ちょっと気になる項目がありますよね？　おそらく下記２項目かと思います。　

```yaml
complex-logic:      ## ロジックの複雑さ
    config:
      threshold: 4
method-complexity:  ## メソッドの複雑さ
  config:
    threshold: 5
```

他の項目はなんとなくわかるが、この項目だけはなんか気になりますね。
どんな内容をチェックするのか…
公式ドキュメントを見ると、CodeClimate側では２つの軸で、複雑さを計算してるといいます。
- [Cognitive Complexity](https://docs.codeclimate.com/docs/cognitive-complexity)
- [Cyclomatic Complexity](https://docs.codeclimate.com/docs/cyclomatic-complexity)

本当にざっくり説明すると　Cognitive Complexityは「人間が理解するのに問題ないのか」、をチェックすることです。　そして、Cyclomatic Complexityは「マシンが理解するのに問題ないのか」をチェックする方法です。　
もし、より深く理解したいのであれば、[こちら](https://www.sonarsource.com/docs/CognitiveComplexity.pdf)を読んでみてください。
そして、Qiitaでは[このページ](https://qiita.com/suzuki_sh/items/824c36b8d53dd2f1efcb)でかならい優しく説明してくれてます。　おすすめです。

そして下記の２項目もまります。

```yaml
similar-code:   ## コードのかぶり
  config:
    threshold: # language-specific defaults. an override will affect all languages.
identical-code: ## 処理のかぶり
  config:
    threshold: # language-specific defaults. an override will affect all languages.
```

それぞれかぶりをチェックする項目であります。　基本的に各言語の設定に頼ってます。
簡単に説明すると、

```go
func test1(a, b) int {
    a = a + 1
    return a + b
}

func test2(a, b) int {
    a = a * 3
    return a + b
}
```
ほんとにざっくり書きましたが、話してる内容は似てると思います。
`similar`は、コード自体の重複ですね。　コードを書く時になんとなく名前だけ微妙に異なって、ほぼ同じぐらいのコードがあります。　このような場合検知され、Issuesになります。
`identical`はやってる処理がほぼ似てる場合になります。
`Aを取得して、Bを処理`、　`Cを取得して、Bを処理` のように名前だけ微妙に異なって、処理はほぼ同じ場合、このようなものがあるから、Refactorしたほうがいいよ的な案内を出してくれるものです。
基準が言語に依存されてるので、自分もよくわかりません…　もし、関連情報があれば教えていただくと助かります。

## まとめ、
この作業を行いながら、コード品質管理について色々勉強する機械になりました。
単純に「テストコードを書いて、カバレッジを達成する」的なエンジニアとして活動してきましたが、このプロセスと投入しながら自ら品質てなんで管理しなきゃいけないのかとかあれこれ考えるチャンスになりました。
そして、このような指標を設定して、チーム員たちの目標を設定して、より高いチームワークを持つことができる機械になると思います。
ぜひ、みなさんもコード品質について深く考えて皆さんのPJにも投入して見てください。
まだ内容も足りないし、きれいじゃない記事ですが、読んで頂いてありがとうございます。