この記事はフリューAdvent Calendar 2022の5日目の記事となります。
はじめに
こんにちは。フリューでサーバサイド開発をしています、kitajimaです。
ここでは、弊チームで行っている"改善会"という取り組みの中で試してみたツール及びその所感を述べていきます。
なお、"改善会"の詳細は弊社テックブログにも執筆しておりますので、こちらもぜひご覧ください。
弊チームが携わるプロダクトの中で、主にビルドツールとして利用しているのがGradleです。
今回、プロダクトコードではなくGradleの依存関係をターゲットにしたLinter、Gradle Lint Pluginを試してみたので紹介させていただきます。
Gradle Lint Plugin とは
Netflixが提供するGradleのプラグインです。
Gradleの設定ファイルであるbuild.gradle
について、静的解析を行ってくれるLinterです。
ルール
多くのルールが提供されており、チェックをかけたいルールを複数設定できます。
- Unused Dependency(不要な依存関係を抽出してくれる)
- Archaic Wrapper(Gradleタスクの古い記法を検出してくれる)
- Duplicate Classes(同じライブラリの依存関係が競合している状態を検出してくれる)
- etc...
利用してみる
検証に使ったプロジェクト
- Gradleプロジェクト
- Spring Bootアプリケーション
- Java 8
チェック
まず、既存のbuild.gradle
に、以下のようにプラグインを導入します。
// プラグインを適用
plugins {
id 'nebula.lint' version '17.7.1' // 執筆時点で最新を使用
}
// チェックしたいルールを設定 複数設定できる
gradleLint.rules = ['unused-dependency', 'duplicate-dependency-class']
// (以下略)
そして、コマンドを叩きます。
$ ./gradlew lintGradle
こんな感じで結果が出ます。
warning unused-dependency this dependency is unused and can be removed
build.gradle:150
implementation("zzzzzz:zzzzzz:1.2.3")
warning duplicate-dependency-class xxxxxxx:xxxxxxx:1.2.3 in configuration ':implementation' has 16 classes duplicated by yyyyyy:yyyyyy:2.3.4 (use --info for detailed class list) (no auto-fix available). See https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule for more details
✖ 2 problems (0 errors, 2 warnings)
To apply fixes automatically, run fixGradleLint, review, and commit the changes.
既存のbuild.gradle
で不要な依存関係、同じライブラリの依存関係が競合している状態が見つかりました。
長年開発しているうちに、いつの間にか不要になっていた記述があったようです。
自動修正
warningの種類によっては、以下のコマンドで自動で問題点を修正してくれます。
$ ./gradlew fixGradleLint
修正してくれた箇所については緑文字でfixed
と出力してくれます。
fixed unused-dependency this dependency is unused and can be removed
build.gradle:150
implementation("zzzzzz:zzzzzz:1.2.3")
build.gradleから対象の依存関係が消えていることが確認できます。
dependencies {
- implementation("zzzzzz:zzzzzz:1.2.3")
}
一方で、黄色文字でneeds fixing
と出て自動修正してくれないものもありました。
needs fixing unused-dependency this dependency should be moved to the runtimeOnly configuration
build.gradle:193
implementation("aaaaaa:aaaaaa:3.4.5")
needs fixing duplicate-dependency-class xxxxxxx:xxxxxxx:1.2.3 in configuration ':implementation' has 16 classes duplicated by yyyyyy:yyyyyy:2.3.4 (use --info for detailed class list) (no auto-fix available). See https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule for more details
前者のunused-dependency
は、コンパイル時は不要である依存関係のため依存関係構成をimplementation
からruntimeOnly
にすべきだというチェックであり、手動で変更が必要そうです。
後者のduplicate-dependency-class
は同じライブラリの依存関係が競合している状態です。
クラスパス解決の順序がローカル環境とデプロイ環境で異なる場合などに、開発者によって追跡が困難な問題が発生する場合があるため修正を促しているようです。
Gradleはデフォルトでは依存関係の競合時に新しいバージョンを使用するため、今回は特に修正は行いませんでした。
推移依存関係の深さが浅いものを優先するMavenからGradleに移行するケースでは、依存関係の競合の解決方法が異なるため注意が必要そうです。
課題点
starter系の依存関係をエラーとして扱う
追加するだけで様々なライブラリを利用することができるstarter系の依存関係について、Gradle Lint Pluginは「その中の一部のサブセットしか使っていない」と判定し、unused
エラーを返します。
- アプリケーションの容量が無駄に大きくなること
- アプリケーション自体がライブラリの場合は不要な依存関係の増大により利用者側での競合問題に発展しうること
が理由として挙げられています。
https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Unused-Dependency-Rule より
弊チームのプロダクトでは、Springアプリケーションにおける"org.springframework.boot:spring-boot-starter"
などがこれに当てはまりました。
一方で、Springは本番環境であってもstarter系の依存関係は問題なく使用されることを前提としているため、Linter側で抑制すべきだ
という議論がstackoverflowでもありましたが、特に結論は出ていなさそうです。
コード以外に利用される依存関係をunusedとして扱う
プロダクトには、コードに含まれていなくとも設定ファイルで必要になる依存関係がありました。
こちらをunused
と判定し、./gradlew fixGradleLint
で削除してしまうためアプリケーションがビルドエラー状態になってしまいました。
こちらはチェックの対象とするディレクトリやファイル種別を制限できないか、もう少しドキュメントを読んでみます。
最後に
挙げたような課題点を解決してGradle Lint Pluginが上手く導入できれば、人の目によるレビューの手間を減らすことができ、開発効率向上に繋がります。
課題点や他のツールも導入することについて、今後も"改善会"にて話を進めていきたいと思います。
お読みいただきありがとうございました。