DRUPAL8 DEVELOPMENT STANDARDS
Coding Standard and Best Practices
Abstract This document covers best practices to be followed by all developers who will be working on development and implementation of a Drupal8 CMS on Acquia platform for UNICEF.
ICTD-Solution Center and Services Table of Contents
1 Executive summary ...... 3 2 List of standardized tools which should be used while working on Drupal8 Project...... 4 3 Creating a new Drupal8 codebase ...... 4 4 Drupal 8 implementation structure (where do I find what) ...... 5 4.1 Directory Structure ...... 5 4.2 Install Profile ...... 5 4.3 Modules ...... 5 4.4 Themes ...... 6 4.5 Test directory structure ...... 6 5 Coding standards ...... 7 6 Theme standards ...... 7 7 Automated Testing ...... 7 7.1 Coding standard Test ...... 7 7.2 Functional Test ...... 7 8 Git Usage and workflow ...... 8 8.1 Pull Requests, commits and Code Review Guidelines ...... 8 8.2 Naming Conventions when using Git ...... 9 8.3 Developer Workflow ...... 9 8.4 Deployment Via BLT ...... 10 9 Best practices for project/website development ...... 10 9.1 Composer Dependencies ...... 10 9.2 Configuration Management ...... 11 9.3 Custom Code ...... 11 9.4 Updates...... 11 9.5 Variables naming ...... 11 9.6 Theme best practices ...... 12 9.7 Definition of DONE during development process ...... 12 10 Best practices for PR code review ...... 12 10.1 Preparation steps ...... 12 10.2 General checks ...... 13 10.3 JavaScript-related checks ...... 13 10.4 Twig-related checks ...... 13 10.5 CSS and Sass-related checks ...... 13 10.6 PHP-related checks ...... 14 10.7 YAML-related checks ...... 14 10.8 Automated Checks ...... 14 10.9 Definition of DONE during code review process ...... 15 11 Resources & additional information ...... 15
1 Executive summary
The purpose of this document is to provide guidelines, recommendations and the minimum mandatory requirements, which should apply to any Drupal 8 CMS based implementation using the Acquia platform and authored by or under the responsibility of any UNICEF office.
UNICEF development standards are built to ensure a coherent and cohesive Drupal 8 implementation strategy across the organization as well as better quality, robustness and maintainability during development, launch and post-launch.
UNICEF development standards require the use of Acquia BLT framework with Drupal native configuration management. Using Acquia BLT enforces the development to use a set of tools, such as Composer and NPM as the dependency management tools, and a Continuous Integration tool (such as Travis). In addition, UNICEF highly recommends the use of a Drupal VM for easier integration with BLT.
UNICEF requires to use configuration management approach (file-based) instead of regular SQL database storage, in order to benefit from a versioning system for configuration in any Drupal 8 implementation.
In order to enable easier compliance of these standards, UNICEF will provide a Composer file, which will include the list of approved Drupal modules. This Composer file will be required to be used to create the project. In addition, UNICEF will provide a private Github repository under UNICEF Github organization account where all development should happen.
Regular audits might be performed by UNICEF technical team to ensure compliance of UNICEF development standards.
Additional requirements, guidelines and best practices are found in the document below. 2 List of standardized tools which should be used while working on Drupal8 Project
The below list includes a (non-exhaustive) list of required and recommended tools to be used in any Drupal 8 implementation.
Name of tool Description Ticketing/Project UNICEF highly recommends the use of a project tracking tool which support tracking software agile/scrum based projects (e.g. VSTS, Github Issues, JIRA) tool Github UNICEF requires the use of Github as the control versioning tool. Acquia BLT UNICEF requires the use of Acquia BLT for deployment, build and test. Continuous UNICEF highly recommends the use of Travis CI for seamless integration with Integration Acquia BLT. Bootstrap UNICEF requires the use of Bootstrap as the base theme Acquia Lightning UNICEF requires the use of Acquia lightning distribution profile. distribution
3 Creating a new Drupal8 codebase
UNICEF requires to use composer to manage dependencies with the codebase. For creating a new Drupal8 codebase, UNICEF will provide composer files. Any deviation from the included core and contributed modules and versions will have to communicated/coordinated with UNICEF development team for approval before implementation.
Please note that UNICEF composer includes Acquia BLT framework to manage and deploy code and database, as well as Acquia lightning distribution and additional contributed modules those are approved by UNICEF.
UNICEF standards highly recommends the use of Drupal VM, as it provides a self contained environment for local development. More information is found at https://www.drupalvm.com/
UNICEF standards requires the use of Drupal native configuration management approach (file- based), as it provides a versioning system for configuration instead of regular SQL database storage. More information on configuration management is found at https://www.drupal.org/docs/8/configuration-management 4 Drupal 8 implementation structure (where do I find what)
This section describes the required implementation architecture structure that should be followed:
4.1 Directory Structure
Top-Level directories
/blt /config /docroot /composer.json /travis.yml
Second-level directories
/docroot/modules/ /docroot/profiles/ /docroot/sites/ /docroot/themes/
4.2 Install Profile
Install profile in Drupal 8 has all the functionality of modules, including access to hooks and plugins and, critically, the ability to provide configuration for the site in the form of .yml files.
The profile name should consist of lowercase letters and underscore only.
Creation of the profile should be based on the lightning profile. For more details about how to create sub-profile, refer to Acquia's documentation - https://docs.acquia.com/lightning/subprofile
Should the codebase make use of different profiles, the below structure should be followed.
/docroot /profiles /custom /profilename /config/ /modules/ /README.md /profilename.info.yml /profilename.install /profilename.profile
4.3 Modules
The code base should include the following structure for contributed and custom modules:
/docroot /modules /contrib /custom/ /example/ /example.module /example.info.yml /example.libraries.yml /example.install
NOTE: The list of approved modules is included in the UNICEF composer file. Please note that any additional contributed modules required for the project should be communicated/coordinated with UNICEF technical team for approval before implementation.
4.4 Themes
The code base should include the following structure for sub-themes:
/docroot /themes /contrib /custom /sitetheme /assets /images /templates /sitetheme.info.yml /sitetheme.libraries.yml /sitetheme.info.yml /sitetheme.breakpoints.yml
4.5 Test directory structure
The code base should include the following structure for testing files, which will be created as part of Acquia BLT configuration:
/Tests /behat - contains all Behat tests /features /bootstrap /Example.feature /behat.yml - contains behat configuration common to all behat profiles. /integration.yml - contains behat configuration /phpunit - contains all PHP Unit tests 5 Coding standards
The Drupal community has outlined some pretty comprehensive coding standards for code written and contributed to the Drupal community. The same standards should apply to any UNICEF Drupal 8 project. All the code should comply to the coding standards defined at https://www.drupal.org/docs/develop/standards
6 Theme standards
Any custom theme should be created from base theme bootstrap, as a sub-theme. New theme should follow SASS theming standard defined at https://drupal- bootstrap.org/api/bootstrap/docs%21Sub-Theming.md/group/sub_theming/8
NOTE: The theme should be used strictly as a display layer and should not contain large amounts of business logic or other JS/code.
7 Automated Testing
Drupal 8 development should include automated test coverage as below:
7.1 Coding standard Test
BLT includes automated testing for coding standards through linting/sniffing by default. More information is found in section 10.8 Automated checks.
7.2 Functional Test
Behat Tests: Any development should include Behat test for all business logic and user interfaces that are accessible via the browser. Functionality should be expressed as a behavioral test for automated testing.
By default, the two primary areas of testing should be on the content model/content structure implementation and user roles & permissions.
At a minimum each Pull Request submitted by a developer should include either a complete behavioral test of the 'sunny skies' scenario of the story being built, or an update to an existing scenario if this is a bug fix.
Behat resources can be found in a variety of places, here are a few extra reading links: http://behat.org/en/latest/user_guide/context.html http://docs.behat.org/en/v2.5/guides/1.gherkin.html https://media.readthedocs.org/pdf/behat-drupal-extension/latest/behat-drupal-extension.pdf
Examples of Behat tests can also be found at:
PHPUnit Test: PHPUnit integration/unit test should be used for functionalities that are not reachable by the browser. Examples: inside Cron logic, server-to-server communication of any kind, API integrations, etc. The Drupal community maintains an excellent documentation.
8 Git Usage and workflow
All development should be done in a version control system, such as Git. Github software should be used. Please contact UNICEF technical team to get a UNICEF private repository for your project.
When working with Github and Acquia, the following rules and workflow should be followed:
• The main git repository should contain at least a develop, a master and a hotfix branch • All developers will work on their forked version of the repository • Development can happen in parallel on different branches. Once finished should be merged to Develop branch • Developers will create pull requests against their main repository • Once a pull request happens, a code review should be done by another developer, before being merged to the main repository. • Stable code will be released via Release branch (created from develop branch), it will be tagged accordingly for production release and moved to master branch. • Hotfixes will be managed by a hotfix branch and will be deployed to Prod environment via another tag. • Hotfix branch will later merged to develop • Developers will be allowed to push directly to the Acquia dev environment.
Regular audits might be performed by UNICEF technical team to ensure compliance of UNICEF development standards.
On those special cases when the project/website will live under the same codebase managed by UNICEF development team, all deployments to staging and production environment will be handled by UNICEF, once a code review is approved by UNICEF team.
8.1 Pull Requests, commits and Code Review Guidelines
Pull requests have a number of aspects that should be followed:
• The title of the pull request should include the ticket number and description. E.g. "VSTS- 1234: Fix template style on hero image”. Pull requests should only contain the work relevant to the story being resolved. Do not combine issues, or attach 'rider along code' that is unrelated. Discussion during the review process should be kept civil. It is important to remember that the code being reviewed is not art, and issues raised are only helpful to the cause. Commit messages should identify the ticketing system issue number they are related to. Note that this will not always line up with the number identified in the branch. for example, if VSTS-1234 has a subtask, that issue might be referenced in the commit. EG: "feat(new_module): 1235 - Added micro version handling." Commits should be isolated to working groups of changes only. Do not commit non- functional code, or split functionality between commits if they are dependent on each other. Code reviews should follow best practices for theme review, as found in https://www.drupal.org/docs/develop/standards/css/what-to-look-for-when-reviewing-css
8.2 Naming Conventions when using Git
The below naming conventions is recommended when committing and pushing code.
• commit message – Format is “task_type (very short task desc): task_id – description of commit” Task types are: o feat (new feature) ▪ eg- feat(search): 1564 - updated search block markup o fix (bug fix) ▪ eg: fix(country): 1564 - error for country module dependency. o docs (changes to documentation) ▪ style (formatting, missing semi colons, etc; no code change) o refactor (refactoring production code) ▪ eg: refactor(migration): 1564 - removes duplicated migration file o test (adding missing tests, refactoring tests; no production code change) o chore (updating grunt tasks etc; no production code change) Branch Naming
This section describes the workflow that developers should follow when committing their work to the main repository.
Create a new/update an existing feature: o Developer should create your own fork (forked repository) from main project repository (upstream repository) o On your local system you execute git clone on e.g. https://github.com/
o Once merged delete your branch - git branch -d feature-name
8.4 Deployment Via BLT
As a vendor, you will need to deploy to Acquia cloud environment. The deployment should happen automatically after Pull Request gets merged to the main repository if you are using Travis CI. The configuration for the Travis CI should be similar as follows:
Configure the deployment at blt/project.local.yml: git: default_branch: migration-build remotes: '[email protected]:unicef.git'
More information about deployment workflow is found in: https://blt.readthedocs.io/en/latest/readme/deploy/
More information about continuous integration is found in: https://blt.readthedocs.io/en/latest/readme/ci/
9 Best practices for project/website development
The following are a list of best practices that should be followed by any Drupal CMS project. Many of these are driven by the project's use of Acquia BLT.
9.1 Composer Dependencies
Contributed modules, and libraries must not be included in our code base. All external code (code managed in public repositories) should be added as composer dependencies, and given proper upgrade paths. Any modules, or components that require patches should have those patches added to the master composer.json file, with accurate descriptions associated with each patch.
9.2 Configuration Management
All Drupal configuration should be exported to code in the form of config management using config split and ignore that can be deployed to the site. Configuration should be exported to the config/ path outside of the document root.
For multisite implementations on single codebases, config-split over feature based implementation should be adopted.
9.3 Custom Code
Custom code should always 'live' with the configuration it supports. Sometimes this means it exists in and is maintained in a feature module - Considering these modules are auto-generated, this may sound strange but the source files where this code is housed is always preserved during exports, making these modules the ideal location for the glue-code that supports them.
Sometimes custom modules are not directly tied to a feature. In these cases the module should be moved to the
9.4 Updates
Access to upstream environments should strictly be controlled, and a "zero touch" process is in place. This means that no manual changes can take place on the servers, every update must be deployed automatically. This comes in the form of 'hook_update_n()' functions. These functions are required when any of the following conditions are needed:
Fields are renamed Fields are deleted Fields are changed from one data type to another Fields are moved from one entity type to another Data is manipulated Content must be created
All of the reasons above must also be taken into account in either the module's config/install folder, or in the hook_install() function, depending on the use case. For example: A renamed field must have the config/install folder adjusted to take into account the new field name, and a hook_update_n() needs to be created to transition the data to the new field, and remove the old field. Creating a mandatory node however, it does not need the config/install folder adjusted, but does need to be handled in both hook_install() and a hook_update_n() function.
9.5 Variables naming When creating a new component/template starting from Front-end side, these instructions should be followed to map the variables name to be used in templates.
• Prefix should start with ‘field_’ plus field name. e.g: field_[name] -> field_author Body and Title are Drupal default fields, and the should be kept as it is. If necessary, the same structure as above should be followed. e.g.: field_body or field_title
This way rework at variable’s renaming will be avoided since it will match both sides.
If development starts with Back-end side first, then this variable naming convention should also be followed and Front-end will replicate the same variable names in templates.
9.6 Theme best practices
UNICEF recommends to use drupal 8 theme standards documentation found in https://www.drupal.org/docs/develop/standards/css/css-architecture-for-drupal-8.
9.7 Definition of DONE during development process
The below information is used by UNICEF development team to ensure the quality of the process during development process. UNICEF recommends to follow these rules:
The work of the developer is considered done when:
✓ Functionality passes the acceptance criteria ✓ Manual test is provided, modified if needed and passing ✓ Automated test is provided if needed and passing ✓ Code complies to Drupal coding standards, and the guidelines & best practices mentioned in this document ✓ A pull request is created, assigned to a reviewer and How-To-Test are provided ✓ CI build is passing ✓ If issue type is bug, a short description of the solution is provided ✓ The issue has been set to a reviewer with the correct status 10 Best practices for PR code review
This section covers pull request code review best practices. UNICEF recommends following them when reviewing other developers’ work.
10.1 Preparation steps
1. Checkout the PR code:
`git fetch
2. Open the source code of the project in an IDE This is helpful to quickly look up relevant source code parts, or rely on the built-in inspections of the 1 IDE.
10.2 General checks
Check the naming of functions, PHP classes, CSS classes, files, constants, SASS mixins, etc. The names should be clear and concise. Duplicated or very similar, code parts are problematic and should be removed in every file type. Code comments should be checked, that it's not copy and pasted with irrelevant pieces, and that it is meaningful and provides value for the reader of the source code. This applies to every file type. Check whitespaces in every file type.2 Commented out code parts should be removed in almost every case, Git history is there to restore any previous state if needed. Check for obviously not used variables, rules, files, classes. Check if Travis passed for the last commit.
10.3 JavaScript-related checks
Check the use of the Javascript API: Behaviors, settings, context.3 Check Javascript code format.4 • Excessive amount of custom, project-specific JavaScript code is a “code smell,” for a typical Drupal project. Most functionality should be solved in PHP or using a JavaScript-based library. Check that errors of any kind are handled properly (e.g., unsuccessful HTTP requests)
10.4 Twig-related checks
BLT does validation automatically. Check for indentation and spacing issues. Check for absolute, hard-coded URLs that might cause issues if the base URL changes. Check for HTTP-only included resources (will result in mixed content warning).
10.5 CSS and Sass-related checks
1 For PhpStorm, see https://confluence.jetbrains.com/display/PhpStorm/Drupal+Development+using+PhpStorm ; For Atom.io, see https://atom.io/packages/linter-drupalcs 2 https://www.drupal.org/docs/develop/standards/coding-standards#indenting 3 see https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview. 4 https://www.drupal.org/docs/develop/standards/javascript/javascript-coding-standards - use eslint to check automatically (https://www.drupal.org/node/1955232). Check code format.5 If in doubt that something is valid SASS, compile it.6 Check for HTTP-only included resources (will result in mixed content warning).
10.6 PHP-related checks
Use local static code analysis, like Drupal coding standard check, to spot obvious problems, see below, report all issues. Check for security issues, SQL injections and XSS. SQL injection can come from un-sanitized user input, directly appended to SQL query. XSS typically come from unsanitized user input sent to the output without filtering.7 Check for hard-coded paths, hard-coded URLs. Check for HTTP-only included resources (will result in mixed content warning). Check for proper usage of the Drupal API. If there is an API function or class for the purpose, custom code should not be written, rather the code should rely on the existing solution. This is the hardest part of the code review, as it requires an extensive knowledge of Drupal. Errors of any kind should be handled and logged with Logger properly. Check for validation of data forms. Validation should happen when accepting data from the user, typically handled by the Drupal API. Do performance-related checks, to determine if something seems to be a resource-heavy operation. If so, question it; check if it's cache-able
10.7 YAML-related checks
Follow https://www.drupal.org/docs/develop/coding-standards/configuration-file-coding-standards
10.8 Automated Checks
Setting up PhpCS8
The ruleset can be found at the installed project too: vendor/drupal/coder/coder_sniffer
If for any reason, it's needed globally (for other projects, contributed modules and so on): git clone --branch 8.x-2.x https://git.drupal.org/project/coder.git cd coder composer install
5 https://www.drupal.org/docs/develop/standards/css/css-formatting-guidelines 6 http://beautifytools.com/scss-compiler.php 7 Refer to https://www.drupal.org/docs/8/security/writing-secure-code-for-drupal-8 for details 8See https://github.com/squizlabs/PHP_CodeSniffer and http://drupal.org/project/coder Bash aliases:
These aliases should be appended to .bash_profile (MacOSX) or to .bash_rc (Linux): alias codingstd='
Setting up ESLint
Drupal 8 provides ESLint configuration out-of-the-box. To perform the initial setup: cd docroot/core npm install
Then to inspect an individual file:
10.9 Definition of DONE during code review process
The below information is used by UNICEF development team to ensure the quality of the process during the code review process. UNICEF recommends to follow these rules:
The work of the code reviewer is considered done when:
✓ The code looks good ✓ The How-To-Test steps can be executed ✓ The manual test is executed successfully ✓ The pull request is merged into the correct branch ✓ The issue has been completed 11 Resources & additional information
Below is a set of URLs to documentation pertaining to various topics covered above and or general reference resources.
• Acquia's Documentation: https://docs.acquia.com/documentation • Acquia's BLT: https://blt.readthedocs.io/en/8.x/ • Travis CI Documentation: https://docs.travis-ci.com • Composer: https://getcomposer.org