diKTatでKotlinコードレビューを自動化ルーティンに
プルリクエストのコメントの約3分の1がフォーマットの議論だった経験はありませんか?誰かが否定形のbooleanをisNoErrorのように残していたり、クラスのメソッド順序がバラバラだったり、浮動小数点数を==演算子で比較していたりと、コードはコンパイルが通ってテストもパスするものの、6ヶ月後にそのコードベースを読むと本当に的痛苦を伴うようになります。
通常、Kotlinではktlintとdetektのコンボを使用します。前者はインデントやスペースをチェックし、後者は明らかなコードスメルを検出します。しかし、アーキテクチャスタイルや規約に関してはその間にグレーゾーンがあり、チームは独自のルールを書いたり、手動でコメントを書いたりして時間を無駄にします。SaveOurToolチームのdiKTatリポジトリは、まさにこの問題を解決します。
diKTatとは
このプロジェクトは、Kotlin用の厳格なコード規約ルールのセットです。技術的には、diKTatはktlintの上に構築されており、ファイルのASTを解析します。リポジトリには、命名、KDocコメント、クラス構造、関数、型和変数の操作に分かれた詳細なガイドラインが含まれています。
このツールには100以上のチェックが含まれており、その多くは他の静的アナライザーにはそもそも存在しません。主な利点は、diKTatはコンソールに警告を出すだけでなく、見つけた違反をその場で自動的に修正できることです。
コードを救う一目惚れではないチェック
ほとんどのリントツールはフォーマットに注目します。diKTatはもっと深く掘り下げ、意味的な奇妙さを検出します。
命名とロジックのクリーンさ
diKTatには二重否定の変数名を禁止する機能が組み込まれています。フラグをval isNotValid = falseと宣言すると、リンターは肯定形同等物にリネームすることを要求します。!isNotValidのような構文は読むときに頭を痛くするので、このルールはみんなの神経を節約します。
否定を含む関数呼び出しもチェックします。!list.isEmpty()の代わりに、ツールはしつこくlist.isNotEmpty()を書くことを提案します。
クラスメンバーの順序
大きなKotlinファイルにおける一般的な問題は、フィールド、関数、オブジェクトの乱雑さです。diKTatは構造を厳密に制御します:
- コンパイル時定数
- 通常プロパティ
- late-initプロパティ
- initブロック(ツールは明示的な必要性なしに複数の
initブロックを作成することを禁止します) - コンストラクター
- public、internal、protected、privateメソッド
- Companion object
誰かがpublic APIの前にprivateヘルパーを置くと、CIビルドが失敗します。
型和計算の安全性
このツールは型FloatとDoubleの直接比較を==経由では禁止しています。浮動小数点数のバイナリ表現の特性により、このような比較は検出困難なバグにつながることが多いです。diKTatは、abs(a - b) > EPS経由のデルタチェックを使用するか、BigDecimalに切り替えすることを強制します。
別の便利なチェック冗長なキャストを追跡します。Kotlinが条件内で既にSmart Castを実行している場合、as Typeを呼び出すことは不必要なノイズとしてマークされます。
// Было
if (x is String) {
print((x as String).length)
}
// Стало после автофикса
if (x is String) {
print(x.length)
}
実行と設定方法
diKTatはターミナルから実行したり、GradleやMavenビルドに統合したり、Spotlessアグリゲーター経由で接続したりできます。
Gradleへの追加
Kotlin DSLを使用するGradleプロジェクトでは、数行でプラグインを接続できます:
plugins {
id("com.saveourtool.diktat") version "2.0.0"
}
diktat {
inputs {
include("src/**/*.kt")
exclude("src/test/kotlin/excluded/**")
}
reporters {
plain()
html {
output = file("build/reports/diktat.html")
}
}
}
チェックはコマンド./gradlew diktatCheckで実行され、アナライザーが到達できるすべての自動修正は./gradlew diktatFixで行います。
ルールの微調整
設定は標準のYAMLファイルdiktat-analysis.ymlに配置されます。各ルールは個別に有効または無効にでき、多くのルールには特定のパラメータがあります:
name: HEADER_MISSING_OR_WRONG_COPYRIGHT
enabled: true
configuration:
isCopyrightMandatory: true
copyrightText: Copyright (c) MyTeam, 2024. All rights reserved.
name: HEADER_NOT_BEFORE_PACKAGE
enabled: true
ignoreAnnotated: [Generated, Controller]
ローカルで特定のチェックを抑制する必要がある場合は、標準の注釈@Suppress("FUNCTION_NAME_INCORRECT_CASE")または一般的な@Suppress("diktat")がコード内で直接動作します。
Baselineによる段階的な導入
5万行のコードを持つ古いプロジェクトに準備なしで厳格なリントを有効にすることはできません。開発者は数千の警告に溺れます。
これ 위해、diKTatにはベースラインモードがあります。最初の実行で、ユーティリティはプロジェクト内のすべての既存の問題を含むXMLファイルを生成します:
./diktat --baseline=diktat-baseline.xml "src/**/*.kt"
ベースラインファイルはリポジトリにコミットされます。その後、リンターは古いコードについて警告を出しなくなり、新しいコミットで新しい違反を導入した場合のみビルドをブロックします。
GitHub Actions統合

このツールはSARIF形式でレポートを出力できます。GitHub Actionsと組み合わせると、スタイルエラーと警告が正確な行参照とともにプルリクエストインターフェースで直接ハイライト表示されます。コメント用のサードパーティ製ボットを設定する必要はありません。
name: Upload SARIF report
uses: github/codeql-action/upload-sarif@v1
if: always()
with:
sarif_file: build/reports/diktat/diktat.sarif
試す価値はあるか
diKTatは非常に妥協がありません。そのガイドラインは明示的なインポート順序を要求し、関数の長さを30行に制限し、publicメソッドのKDocドキュメントの存在を制御し、不必要なvarを禁止します。
2人だけのペットプロジェクトでは、このような制限は過剰に感じるでしょう。しかし、分散チームがサービス開発していたり、オープンソースライブラリを開発していたりする場合は、diKTatはスタイルの同期に関する頭痛を取り払い、コードレビュー時間をホワイトスペースではなくアーキテクチャの議論に解放します。最も簡単な開始方法は、シングルモジュールチェックモードでGradleプラグインを追加し、ベースラインを生成することです。
関連プロジェクト