When reviewing merge requests I always find it hard to bring up issues with code style.
Code style is subjective. I have my own opinion of what clean code looks like, and that opinion may be very different from the opinion of the rest of my team.
There are also different levels of code style. On one end of the spectrum we have best practices that directly affect the maintainability of the code going forward:
- Small methods
- Descriptive method names
On the other end we have issues that do not necessarily make the code harder to maintain, but often make the codebase more consistent and easier to read:
- Consistent indentation
- Wrapping long lines
- Avoiding walls of code
While I find it easy to comment on code that does not follow the best practices in the first group, I find it harder to send a merge request back to the author because of issues from the second group.
If the code works and the tests pass, is it worth delaying that feature because the author used tabs instead of spaces?
This is where automation comes in. While it isn’t possible to automate everything, there are tools that can automatically detect code style violations and flag them during the coding process or during the build pipeline.
Some tools can even automatically fix some code style violations.
In my opinion, the first step to implement these kinds of checks is to get the team together and agree upon a set of code-style rules — rules that may be limited to the best practices for that particular language or also include specific rules for your project. Once the rules have been decided, integrate the tool into your development/build process to flag code that breaks those rules. This way developers get feedback on code that breaks the style rules early and can fix them before even submitting their code for review.
Different languages have different tools for this purpose. When I am working on a Kotlin project, I use Ktlint.
What is Ktlint?
Ktlint is a tool that scans your codebase against a set of code style rules to find violations. It describes itself as:
An anti-bikeshedding Kotlin linter with built-in formatter
The term “bikeshedding” refers to the idea that when a team is faced with a large or complex decision they will spend too much time on trivial and unimportant decisions. In the original metaphor it refers to a committee tasked with approving plans for a nuclear power plant that end up spending the majority of their time on unimportant decisions, such as the materials to be used for the staff bike shed.
Ktlint tries to avoid bikeshedding by making the unimportant decisions for you — the ones about what style rules to follow.
It comes with a set of style rules based on the official Kotlin style guide. That doesn’t mean you can’t configure it though. You’re free to disable some rules or create new ones, but in most cases, the standard rules will be enough.
You can use it either to check that your code conforms to all the rules, or as a formatter to fix non-conforming code automatically. The formatter is unable to fix certain issues, but, in my experience, it correctly fixes the most common ones.
Integrating Ktlint and Gradle
One of the things I like about Ktlint is the ability to integrate it into your build pipeline using maven or gradle. You can find installation instructions in the Ktlint README. Personally, I use it with gradle and I prefer to set it up without plugins.
The installation is pretty straightforward — the build.gradle
file shown below has all the pieces to set it up. The two main steps are 1. adding Ktlint as a dependency and 2. adding new gradle tasks to run Ktlint against your codebase.
apply plugin: 'java'
repositories {
jcenter()
}
configurations {
ktlint
}
dependencies {
ktlint "com.pinterest:ktlint:0.38.1"
}
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
args "src/**/*.kt"
}
check.dependsOn ktlint
task ktlintFormat(type: JavaExec, group: "formatting") {
description = "Fix Kotlin code style deviations."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
args "-F", "src/**/*.kt"
}
We’re also linking the check
task to depend on the ktlint
task. This means that the gradle check
command will run code-style validations and fail if your code does not follow the style guides you have configured for your project.
Running Ktlint
Now that you have set up your gradle file, running Ktlint is simple. You can either run gradle check
to run all checks, or run one of the custom tasks we just created:
// To check your code follows style rules
gradle ktlint
// To attempt to fix code that does not follow style rules
gradle ktlintFormat
You can also run these tasks as part of your CI/CD pipeline and require them to pass before merging new features. This way you can ensure your code always conforms to the style guides your team agreed upon.
You can take a look at my Kotlin project template to see how I setup Ktlint and Gitlab CI/CD for my Kotlin projects.
Thanks for reading. You can follow the links below to learn more about Ktlint and how I use it.
Resources
- Ktlint homepage — https://ktlint.github.io/
- Ktlint GitHub repository — https://github.com/pinterest/ktlint
- Ktlint Installation Instructions — https://github.com/pinterest/ktlint#installation
- My Kotlin Template Project — https://gitlab.com/hctrdev/kotlin-template