Static analysis
Checking your code without running it
Basic idea
Static analysis = checking codebase by looking at the source code without running it
Great addition to automated testing and code reviews
Formatting and coding style
- Automated checking of formatting rules
- Example (multi-language): Prettier
- Example (Java): CheckStyle
- Automated formatting
- Example (multi-language): Prettier
- Example (Java): Eclipse Code Formatter
- Automated coding style checks
- Example (JavaScript): ESLint
- Example (Java): CheckStyle
- Example (Java): SpotBugs
Common bugs and code smells
- Example (JavaScript): ESLint
- Example (Java): CheckStyle
- Example (Java): SpotBugs
- Example (multi-language): SonarQube
- ESLint plugin with some relevant rules: eslint-plugin-sonarjs
- Example (multi-language): Semgrep
- Very straightforward way to add own rules on top of community rules
Technical debt and duplication
- Example (multi-language): SonarQube
Note: stay practical about this!
- The technical debt reported by tools like this is just an indication. Set your own priorities and see where the cost of paying off the debt is worth the benefits.
- Not all duplication is bad duplication. See also Duplication.
Third-party dependencies
- Check if third-party dependencies used by the code are properly defined
- Example (JavaScript): dependency-cruiser (check for dependencies missing in
package.json
, production code relying ondevDependencies
oroptionalDependencies
, ...)
- Example (JavaScript): dependency-cruiser (check for dependencies missing in
- Check for known vulnerabilities in third-party dependencies
- Example (JavaScript):
npm audit
- Example (multi-language): GitHub dependency vulnerability checks (see About supply chain security )
- Example (JavaScript):
- Check licenses for third-party dependencies
- Example (JavaScript): NPM License Checker
Internal dependencies
- Check for circular dependencies, unused code, ...
- Example (JavaScript): dependency-cruiser
- Example (JavaScript): ESLint (import/no-cycle )
- Example (Java): JDepend (see example code below)
- Example (TypeScript): ts-unused-exports
- Enforce monorepo boundaries
- Example (JavaScript): eslint-plugin-monorepo-cop
- Enforce custom boundaries
- Example (JavaScript): dependency-cruiser (see example code below)
- Example (Java): JDepend (see example code below)
- Visualize dependencies
Example dependency-cruiser rule for enforcing custom boundary:
{
name: 'component-a',
severity: 'error',
comment: 'Do not reach into component A',
from: {
pathNot: '^src/componentA/'
},
to: {
path: '^src/componentA/',
pathNot: '^src/componentA/index',
}
}
Example automated test code for circular dependency checking with JDepend:
Collection packages = jdepend.analyze();
assertEquals("Cycles found", false, jdepend.containsCycles());
Example automated test code for checking direction of imports using JDepend:
DependencyConstraint constraint = new DependencyConstraint();
JavaPackage ejb = constraint.addPackage("com.xyz.ejb");
JavaPackage web = constraint.addPackage("com.xyz.web");
JavaPackage util = constraint.addPackage("com.xyz.util");
ejb.dependsUpon(util);
web.dependsUpon(util);
jdepend.analyze();
assertEquals("Dependency mismatch", true, jdepend.dependencyMatch(constraint));
Type checking
- A programming language's type system can be seen as a form of static analysis
- It's possible to add type checking to a language that doesn't have it built in
- Example: using TypeScript to add type checking to a JavaScript codebase