LIFULL Creators Blog

「株式会社LIFULL(ライフル)」の社員によるブログです。

コード品質管理について

こんにちは、
アプリケーションエンジニアとして働いてます。キムと申します。
今日はこの最近経験したことの中で、アプリケーションを開発する途中や、リリース後にコードベースを管理する時重要なことの一つ「品質管理」について経験したことを共有したくて記事を準備しました。

背景

去年は新しく配属されたPJでアプリケーションの基盤から作るチャンスを頂きました。
当時、個人的にLintを投入したい思いがあったので、Go言語で最もよく使われていたgolangciというツールの基本的な部分を使えるように設定を行いました。

個人的に Lintを入れたかった理由は、自分の経験の中でコーディングルールが甘い状態が長く続けると、古いコードを読んだり、複数人のメンバーが同じ作業を行う、又はコードレビューをする等、他人のコードを読む時、人によってバラバラの書き方が混在し、場合によっては基本的なタイポイシューがあったりする指摘でレビューが長くなったりする不便がありました。
そこで、Lintを投入してたチームで経験した、Lintが存在する時のメリットを今回参加してるチームメンバーたちにも経験してもらいたかった思いでした。

イメージ1
すごく極端てきなイメージですが、十分にありえるシチュエーションです。

PJはどんどん進んで、最初より多い人数が入っていただきました。みんなどんどん新しい機能を開発し続けましたが、Lintがあったので、コードベースは基本的なルールを守り状態で管理できたと思います。

この時、部内では新しくCode Climateていうツールを利用し、コードのクオリティチェックを行い、より高いクオリティを目指しましょうていう話が出始め、私達のチームもこのツールを投入することを決めました。

これを適用しながら感じたことや、Golangiciと連携してもっと有効活用できる方法やカスタムルール作成方法などを共有したいと思います。

コード品質について

f:id:LIFULL-SeongjooKIM:20210319111052p:plain
アプリケーションは機能が増えるたびコードベースは大きくなります。
レポジトリに対して、コード品質管理はなぜ必要だと思いますか?
サービスがリリースされた後、時間の経過とともに機能はどんどん増えるし、コードベースはどんどん複雑になっていきます。この時コードベースの管理状態をひと目に判断する方法として、コード品質管理を行っていると思います。

アプリケーションは他の商品とは異なって実態が目に見えない商品であり、ということで人の目には見えないところで問題が起きる可能性が存在します。
目に見えるエラーは原因把握も簡単にできるし対応も簡単ですが、目に見えないところから発生したエラーは原因を把握することも大変複雑で、対応するにはより高いコストがかかる可能性も高いです。

この問題は、チーム単位で作業するときにより頻繁に発生します。 同じ機能を作るとしても人によってコードの書き方や、考え方はそれぞれです。そのためコードレビューを行ったり、コードを作成する前にダイアグラムやシークエンス図などを準備して設計レビューをしたりするプロセスが発生してきました。

f:id:LIFULL-SeongjooKIM:20210319120436p:plain
Active DiagramやSequence Diagramなどでお互い認識合わせや、効率的な処理を探してきました。

このプロセスの中、どうすれば少しでもレビューを簡単にできるのか、こういった機能を十分に活用して投入することで、コードはより統一感を持つことになり、時間が過ぎてもある程度ルールで守られ、読む人に安定感を渡します。

Lintチェックでは簡単な英語スペルチェックから、メソッド名の作成方法、変数の書き方をCamelCaseかsnake_caseにするかなどのチェック、1ファイルあたりの行数制限など様々なチェックを行っています。レポジトリに対して、コード品質管理はなぜ必要だと思いますか? サービスがリリースされた後、時間の経過とともに機能はどんどん増えるし、コードベースはどんどん複雑になっていきます。この時コードベースの管理状態をひと目に判断する方法として、コード品質管理を行っていると思います。

Lintチェックでは簡単な英語スペルチェックから、メソッド名の作成方法、変数の書き方をCamelCaseかsnake_caseにするかなどのチェック、1ファイルあたりの行数制限など様々なチェックを行っています。
簡単に言うと人によっていろんな差があります。

## camel case
CamelCase := ""

## snake case
snake_case := ""

if() {
// 処理
}

if()
{
// 処理
}

「こんなことまで気にするの?」と言われるかもしれませんが、こういった細かいところから問題は大きくなっていきます。

今回紹介しようとするレポジトリ管理サービスも同じです。関連サービスには独自、又は有名アルゴリズムによってコードのメンテンナンス状態や、テストカバレッジ状況を見やすく可視化してデータを提供することで該当サービスがどんな状態で管理されてるのかを一目に把握できるように提供してくれます。
上記でも話したように、アプリケーションは実態が目に見えない商品なので、このように可視化してくれるのはすごく役に立ちます。利用者には、該当アプリの信頼性を、関係者には今アプリにはどんな暫定的な問題があり、どんな改善が必要なのかの判断の軸になることもあります。

f:id:LIFULL-SeongjooKIM:20210319123235p:plain
このように、ウェブ上でレポジトリの状態をひと目に見れます。

こういった機能を十分活用し、導入することで、コードはより統一感を持つことができ、時間が過ぎてもある程度ルールに守られ、後々読む人にも安定感を渡します。 もちろん、色々設定が必要とか、今すぐ始まるには面倒なことが多い等、今までのやり方と違うことで大変かもしれませんが、将来を考えたら今時間を使って投入することが確実にメリットがあると思っています。

準備

  • Code Climateの利用準備
  • Repository と、Code Climateへの連動(ここではGithub を利用します。)
  • レポートをアップロードするための手段準備(ここではGithuib Actions を利用します。)

