As a developer, I strive to deliver high-quality code that is understandable for other developers and is as future proof as it can be. For me, this is an ongoing learning process in the way code is written, and tools that can be used to assist me. Many different sources can be found with opinionated instructions on how to write "perfect" code. It comes down to using a well-configured integrated development environment (IDE), not being shy in providing supportive comments that explain the code flow and structure the implemented functionality in logical methods and classes. But as a lazy programmer, I'm also interested in extending my development stack with tools that result in more qualitative code. When I can run these programs with one push of a button (better yet, run them automatically), it makes it easy to create quality reports and apply improvement changes immediately.
I've incorporated three different tools in my development stack, which are applied regularly and look at the code from different perspectives. One improves the readability of code by ensuring that Drupal's coding conventions are adhered, enforcing uniform code throughout the complete project (core, contributed, and custom code) and between all developers (also the ones in the future). The second tool uses static code analysis to locate flaws and make suggestions to improve the code. Finally, the third tool applies unit testing to ensure the code shows the intended behavior.
Required software packages
Assuming you're using Composer to manage Drupal's dependencies, the command line instructions below can be used to install all three code quality tools (for our development environment):
composer require --dev drupal/core-dev composer require --dev mglaman/drupal-check
Note that the drupal/core-dev provides both the drupal/coder and phpunit/phpunit packages. However, depending on your setup and preferences, you might want to install these tools globally. In that case, I can highly recommend taking a look at consolidation/cgr.
Enforcing Drupal's coding standards
The drupal/coder project provides the Drupal coding standards definitions, which are used as the configuration input for the scripts offered by squizlabs/PHP_CodeSniffer to detect whether code style violations are made. Besides detecting violations, this tool is also able to automatically provide fixes. The commands to invoke the scripts and check the code of our custom modules is:
./vendor/bin/phpcs --runtime-set installed_paths vendor/drupal/coder/coder_sniffer --standard=Drupal --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md,yml' web/modules/custom ./vendor/bin/phpcbf --runtime-set installed_paths vendor/drupal/coder/coder_sniffer --standard=Drupal --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md,yml' web/modules/custom ./vendor/bin/phpcs --runtime-set installed_paths vendor/drupal/coder/coder_sniffer --standard=DrupalPractice --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md,yml' web/modules/custom
The first command verifies whether the source code meets the Drupal coding standards, reports any violations and indicates which one can be fixed automatically. Run the second command to apply these automatic fixes. To avoid common mistakes and be informed about best practices, such as using Dependency Injection to load services, run the third command.
Using static code analysis to improve code
This tool is based/build on PHPStan and spots errors without running the code. It analysis your code and reports errors such as nonexistent classes and usage of deprecated code. To analyze your custom modules, run:
Applying automated tests using PHPUnit
To guarantee code keeps behaving as intended by the developer, unit tests should be supplied. When code is changed, due to refactoring, extending functionality, or simply because libraries are updated, running unit tests can give you a (relative) quick feedback whether errors occur. Another advantage of writing unit tests is that they provide in some way documentation about the implemented code. In this blog post, we focus only on how to run the unit tests easily, the topic of how to write proper unit tests and all possible feature that exists is out of scope.
Drupal (core) ships with a PHPUnit configuration file, i.e.,
web/core/phpunit.xml.dist, which can be used to set the correct options for running tests of your custom modules. Although this configuration file introduces some overhead, the main advantage is that it's kept up-to-date by Drupal (which controls the PHPUnit version). To correctly execute all different types of tests (e.g., based on
BrowserTestBase), some parameters have to be set. The easiest way to do this is by setting the following environment variables, which can be auto-loaded using vlucas/phpdotenv:
SIMPLETEST_BASE_URL=http://localhost SIMPLETEST_DB=mysql://username:password@localhost/databasename#table_prefix BROWSERTEST_OUTPUT_DIRECTORY=/path/to/webroot/sites/simpletest/browser_output
The command to start the unit tests then becomes:
./vendor/bin/phpunit --configuration web/core web/modules/custom