diKTat zamienia przegląd kodu Kotlin w zautomatyzowaną rutinę
Czy zdarzyło Ci się kiedyś, że jedna trzecia komentarzy do Twojego pull requesta dotyczyła sporów o formatowanie? Ktoś zostawił ujemne boolean jak isNoError, ktoś pomieszał kolejność metod w klasie, a ktoś porównywał liczby zmiennoprzecinkowe używając operatora ==. Technicznie kod się kompiluje i testy przechodzą, ale czytanie takiej bazy kodu sześć miesięcy później staje się fizycznie bolesne.
Zazwyczaj w przypadku Kotlina zespoły stawiają na połączenie ktlint i detekt. Pierwszy pilnuje wcięć i odstępów, drugi wypatruje oczywistych code smells. Ale jest szara strefa między nimi, jeśli chodzi o styl architektoniczny i konwencje, gdzie zespoły albo piszą własne reguły, albo marnują czas na ręczne komentarze. Repozytorium diKTat od zespołu SaveOurTool rozwiązuje dokładnie ten problem.
Czym jest diKTat
Projekt to rygorystyczny zestaw reguł konwencji kodu dla Kotlina. Technicznie diKTat jest zbudowany na bazie ktlint i analizuje AST plików. Repozytorium zawiera obszerne wytyczne podzielone na sekcje: nazewnictwo, komentarze KDoc, struktura klas, funkcje, praca z typami i zmiennymi.
Narzędzie zawiera ponad sto sprawdzeń, z których wiele nie występuje w innych statycznych analizatorach w ogóle. Główną wygodą jest to, że diKTat może nie tylko narzekać do konsoli, ale także automatycznie naprawiać znalezione naruszenia w locie.
Nieoczywiste sprawdzenia, które ratują Twój kod
Większość linterów koncentruje się na formatowaniu. DiKTat kopie głębiej i wyłapuje semantyczne dziwności.
Czystość nazewnictwa i logiki
DiKTat ma wbudowany zakaz podwójnie negatywnych nazw zmiennych. Jeśli zadeklarujesz flagę val isNotValid = false, linter zażąda zmiany jej nazwy na pozytywny odpowiednik. Konstrukcje jak !isNotValid psują mózg podczas czytania, więc ta reguła oszczędza nerwy wszystkim.
Sprawdza również wywołania funkcji z negacją. Zamiast !list.isEmpty(), narzędzie będzie uporczywie sugerować pisanie list.isNotEmpty().
Kolejność członków klasy
Typowym problemem w dużych plikach Kotlina jest bałagan pól, funkcji i obiektów. DiKTat ściśle kontroluje strukturę:
- Stałe czasu kompilacji
- Zwykłe właściwości
- Właściwości z late-init
- Bloki init (a narzędzie zabrania tworzenia wielu bloków
initbez wyraźnej konieczności) - Konstruktory
- Metody publiczne, wewnętrzne, chronione i prywatne
- Companion object
Jeśli ktoś umieści prywatnego helpera przed publicznym API, build CI nie przejdzie.
Bezpieczeństwo typów i obliczeń
Narzędzie zabrania bezpośredniego porównywania typów Float i Double przez ==. Ze względu na specyfikę binarnej reprezentacji liczb zmiennoprzecinkowych, takie porównania często prowadzą do trudnych do wykrycia błędów. DiKTat zmusi Cię do używania sprawdzania delta przez abs(a - b) > EPS lub przejścia na BigDecimal.
Inne przydatne sprawdzenie śledzi zbędne rzutowania. Jeśli Kotlin już wykonał Smart Cast wewnątrz warunku, wywołanie as Type zostanie oznaczone jako niepotrzebny szum.
// Было
if (x is String) {
print((x as String).length)
}
// Стало после автофикса
if (x is String) {
print(x.length)
}
Jak uruchamiać i konfigurować
DiKTat można uruchamiać przez terminal, zintegrować z buildami Gradle lub Maven, lub podłączyć przez agregator Spotless.
Dodawanie do Gradle
Dla projektów używających Gradle z Kotlin DSL, plugin podłącza się w kilku linijkach:
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")
}
}
}
Sprawdzenia uruchamiamy poleceniem ./gradlew diktatCheck, a automatyczną naprawę wszystkiego, co analizator może osiągnąć, wykonujemy przez ./gradlew diktatFix.
Drobna konfiguracja reguł
Konfiguracja znajduje się w standardowym pliku YAML diktat-analysis.yml. Każda reguła jest włączana lub wyłączana osobno, a wiele z nich ma specyficzne parametry:
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]
Jeśli musisz pominąć konkretne sprawdzenie lokalnie, standardowa adnotacja @Suppress("FUNCTION_NAME_INCORRECT_CASE") lub ogólna @Suppress("diktat") działa bezpośrednio w kodzie.
Stopniowe wdrażanie przez Baseline
Włączenie rygorystycznego lintera na starym projekcie z 50 000 liniami kodu bez przygotowania jest niemożliwe. Developerzy utoną w tysiącach ostrzeżeń.
Do tego diKTat ma tryb baseline. Przy pierwszym uruchomieniu narzędzie generuje plik XML ze wszystkimi bieżącymi problemami w projekcie:
./diktat --baseline=diktat-baseline.xml "src/**/*.kt"
Plik baseline jest commitowany do repozytorium. Po tym linter przestaje narzekać na stary kod i blokuje build tylko wtedy, gdy ktoś wprowadzi nowe naruszenia w świeżym commicie.
Integracja z GitHub Actions

Narzędzie może wyprowadzać raporty w formacie SARIF. W połączeniu z GitHub Actions błędy i ostrzeżenia stylistyczne są podświetlane bezpośrednio w interfejsie pull requesta z dokładnymi referencjami do linii. Nie trzeba konfigurować zewnętrznych botów do komentarzy.
name: Upload SARIF report
uses: github/codeql-action/upload-sarif@v1
if: always()
with:
sarif_file: build/reports/diktat/diktat.sarif
Czy warto wypróbować
DiKTat jest bardzo nieprzejednany. Jego wytyczne wymagają jawnego porządku importów, limitują długość funkcji do trzydziestu linii, kontrolują obecność dokumentacji KDoc dla metod publicznych i zabraniają niepotrzebnych var.
W przypadku projektu hobbystycznego z dwoma osobami takie ograniczenia będą wydawać się przesadą. Ale jeśli rozproszony zespół pracuje nad serwisem lub rozwijasz bibliotekę open-source, diKTat usuwa ból synchronizacji stylu i uwalnia czas na code review do dyskusji o architekturze zamiast o białych znakach. Najłatwiejszy sposób na start to dodanie pluginu Gradle w trybie sprawdzania jednego modułu i wygenerowanie baseline.
Powiązane projekty