>_ DevTrendsnl

Taal

Home

Talen

Secties

Frontend Backend Mobiel DevOps AI / ML GameDev Blockchain Embedded Beveiliging
Kotlin

diKTat Verandert Kotlin Code Review in een Geautomatiseerde Routine

Ben je ooit in een situatie geweest waarbij een derde van je pull request-opmerkingen over opmaakgeschillen ging? Iemand liet een negatieve boolean achter zoals isNoError, iemand gooide de volgorde van methoden in een klasse door elkaar, en iemand vergeleek floating-point getallen met de ==-operator. Technisch gezien compileert de code en slagen de tests, maar zo'n codebase lezen wordt zes maanden later fysiek pijnlijk.

Meestal gaan teams voor Kotlin voor de combinatie van ktlint en detekt. De eerste let op inspringing en spaties, de tweede zoekt naar voor de hand liggende code smells. Maar er is een grijs gebied ertussen als het gaat om architectuurstijl en conventies, waar teams ofwel hun eigen regels schrijven of tijd verspillen aan handmatige opmerkingen. De diKTat-repository van het SaveOurTool-team lost dit probleem precies op.

Wat is diKTat

Het project is een strikte set codeconventieregels voor Kotlin. Technisch gezien is diKTat gebouwd bovenop ktlint en analyseert het de AST van bestanden. De repository bevat uitgebreide richtlijnen onderverdeeld in secties: naamgeving, KDoc-opmerkingen, klassenstructuur, functies, werken met types en variabelen.

Het hulpmiddel bevat meer dan honderd controles, waarvan veel helemaal niet worden gevonden in andere statische analyzers. Het belangrijkste gemak is dat diKTat niet alleen naar de console kan klagen, maar ook gevonden overtredingen automatisch onderweg kan herstellen.

Niet voor de hand liggende controles die je code redden

De meeste linters richten zich op opmaak. DiKTat graaft dieper en pakt semantische onregelmatigheden op.

Naamgeving en logica-netheid

DiKTat heeft een ingebouwd verbod op dubbele-negatieve variabelenamen. Als je een vlag declareert val isNotValid = false, zal de linter hernoemen naar een positief equivalent vereisen. Constructies zoals !isNotValid breken je hersenen bij het lezen, dus deze regel bespaart iedereen zenuwen.

Het controleert ook functieaanroepen met negatie. In plaats van !list.isEmpty() zal het hulpmiddel aanhoudend suggereren om list.isNotEmpty() te schrijven.

Volgorde van klasseleden

Een veelvoorkomend probleem in grote Kotlin-bestanden is de rommel van velden, functies en objecten. DiKTat controleert de structuur strikt:

  • Compile-time constanten
  • Regelmatige properties
  • Late-init properties
  • Init-blokken (en het hulpmiddel verbiedt het spawnen van meerdere init-blokken zonder expliciete noodzaak)
  • Constructors
  • Public, internal, protected en private methoden
  • Companion object

Als iemand een private helper voor de publieke API plaatst, zal de CI-build falen.

Type- en berekeningsveiligheid

Het hulpmiddel verbiedt directe vergelijking van types Float en Double via ==. Vanwege de eigenaardigheden van binaire representatie van floating-point getallen leiden dergelijke vergelijkingen vaak tot moeilijk te vangen bugs. DiKTat dwingt je om delta-controle via abs(a - b) > EPS te gebruiken of over te schakelen naar BigDecimal.

Een andere leuke controle volgt redundante casts. Als Kotlin al een Smart Cast binnen een conditie heeft uitgevoerd, wordt het aanroepen van as Type gemarkeerd als onnodige ruis.

// Было
if (x is String) {
    print((x as String).length)
}

// Стало после автофикса
if (x is String) {
    print(x.length)
}

Hoe uit te voeren en te configureren

DiKTat kan via terminal worden uitgevoerd, geïntegreerd in Gradle- of Maven-builds, of verbonden via de Spotless-aggregator.

Toevoegen aan Gradle

Voor projecten die Gradle met Kotlin DSL gebruiken, wordt de plugin in een paar regels verbonden:

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")
        }
    }
}

Controles worden uitgevoerd met het commando ./gradlew diktatCheck, en alles wat de analyzer kan bereiken automatisch herstellen wordt gedaan via ./gradlew diktatFix.

Fijnafstelling van regels

Configuratie leeft in een standaard YAML-bestand diktat-analysis.yml. Elke regel wordt afzonderlijk in- of uitgeschakeld, en veel hebben specifieke parameters:

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]

Als je een specifieke controle lokaal moet onderdrukken, werkt de standaard annotatie @Suppress("FUNCTION_NAME_INCORRECT_CASE") of een algemene @Suppress("diktat") direct in de code.

Geleidelijke adoptie via Baseline

Een strikte linter inschakelen op een oud project met 50.000 regels code zonder voorbereiding is onmogelijk. Ontwikkelaars verdrinken in duizenden waarschuwingen.

Hiervoor heeft diKTat een baseline-modus. Bij de eerste uitvoering genereert het hulpprogramma een XML-bestand met alle huidige problemen in het project:

./diktat --baseline=diktat-baseline.xml "src/**/*.kt"

Het baseline-bestand wordt gecommit naar de repository. Daarna stopt de linter met klagen over oude code en blokkeert de build alleen als iemand nieuwe overtredingen introduceert in een verse commit.

GitHub Actions-integratie

img.png

Het hulpmiddel kan rapporten uitvoeren in SARIF-formaat. Gecombineerd met GitHub Actions worden stijlfouten en waarschuwingen direct in de pull request-interface gemarkeerd met exacte regelverwijzingen. Geen noodzaak om externe bots voor opmerkingen te configureren.

name: Upload SARIF report
  uses: github/codeql-action/upload-sarif@v1
  if: always()
  with:
    sarif_file: build/reports/diktat/diktat.sarif

Is het de moeite waard om te proberen

DiKTat is zeer onverbiddelijk. De richtlijn vereist expliciete import-volgorde, beperkt de functielengte tot dertig regels, controleert de aanwezigheid van KDoc-documentatie voor publieke methoden, en verbiedt onnodige var.

Voor een hobbyproject met twee mensen zullen dergelijke beperkingen overdreven lijken. Maar als een gedistribueerd team aan een service werkt of je een open-source bibliotheek ontwikkelt, verwijdert diKTat de hoofdpijn van stijlsynchronisatie en maakt het codereview-tijd vrij voor het bespreken van architectuur in plaats van witruimte. De gemakkelijkste manier om te beginnen is door de Gradle-plugin toe te voegen in single-module-controlemodus en een baseline te genereren.

Gerelateerde projecten