Topic 1.5
Code Quality Gates: Linting, Static Analysis & Coverage
In one line
Quality gates are automatic checks that a change must pass besides tests: formatting and linting (consistent style, simple mistakes), static analysis (bugs and code smells found without running the code, like SpotBugs, Error Prone, or SonarQube), and coverage thresholds on new code. Run fast ones on every pull request, fail on new problems rather than old ones, and keep the rules few and meaningful so the gate is respected rather than bypassed.
Think of it like this
An editor checking a newspaper article before printing. Spelling and layout first (formatting and linting), then facts that look wrong (static analysis), and a rule that every new claim has a source (coverage on new code).
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Quality gate
- An automatic pass/fail check on code quality that a change must meet.
- Linter
- A tool that checks code for style problems and simple mistakes.
- Static analysis
- Finding likely bugs and problems by examining code without running it.
- Code coverage
- The share of code lines or branches executed by tests.
- New code period
- The changes being reviewed, as opposed to the whole existing codebase.
- SonarQube
- A platform that analyses code quality, coverage, and security issues and enforces quality gates.
Step by step
01Formatting and static checks in the build
Tiffin adds Spotless (formatting) and SpotBugs (likely bugs) to the Maven build. spotless:check fails CI if code isn't formatted, and developers run spotless:apply locally to fix it.
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.44.0</version>
<configuration>
<java><palantirJavaFormat/></java>
</configuration>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.6.6</version>
<configuration><failOnError>true</failOnError></configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution><goals><goal>prepare-agent</goal><goal>report</goal></goals></execution>
</executions>
</plugin>02A quality gate on new code
SonarCloud analyses each pull request and comments with the result. The gate fails only for problems in the PR's own changes, so a legacy class with old warnings doesn't block unrelated work.
sonar:
needs: unit-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # full history for new-code detection
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: "21", cache: maven }
- run: ./mvnw -B -ntp verify sonar:sonar -Dsonar.qualitygate.wait=true
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}03Reading the gate result
Arjun's PR adds a method with a possible null dereference and no tests. The gate explains exactly what to fix.
Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
A gate on the whole codebase
The team turns on a gate requiring 80% coverage overall, and the legacy codebase is at 52%.
Myth vs fact
Myth
High coverage means good tests.
Fact
Coverage shows lines that ran, not whether results were checked. A test with no assertions can reach 100%. Use coverage to find untested code, not to prove quality.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Add formatting to a pre-commit hook (Git course, Topic 4.4) and run the same check in CI. Developers fix style before pushing, and CI catches anyone who skipped the hook.
Remember this
- 1
Formatting: tools like Spotless (google-java-format or Palantir) or Prettier make style automatic, so reviews stop discussing spaces and braces. CI checks, developers' IDEs or hooks fix.
- 2
Linting and static analysis: Checkstyle (style rules), PMD, SpotBugs, and Error Prone (likely bugs: null dereferences, wrong equals, resource leaks) analyse code without running it.
- 3
SonarQube / SonarCloud: combines analysis, coverage, duplication, and security hotspots, with a quality gate on new code (for example: no new bugs, coverage on new code at least 80%).
- 4
Coverage (JaCoCo): shows which lines tests execute. Useful as a trend and as a floor for new code, misleading as a single target number for the whole codebase.
- 5
Clean as you code: gate on new or changed code only, so legacy issues don't block every PR while new code stays clean.
- 6
Keep gates fast and few. Every rule that produces noise trains people to ignore or suppress warnings.
Explain it without notes
Why gate on new code instead of the whole codebase?
What can static analysis find that tests miss?
Practice
Add a formatting check and a static analysis check to a project's CI.
Set up a coverage report and find the least-tested package.
Trade-offs
- ↔
Gates catch problems early and keep standards consistent, but noisy rules slow teams and get bypassed. A few high-signal checks beat many low-value ones.
Done when you can
CI checks formatting and static analysis on every PR.
Quality gates apply to new code.
I use coverage to find untested code, not as the goal.