The Drupal Commerce project is striving for strict adherence to the following development standards to produce the best quality code we can with a high level of maintainability. Any patch that is posted for review will be subject to these standards, which largely follow widely accepted Drupal development standards. Some of these items are simply best practices that will help us have a unified code style throughout the project.
If a patch needs work based on any of the project's development standards, please indicate the number below so the patch author can adapt his or her code style.
Suggestions for improving and/or expanding these standards should be posted in the Brainstormings forum for consideration. Don't be shy... we want these to be as helpful as possible.
- Code Syntax and Documentation
- Module File and Directory Structures
- Module Packages
- Function and Hook Naming
- Automated Testing
- Using Core and Contributed Module APIs
- Drupal Permissions and Access Control
- Localization and Variable Strings
- Template Files and Theme Functions
- Separating API from UI
- Performance Considerations
- Data Storage
1. Code Syntax and Documentation
We'll follow Drupal's coding standards for code syntax and documentation. All functions should be well-documented with both doxygen comment blocks and inline comments. Patches should pass the code review provided by the Coder module.
2. Module File and Directory Structures
Modules should pattern their files and directories after CCK:
The help directory contains files compatible with the Advanced Help module. The includes directory contains files referenced in menu items and other necessary module includes. The theme directory contains a theme.inc file for theme functions and preprocess functions in addition to any CSS or module based .tpl.php files. Theme / preprocess functions referenced by functions in *.admin.inc and *.pages.inc files can reside in the files themselves.
The tests directory contains SimpleTest include files.
3. Module Packages
Module .info files should use a strict set of package names:
- Commerce - used for all modules in the core Commerce project
- Commerce (contrib) - used for modules not in the core Commerce project regardless of who develops them
- Commerce (_____) - projects with dependencies between the various modules in the package may consider their own package name using the same format but should otherwise default to Commerce (contrib)
As an example exception, Commerce PayPal uses the Commerce (PayPal) package name, because each PayPal payment method is represented by a separate module that depends on a core PayPal module for IPN processing. It is helpful to the user to group these 4+ modules together with their dependency.
Contributed modules that don't conform to this standard should not be included in Features / distributions until they do. Issues should be posted on drupal.org to projects that do not conform.
4. Function and Hook Naming
Use the [module]_(object)_verb pattern for all function names:
(This list of examples needs to be fleshed out further.)
Hooks should include a soft namespace by using the commerce_ prefix to avoid conflicts with other contributed modules. For example, Ubercart's hook_order() would become hook_commerce_order() under this convention.
Only form builder functions should end in _form.
5. Automated Testing
We will be using Drupal 7's core SimpleTest testing framework to facilitate code development and maintainability. While not embracing true test-driven development, we will still only be committing code that comes with appropriate function tests.
The Commerce module provides a base class used for creating Drupal Commerce tests. The process is documented in the Specification handbook, Writing SimpleTests for Commerce modules.
Unit testing is under consideration for the core APIs, but a realistic target for now is to mimic Drupal's core test coverage guidelines.
6. Using Core and Contributed Module APIs
Drupal Commerce modules should follow Drupal coding best practices when implementing core APIs, including (but by no means limited to):
- Using the Form API appropriately
- Taking advantage of Drupal's alter hooks
- Exposing their own objects for alteration via drupal_alter()
- Maintaining a strict separation between API functions and the user interface (i.e. not altering data directly in form submit handlers)
- Integrating with the core Entity and Field systems
Our general rule is to integrate with major, well-maintained third party modules where possible. For example, Drupal Commerce modules should depend on Views instead of creating their own table listings. Ctools and Panels integration are under consideration, pending availability on Drupal 7.
7. Drupal Permissions and Access Control
Our problem in the past has been too few permissions, not too many. In general, we're adopting an approach that favors finer-grained permissions over having too few. Every permission should have a description.
This same goal holds true for access control as it pertains to products, orders, customer profiles, etc. While the core modules don't need to anticipate every possible implementation of the Commerce modules, these access systems and others like them should be extensible to allow for finer-grained access. The goal here is to eliminate the need for core patches to allow use cases like peer-to-peer sales.
8. Localization and Variable Strings
In Ubercart we provided numerous configuration options to override interface strings, like the text used on the Add to Cart button. This presented a problem for multilingual sites, as Drupal's localization system can translate string literals but not variables. (For more information, see documentation on the t() function.)
To correct this problem, the ability to override strings via custom settings forms will not be provided by the core modules. Instead, we will instruct administrators to use the String Overrides module (or whatever comparable systems exist).
Furthermore, modules should provide help 'context' to functions used in localization to facilitate accurate translation.
9. Template Files and Theme Functions
Module files and includes should not contain style tags or attributes in any HTML output. Instead, use appropriate IDs and classes with coordinating CSS in the module's .css file(s).
Template files with preprocess functions should be used for nearly all HTML output. In cases where logic cannot be easily abstracted into variables in preprocess functions or when the amount of HTML is very minor, a theme function can be used instead. Use Drupal's core theme functions whenever possible.
10. Separating API from UI
As much as possible, we want to enforce at the core level a strict separation of API components from UI components. At one level, this looks like including both a dc_product and dc_product_ui module, like the core Drupal field and field_ui modules. Since a major goal of the project is to develop a solid core and leave the door open for installation profiles and Feature modules to take care of packaging components, we don't want to make it difficult for developers and site builders to replace default UI components.
To be honest, we could probably use a separate set of user interface guidelines to ensure we have a consistent feel across all the Drupal Commerce modules.
11. Performance Considerations
Code should take advantage of static caching and *_load_multiple() API functions to reduce the amount of queries per page request. The Code module can also be used to audit queries for execution speed. Code should also take advantage of Drupal's file handling abilities in various systems (like the #file property on menu items) and class autoloading capability to minimize the amount of code loaded on any given pageload.
A topic for discussion would be a custom variable storage table or system to reduce the amount of variables stored at the global level. At the very least, modules should consider storing data in custom tables before storing complex module settings in Drupal's variables system.
12. Data Storage
If there's anything we've learned from our past, it's that we want to leave serialized arrays of data in the database behind. We're striving for better data models, and this section should be fleshed out as the project matures.
This heading could be further expanded to address all of our underlying data models and how to best incorporate classes in our modules.