こんにちは。都志(@louvre2489)です。
突然ですが、みなさんの開発/保守しているシステムのソースコードは読みやすいですか?それとも読みにくいですか?
自信を持って「読みやすいです!」と答えたいところですが、「う〜ん・・・」となってしまう方は多いのではないでしょうか?
私たちも同様の悩みを抱えています。ソースコードはどれだけ責務分割を意識して丁寧に書いても、長年の開発/保守の中で徐々に複雑化し、読みにくくなっていってしまうと思います。
そのような悩みを抱える中で、Chatworkでは全社的にSonarCloudを導入することにしました。まだ導入したばかりなので手探りで運用している点もありますが、本ブログではChatworkでのSonarCloud運用事例をご紹介したいと思います。
「SonarCloud(または後述するSonarQube)」は日本語の情報も少なく、決して馴染みのあるツールではないと思いますので、本ブログを通してSonarCloudのメリットを知っていただいて導入検討のきっかけになれば、と思います。
SonarCloudとは
SonarCloudとは、「コード品質検査」のためのツールです。
「SonarQube」という名前で提供されているツールもありますが、SonarCloudはSonarQubeのSaaS版です。SonarCloud/SonarQubeで利用できる機能は概ね同じとなっています。
コード品質とは
SonarCloudのヘルプページには以下のように記載されています。
コードの保守性、信頼性、セキュリティを継続的に保証します
プロダクトとしての機能バグは存在しなくても以下のような問題が潜んでいる可能性があります。
- コードをメンテナンスしづらい(=保守性)
- バグを引き起こす可能性がある(=信頼性)
- セキュリティ問題を引き起こす可能性がある
コード品質に対してSonarCloudでできること 〜違反コードの検出〜
SonarCloudはコード品質を低下させるコードを検知してくれます。
例えば、Scalaのルールには以下のようなルールが用意されています。
All branches in a conditional structure should not have exactly the same implementation
これは以下のようなコードを抑止するためのものです。
if (i == 0) { doHoge } else { doHoge // i == 0 の判定結果に依らず doHogeを実行している }
このコードがelse
の時に実行したかったのは本当にdoHoge
なのでしょうか?コードをコピーして持ってきた時にコードを修正するのを忘れたのかもしれません。
もしそうであれば、このコードはバグを抱えています。このようなコードを、「バグを引き起こす可能性があるコード」として検出することができます。これによって「コード品質」を低下させるコードの混入を検出することができます。
このようなルールが言語に応じて用意されています。(言語によって用意されているルールの数も異なります)
コード品質に対してSonarCloudでできること 〜品質の見える化〜
違反コードの検出は、GitHubへのプッシュ時に自動的に実行するように設定することができます。
コードをスキャンすることで以下の観点での検査ができるようになります。
- 保守性、信頼性、セキュリティ品質の検査
- コード重複検査
- カバレッジ検査
- ...等々
ルール違反の検査だけではなく、他にも多数の検査項目が用意されています。
そして、その検査結果を以下のように数値によって可視化することができます。
下の画像では青色のエリアがコード全体、黄色のエリアが直近のコミットによる増分を示していて、以下のような指摘をされていることがわかります。
- 信頼性の指摘:0件
- セキュリティの指摘:0件
- 保守性の指摘:69件
上記画像の状態について、『保守性の指摘が69件発生しているのは問題ではないのか?』という疑問が生じるかもしれません。
いわゆるLintツール(Scalaであればscalafix、TypeScriptであればtypescript-eslintなど)のエラーの場合はルール違反が検出されるとビルドが不可(つまり、指摘が存在する=是正すべき問題)となるので対処が必須となります。
しかし、SonarCloudの場合はSonarCloudの検査結果に対してそれを是正するか否かはエンジニアに委ねられます。(「検出レベルが全てWARN」というとわかりやすいかもしれません。)
開発チームと品質管理チームで協力して開発を行っている場合、品質管理チームからのフィードバックに対して開発チームは「是正する」または「理由を示してパスする(対処しない)」のアクションを取ることができますが、SonarCloudは品質管理チームの役割を果たしてくれます。
開発チーム内で協議し、『コードは妥当なので対処不要』という判断を下したのであれば無理に対処する必要はありません。
「対処しない」という旨をSonarCloudに記録すれば指摘件数からも除外してくれます。
上記画面以外にもコード品質を数値化したり図示してくれる画面が多数存在します。SonarCloudの機能やルールの詳細については以下をご確認ください。
SonarCloudの運用方法
開発初期から導入できる場合
開発初期からSonarCloudを導入することができれば、SonarCloudの指摘が発生した場合はその都度対応するか否かを判断しながら実装を進めていくことで開発初期から安定したコード品質をキープすることができます。
GitHubと連携させることでスキャンの結果をP-R画面でP-Rの都度確認することができるので、短いフィードバックサイクルで品質を低下させるコードを効率良く除去することができます。 ちなみに、SonarCloudのデフォルトの設定では信頼性・セキュリティに関する違反は「発生した時点でNG」、保守性に関する違反は「混入率が一定量を超えたらNG」という設定になっています。
上記の画面では保守性に対して1件の指摘がありますが、実装者はこの指摘内容を確認して対応の是非を検討します。
チームの見解として毎回「処置しない」になる指摘項目があるのであれば、ルールを見直してチェックルールから除外することも検討します。
デフォルトではONになっていない検査項目も多数存在するので、チームのポリシーに合ったルールになるようにカスタマイズしてより良い検査項目になることを目指します。
隔週の振り返りのタイミングでActivityを確認して、急激に状況が悪化していないかを確認しているチームもあります。
上記はActivityのグラフです。
大きく数値が減少しているのは、実装方針が曖昧な部分をラフに書いて方針固めをした上でリファクタリングをおこなってコード品質が改善している様子です。
一方で、グラフが上昇してしまっている箇所もあります。
新規開発プロダクトなのでまだまだコードの母数も少なく、累積の指摘数も少ないので、指摘件数多めなコミットを入れてしまうことでグラフが急上昇しています。
これに対しては適切な処置、またはルールの見直しを行うことで運用を改善する必要があると考えています。
開発済のプロダクトに導入した場合
基本的な考え方は新規開発プロダクトと同じなのですが、既に作成済のコードに対してコード品質検査をかけると様々な指摘が挙がってきます。
保守性に対する指摘が1,000件近く発生しており、Bugs(=バグを引き起こす可能性がある)も数件存在することがわかりました。
これらの内容を確認した上で、実施していくべきことは以下の2点です。
- 既に混入している指摘について、対応の優先付けをおこなう
- 今後手を加える際は、コード品質を悪化させないようにする
大量の指摘に驚きはしますが全ての指摘が致命的な内容ではないはずなので、内容を確認して急ぐべき対応(バグを引き起こしかねない指摘への対応)とそうでない対応を明らかにする必要があります。
そして、計画的に処置をしていきます。
今回は発生していませんが、セキュリティに関する指摘が見付かった場合は急いで対応していきたいところです。
また、既存の指摘に対して手を打つ一方で、プロダクトに対して手を加える際は新たな指摘を増やさないようにすることで、確実に指摘件数が減少していくようにしていきます。
これらを粛々と継続して、コード品質を改善していきます。 元の指摘件数が多いので傾きは緩やかですが、着実に改善を進められている様子が伺えます。
最初からSonarCloudを導入していれば、混入済の問題に対して検討/処置する手間が発生しにくくなるので、可能な限り開発初期からSonarCloudを導入しておくのがオススメです。
SonarCloudを設定する
それでは最後に設定方法について解説したいと思います。
SonarCloudは導入方法をいくつか提供してくれているので、各現場の事情に最も適した方法でSonarCloudの機能を使用することができます。
入門編
ソースコードをGitHubで管理している場合は、GitHub Appsを利用することでSonarCloudと容易に(ボタンをポチポチしていくだけで)連携することができます。
新規のGitHubリポジトリをSonarCloudと連携させる際はまずGitHub Appsを利用するのがオススメです。
GitHub Appsはとても便利なのですが、取得したい内容やリポジトリの構成によっては利用することができないので注意が必要です。
公式ドキュメントのAutomatic Analysisのページに自動解析(GitHub Appsによる解析)を行う上での前提や制限事項が記載されています。
いくつか例を挙げたいと思います。
実践編 〜モノレポのコード品質を測定したい〜
モノレポとは?
単一のリポジトリに複数のプロジェクトが配置されている状態を指します。
Webアプリケーション、バッチ、モバイルアプリ、、、同一のシステム内で使用はすれど業務的あるいは技術的に異なるプロジェクトが混在している状態をモノレポといいます。
詳細は公式ドキュメントのモノレポ用のページで確認してください。
何が困るの?
GitHub Appsを利用することでSonarCloudと連携する場合、GitHubのリポジトリとSonarCloudのプロジェクトが1:1の関係になります。
SonarCloudで設定できるルールや品質基準はプロジェクトに対して1つなので、1つのリポジトリに複数のプロジェクトが混在してルールや品質基準を1つに定めることができないとSonarCloudの設定を行う上での問題が発生してしまいます。
1つのリポジトリ内に複数言語(ScalaとPHPなど)が混在していることも、適用するルールを1つに定めることができなくなるので問題となります。
1リポジトリ内でプロジェクトごとに複数のチームが動いている場合は、SonarCloudのレポートが1つにまとまることによって自チームの扱っている範囲のコード品質が見えづらくなるような問題も発生します。
どう対処する?
SonarCloudはGitHub Appsだけではなく、各種CIツールを利用して連携させることもできます。
ソースコードをGitHubで管理していない場合はGitHub Appsが使えないので、その場合もCIツールを利用して連携させることとなると思います。
手順は以下のようになります。(以下はCircleCIの場合です。)
1.SonarCloudの管理画面で、手動で解析するように設定すると各種CIツールでの設定方法が表示されるので、それに従って設定(環境変数等)をおこなう
2.プロジェクトのルート直下に sonar-project_X.properties
、sonar-project_Y.properties
のようにスキャンしたい単位のプロジェクトファイルを用意する
各propertiesファイルは以下のような内容になります。
- sonar-project_X.properties
# SonarCloudの組織 sonar.organization=OrganizationName # SonarCloud上でプロジェクトを一意に設定するためのキー sonar.projectKey=XXXXXXXXX # SobarCloudのURL sonar.host.url=https://sonarcloud.io # SonarCloud上に表示するプロジェクト名 sonar.projectName=ProjectName # スキャン対象プロジェクトのベースディレクトリ sonar.projectBaseDir=./target_dir # `sonar.projectBaseDir`で指定したディレクトリ配下のスキャン対象ディレクトリを指定する # 複数指定する場合はカンマ区切り sonar.sources=src1,src2,sec3
3.config.ymlでプロジェクトごとにスキャンを実行する
config.ymlは以下のように内容になります。(jobsのstepsのみを抜粋。)
- config.yml
steps: - run: cp -f ./sonar-project_A.properties ./sonar-project.properties - sonarcloud/scan - run: cp -f ./sonar-project_B.properties ./sonar-project.properties - sonarcloud/scan - run: cp -f ./sonar-project_C.properties ./sonar-project.properties - sonarcloud/scan
これでモノレポ内のプロジェクトに対してスキャンを実行することができるようになります。(上記の場合、SonarCloudには3プロジェクト分のスキャン結果が表示されます。)
実践編 〜カバレッジを取得したい〜
なぜカバレッジが取れないのか?
公式ドキュメントのAutomatic Analysisのページに以下の制限事項が記載されています。
Code coverage information is not supported.
自動解析ではコードカバレッジはサポートされていないと読み取れます。
実際に自動解析を行ってみてもカバレッジは0%となってしまいます。
どう対処する?
自動解析ができないということなので、モノレポ時と同様にCIを使います。
注意点としては、SonarCloud自身はカバレッジ判断に必要な情報を自力で生成することができないので、カバレッジ情報をSonarCloudに連携するためにはスキャン実施前にカバレッジ取得に必要な情報を作成しておく必要があることです。
Scalaのプロジェクト(カバレッジ取得にはsbt-scoverageを使用)を例にすると、config.ymlは以下のように内容になります。(jobsのstepsのみを抜粋。)
- config.yml
steps: - checkout - run: name: "coverage" command: sbt coverage test coverageReport - sonarcloud/scan
実践編 〜TypeScriptプロジェクトへの導入〜
TypeScriptで導入する場合は少しコツが必要となるかもしれません。
どういう時にコツが必要となるのか?
tsconfig.jsonで以下のようにエンドポイントを指定している場合、SonarCloudのスキャン対象はinclude
で指定された範囲のみとなってしまいます。
以下の場合は、./src/index.js
のみがスキャン対象となります。
- tsconfig.json
{ ... , "include": ["./src/index.js"], ... }
どう対処する?
これを回避するためには、スキャン時にtsconfig.jsonを差し替えて、スキャン用のinclude
設定を行う必要があります。
- sonar-project.properties
# スキャン用のtsconfig.jsonを読み込むようにする sonar.typescript.tsconfigPath=tsconfig.sonar.json # ソース格納ディレクトリを指定する sonar.sources=src
- tsconfig.sonar.json
{ ... , "include": ["src"], ... }
このようにすることでsrc
配下スキャンの対象にすることができるようになります。
開発環境編 〜ローカル環境でコード品質を確認したい〜
スキャンを実行するタイミングがGitHubへのプッシュ時だけだと、プッシュをしてみないとコード品質に問題があるか否かがわかりません。
プッシュして指摘が発生したら、そのために修正を入れて再プッシュする必要があるので手間です。
そこで、SonarLintというプラグインを使用します。
www.sonarlint.org SonarLintを使用することで、お好みの開発環境でローカルスキャンを実行することができます。 以下はIntelliJでSonarLintを使用した際のキャプチャです。 ルールはSonarCloudサーバーから取得して実行するので、サーバーで実行するのと同一のルールでスキャンをすることが可能なので、GitHubにプッシュする前に指摘箇所を把握して対処することが可能になります。
まとめ
SonarCloudを導入することで、P-Rごとにコード品質をチェックしてグラフ化してくれる品質管理担当メンバーを増やすことができます。
SonarCloudを導入したからといって人間によるレビューを省略することができるわけではありませんが、人間の目では見落とす可能性のあるコードの誤りを自動的に検出してくれることは大きなメリットだと思います。
機械的に実施できるレビューはSonarCloudに任せることで、人間は業務観点のレビューに集中することができるようになるので、SonarCloudと人間の力を合わせることによってコード品質を高めていくことができるようになるのではないかと思います。
2週間の無料トライアルもあるようなので、興味のある方は是非導入を検討してみてください。