golangci

公式ドキュメント Golangを利用して開発してるなら、最も注目するべきツールです。 Go言語が提供してる基本Lintはもちろん、世の中に名前が知られてる各種3rdパーティーモジュールも追加で設定を行うことで利用できる環境を提供してくれます。
Local環境はもちろん、Github ActionsなどCI/CDを利用する場合、自動チェックを行うことができます。 また、下で話しする Code Climateとも似てるチェック項目が準備されて、これを利用することでCode Climate側でチェックされる前に先に対応することも可能です。

チェック項目のカスタマイズについて

PJのRootに設定ファイルを準備します。
Code-Climateのチェックと同じチェックがあるので、先に行うとCodeClimate側で指摘されないので、安心です。 nestifや、gocognit の場合コードの複雑さを表す部分です。
CodeClimate側でも言語によって自動でチェックしているので、内容をある程度把握しておいたほうが良いと思います。

## golangci.yml
## code-climate側と同じチェック
linters-settings:
  nestif:
    # 
    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
  # 該当チェックでは、*_test.goファイルは除外する。意味
  exclude-rules:
    - path: _test\.go
      linters:
        - errcheck
        - gocognit
        - nestif
        - gofmt
## 設定使うLinterを表示
linters:
  enable:
    - nestif
    - gocognit
    - gofmt
    - nakedret
  fast: false

f:id:LIFULL-SeongjooKIM:20210319125130p:plain
このように、どこで、どんな問題があるのかを教えてくれます。

Code Climate

公式ドキュメント
Github 以外にも様々なレポジトリ管理サービス(gitlab,gitbucket等)と連動することで各種項目のチェックが可能し、ひと目に見れるUI/UXを提供してます。

  • メンテナンススコアー
  • テストカバレッジスコアー
  • コードスメール(設定値を超えてるもの)
  • コード重複(似てるコードが存在してる) などの項目を簡単に確認できて、該当項目を連動されてるレポジトリ上にイシュー化されることもでき、Pull Requestを作成する時コードレビューにも使える機能もあります。 レポジトリと連動されてるときにウェブページ以外に、コードベースにも設定ファイルを追加して、より細かい設定が可能になる。

設定のカスタマイズについて

CodeClimateの場合、ウェブページでの操作 である程度コントロールができますが、コードで設定することも可能です。
golangciと同じくPJのRootに、設定ファイルを配置することで設定可能になります。

※一緒に使えるPluginも多数あるので自分た ちのレポジトリで必要なものを選択して入れましょう。

version: "2"   # required to adjust maintainability checks
checks:
  # パラメータの数
  argument-count:
    config:
      threshold: 4
  # ロジックの複雑さ
  complex-logic:
    config:
      threshold: 15
  # 1ファイルの最大行数
  file-lines:
    config:
      threshold: 500
  # メソッドの複雑さ
  method-complexity:
    config:
      threshold: 15
  # 1ファイルあたりメソッド数
  method-count:
    config:
      threshold: 20
  # 1メソッドあたりの行数
  method-lines:
    config:
      threshold: 50
  # nest制限数
  nested-control-flow:
    config:
      threshold: 4
  # 1メソッドあたりRetrunの制限
  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:
  - 除外したいファイルパターン

CodeClimateのトップ画面を見ると

f:id:LIFULL-SeongjooKIM:20210319125720p:plain
トップページ、各種スコアーが一目で見れます。
このようにサマリーが見えます。
詳細設定を利用して連動されてるコードレポジトリ(Github,Gitlab,Gitbucketなど)にコメントをつけることの可能です。(レビュー機能です。)

全体の流れ

テスト結果レポート転送についてこちらのようにテスト完了した結果をCodeClimateに転送して、現Repositoryの状態を更新します。

f:id:LIFULL-SeongjooKIM:20210205155137p:plain
全体図

上記案内した各設定が全部準備できたら、このような流れの運用が可能になります。 Github Actionsの利用方法によって、golangci-lintや、UNITテストのエラーをチャットワークや、Slackなどに送ることで、自分がPUSHしたコードがどんな問題があるのかを早めに把握でき、必要最小限の統一感を持つコードとして保存できます。

そして、最後にテスト結果をCodeClimate側に送ることでレポジトリの状態を管理することも可能になります。

自分が作成したこの例は、自分が配属されてるチームで使ってる方法の一つであり、これを見てより良い案があれば、チャレンジしてみてください。

最後に

いかがでしょうか?
使える機能を考えると以外に簡単に設定できますね?
項目の設定はチームメンバーと一緒にどれぐらいの数字を設定するのかをディスカッションすることでみんなと、認識合わせもできるし、コード作成時Lintチェックで怒られながらどんどん設定したコーディングルールが身につけられて行けると思います。
もちろん設定した数値は、絶対的なものではないので後で修正しながらチームの状態に合わせて行くことも可能です。
私も今まで、簡単なLintチェックなどは自動化した経験はありますが、ここまで全部自動化してコードベースを管理するのは初めてだったのでかなりいい経験だと思っています。
余談ですが、badgeをREADMEに入れることで、レポジトリページに接続したらレポジトリのメンテナンススコアや、テストカバレッジスコアがすぐ目に見えることで、より具体的なチームの目標や、モチベーションにもつながると思います。

f:id:LIFULL-SeongjooKIM:20210319131439p:plain
このようなBadgeをREADMEに配置することで、簡単に確認できます。

今までコード品質管理などについて特に興味がなかったとしても、この記事がきっかけでご自分のレポジトリにも品質管理ツールと導入を検討していただければいいかなと思います。
長い記事読んでいただきありがとうございます。