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.
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.
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:
/blt
/config
/docroot
/composer.json
/travis.yml
Second-level directories
/docroot/modules/
/docroot/profiles/
/docroot/sites/
/docroot/themes/
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
/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:
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
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.
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.
• 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
• 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 <type>-<name>
o <type>
▪ feature - New feature.
▪ release - New release.
▪ hotfix - Quick fixes to the codebase.
▪ junk - Experiments (will never be merged).
o <name>. Always use dashes to separate words, and keep it short. Examples:
▪ feature-renderer-cookies
▪ release-3.0
https://blt.readthedocs.io/en/latest/readme/deploy/
https://blt.readthedocs.io/en/latest/readme/ci/
For multisite implementations on single codebases, config-split over feature based implementation
should be adopted.
Sometimes custom modules are not directly tied to a feature. In these cases the module should be
moved to the <root>/docroot/modules/custom folder, which will be maintained and tracked via Git
(unlike its 'contrib' counterpart).
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:
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.
• 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.
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).
vendor/drupal/coder/coder_sniffer
If for any reason, it's needed globally (for other projects, contributed modules and so on):
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:
Setting up ESLint
cd docroot/core
npm install
<path to repository-name>/docroot/core/node_modules/eslint/bin/eslint.js
[target_custom_js]