January 2020 by George Guimarães

Boosting Developer Productivity Through Linters

Developers are always looking for opportunities to improve productivity — it's inherent to our mindset. The search for productivity occurs at all stages of development — from saving a few keystrokes to saving hours of time spent on manual deployment.

In this article, you'll learn how linters let developers increase their productivity. We explore how to integrate linters into our workflow, and the stages of development where linters work best.

This is a guest post from George Guimarães, the CEO of SourceLevel. SourceLevel is a service providing automated code reviews and engineering metrics that improve codebase insight for tech leaders.

Modern software development has evolved a mindset of effectiveness as well as productivity. That is, we're concerned not only with deploying more code, but with solving real problems in a fast and sustainable way.

This change in mindset was ignited by the Agile Manifesto and the Extreme Programming methodology. Both of those movements affected the way many developers looked at the development workflow.

Currently, the challenge isn't how to build and deploy software — as technology evolved as well — but achieving a fast and sustainable pace with space for innovation and agility to change directions.

This new dynamic requires developers to work smarter. In this sense, code quality and maintainability become vital aspects to pay attention to. More than ever, business success depends on them.

Why Linters Are Essential

Linters use static code analysis techniques to look for inconsistencies, potential bugs and vulnerabilities in code. Instead of executing the code, static code analysis reads the source files and tries to figure out what's going on.

In practice, linters are pieces of code that perform analysis on other pieces of code, like a programmable, automated peer reviewer. The issues found are presented to the developer, to be tackled before the code is pushed forward.

The great benefit of linting is that it gives you early feedback. Early feedback is at the core of the agile and productivity mindset because it avoids costly rework and mistakes down the road. Even better, it can save time and effort for developers, as using an automated tool for finding potential bugs is faster and, for some classes of bugs, more effective than human review.

There are plenty of linters available covering a wide range of programming languages and technologies. The majority of them are open-source, as seen in the awesome-linters project.

Choosing a Linter

Before choosing a linter, it's essential to understand the goal behind it. Each linter has a different purpose, and the intention behind the choice must be clear. I like to split linters into three main categories based on the kind of checks they do:

  • Syntax checks. Linters in this category look for syntax errors and logic problems. They are an excellent choice to prevent typos, bugs and increase productivity. Instead of exercising the software to find whether the code runs smoothly, linters do it just by checking syntax conformity.

  • Style checks and formatters. Every developer has taken part in a tab vs. space or single quote vs. double quotes discussion at some point in their career. I know, I've been there. It happens because people have different preferences for code style. However, it's crucial to have a standardized codebase to achieve a fast and sustainable pace. Code base standardization through clear and defined guidelines is at the root of maintainability. That's how vital this category is.

  • Best practices. Every programming language or framework has its best practices. More crucially, they have a body of knowledge that can be disseminated through linting. This category includes deprecation warnings, warnings about security and performance issues, and duplicated code detection. The linters here work both as education and bug detection tools.

Another important fact is that teams usually need to adopt more than one linter, as the three categories typically aren't covered by a single linter. In some cases, there may be some overlap, but that's the exception, not the rule. Besides, it's crucial to note that choosing a linter requires teamwork. Everyone should engage in the task. Otherwise, some benefits, such as code standardization, won't emerge.

Developers should use linters to obtain early feedback on their code. Integrating them into your IDE, into Git hooks, and into the code review workflow are excellent ways to ensure they're regularly run. Each integration serves a different purpose, so let's dig into them.

Running Linters in Editors and IDEs

Code editors and IDEs provide the environment where developers spend most of their time. That's why integrating linters here can have a significant impact on productivity.


VIM Editor configured with the vim-syntastic plugin.


Each individual has their preferences, ranging from super-customizable editors like Vim to integrated solutions like VS Code. Whatever your editor, there probably is a way to make it run linters and provide instant feedback in the UI.


VS Code configured with the Peek linter.


In the article Tools and Tasks in Visual Studio Code, Kristian Lumme shows how to configure Prettier to format JavaScript and CSS files. If you're not a VS Code user, don't worry! Finding out how to set up a working environment is easy, and the internet has plenty of useful how-tos and plugins.

Running Linters in Git Hooks

The Tower FAQ on Git Interview Questions states that hooks "are custom scripts that can be configured to be run when certain events happen." You can take advantage of this mechanism to incorporate any checks, including linters.

Many events can trigger automation, and choosing the appropriate one can be tricky at first. I bring a recommendation, saving you time by letting you go straight to the most appropriate one! I recommend the pre-commit hook, which triggers before the git commit command is completed.

In summary, you need to write a script that checks for files selected for commit, then you run a command (which varies depending on the chosen linters) for each file and halt the execution in case of error.

Below is an implementation example. The content should be placed in a file named pre-commit inside the .git/hooks/ directory. Don't forget to grant execution permission using chmod +x .git/hooks/pre-commit.

#!/usr/bin/env bash

for file in "$(git diff-index --cached --name-only HEAD)"; do
    case "$file" in
    *.js)
        # Check JavaScript files with `node` command
        node -c "$file"
        ;;
    *.json)
        # Check JSON files with `jsonlint`
        jsonlint -c "$file"
        ;;
    *.scss)
        # Check SCSS files with `scsslint`
        scss -c "$file"
        ;;
    esac
done

For each file found by the git diff-index command, the script checks its extension. When a file matches a particular case clause, the code in the clause runs. If the script exits with an error status, the commit is aborted. You can force the commit through by using the --no-verify flag, which ignores the hook.


Git aborting a commit due to syntax error in a JavaScript file.


However, excessive usage of the flag is inconvenient and diminishes the benefit of automated code checks. For a better experience, I recommend aborting a commit only when linting syntax checks. Linters that check style and best practices can be handled afterward during code review, where they're more effective.

If you found the template hard to understand, no worries! Managing Git hooks can be tricky, so I recommend using an auxiliary tool like husky, which has comprehensive documentation and examples available online.

In case you're a GUI enthusiast, I have good news! The Tower Git client respects hooks, but you need to make sure the script outputs errors to STDERR.

Running Linters in Code Review

Running linters in the IDE and before committing brings individual productivity gain by anticipating feedback for silly errors and typos.

Developers receive the value of real-time feedback through linting while they're coding. However, teams can unlock another layer of productivity. They can gain velocity and reduce bugs by standardizing the codebase and controlling technical debt.

To achieve this, it's not enough for individual developers to run linters. The practice of linting must be institutionalized for everyone on the team. In other words, linting must become part of the development process.

This works very similarly to running automated tests for every change. But instead of a CI/CD server, it requires a tool like SourceLevel, which runs widely-adopted linters for each pull request, and adds the discovered issues as inline comments in the version control hosting service.


SourceLevel's bot adds inline comments to explain any discovered issues.


Big tech companies around the world have adopted this practice. The industry calls this feature automated code review, though despite the name, automation doesn't remove the need for peer review!

Rather, automated code review removes the tedious and laborious part of code review, enabling high-level discussions on code design, architecture, and maintainability.

Conclusion

Code quality and maintainability are essential for achieving a fast and sustainable pace. Linters are fundamental tools in the quest, as they promote a homogeneous and healthy codebase.

I've explored how developers can take advantages of linters to become more productives. In summary, developers can configure linters to run locally in their code editors and IDEs, and during the pre-commit Git hook. However, for a holistic approach, teams need to institutionalize the practice, and in this case, automated code review is recommended.

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!