PHP/Drupal Code Quality Quick Wins, Part 1: Linting
In this first part we’re looking at a few tools that are very easy to set up and use, yet can make a dramatic impact in the quality and coherence of your team’s codebase.
From validating syntax to detecting dead code to graphing dependency chains and measuring cyclometric complexity, static analysis tools help you analyse code without actually executing it.
For ages we kept saying “we’ve got no time to waste on trying to figure out this stuff, we have bugs to fix”. We kept chasing after elusive bugs, weird regressions (once-solved bugs that suddenly pop up again) and new breakages and we "never had time” to start improving the core of our development process.
Once we actually took the time, we discovered it’s pretty easy to get started. If you come from a workflow with zero attention to code analysis, testing and automated integration, there are some very easy and interesting quick wins out there.
We’ll try to cover several approaches, flows and tools in the weeks and months to come. We’ll likely discover new tools and new ways of improving our internal way of doing things, and we’ll share those as we encounter them - they may in some form be useful to you and your team as well.
On to the linting
In a nutshell, linters check checks if your source code is syntactically valid; it does not necessarily have any opinions about your coding style or about the soundness of your architecture. PHP's built-in linter is such a basic sanity-checking tool. Other tools such as jshint and jslint can be more opinionated.
Though this is a very simplistic check, you’d be amazed of how useful it can be to integrate automatic linting in your commit, test and deployment process.
1. PHP linting
Linting comes built-in with php-cli, the command line version of PHP, so if you’ve got that up and running you’re ready to start linting.
$a = 1;
# Example 1: Lint a single php file.
$ php -l example.php
PHP Parse error: parse error in example.php on line 2
When the linter encounters an error, the return code (a.k.a. exit status) will be non-zero, which means you can easily integrate php -l in scripts that perform certain actions (like deploying code) based on whether or not the linter encountered errors.
# Example 2: Lint all php files in a directory.
$ php -l .
- .jshintrc: some Drupal-specific rules
- .jshintignore: which files JSHint should ignore
The most convenient way to use JSHint is to run it from the command line. For this you'll need to install nodejs (http://nodejs.org/download/) and use its package manager npm to install jshint. Installing nodejs for this may seem like overkill, but there's an incredible array of interesting stuff available in nodejs land :)
# Install JSHint.
$ npm install -g jshint
# Example 1: Lint a single js file.
$ jshint example.js
# Example 2: Lint all of D8's core js.
$ cd /path/to/example.com
$ jshint core
# Example 3: Lint all of a D8 project's js (core+contrib).
$ cd /path/to/example.com
$ jshint .
- JSHint in D8: https://drupal.org/node/1955232
3. CSS linting
The standard ruleset used by CSS Lint (http://csslint.net) is pretty sane, though it does have some conflicts with the proposed Drupal CSS code standards (discussed here: https://drupal.org/node/1886770).
At the time of writing (March 2014) there doesn't seem to be a specific Drupal CSS ruleset available for CSS Lint, though efforts are underway to create a .csslintrc config file, similar to .jshintrc. For now, the standard CSS Lint ruleset is already a huge help.
# Install CSS Lint.
$ npm install -g csslint
# Example 1: Lint a single css file.
$ csslint example.css
# Example 2: Lint all css files in a directory.
$ csslint .
4. SASS/SCSS linting
If you're a front-end developer chances are you're using something like SASS (http://sass-lang.com) or Compass (http://compass-style.org) to infuse to your css files with variables, loops, extensions and more. The CSS extensions defined by sass can become tricky, so it makes sense to bring a specialized linter into play… enter scss-lint (https://github.com/causes/scss-lint):
# If you haven't already, install the SASS gem.
$ gem install sass
# Install scss-lint.
$ gem install scss-lint
#Example 1: Lint a single scss file.
# scss-lint example.css
#Example 2: Lint all scss files in a directory.
# scss-lint .
Note: scss-lint has built-in support for the Compass framework; you just need to explicitly specify you want to enable the compass linter. Check out the docs (https://github.com/causes/scss-lint/blob/master/lib/scss_lint/linter/co…) to see how.
- Source: https://github.com/causes/scss-lint
- SASS: http://sass-lang.com
- Compass: http://compass-style.org
Linting tools help you validate source code. Command-line linters can be run ad-hoc and integrated into IDEs and build scripts. Setting them up and running them is pretty straightfoward and can have huge benefits for your team's code quality.
Look out for follow-up articles where we'll go into validating custom Drupal code and enforcing our code validations with git pre-commit hooks.