A style guide is a set of standards when writing code that provides uniformity in code style and formatting, i.e. tabs versus spaces or variable and function naming conventions.
Having worked on a code-base with several other developers with each having their own style, it is very cumbersome to know what is going on in any given area of the source code. Following a consistent style helps improve the readability of the source code making it easy to understand and maintain. It makes it a lot easier to browse, locate, and fix bugs.
- Whitespace
- Naming Convention
- Global Variables
- Local Variables
- Keys in an Array
- Custom Properties
- Macros
- Beautiful Syntax
- Opening and Closing UTL Statements
The following sections outlines the practices that I use in all UTL code that I am have authored. Before you begin to use this style guide there is one thing that you have to remember, once you've chosen this style guide it is to be considered law. Link to this document to remind yourself and everyone else involved about your project's commitment to code style consistency, readability, and maintainability.
- Never mix spaces and tabs.
- When beginning a project, before you write any code or do anything, set your IDE to use soft indents (spaces) and set the size to 4.
- Make sure that your IDE is showing invisible spaces. If it doesn't go get another one that supports it. The benefits of this practice are:
- Enforced consistency
- Eliminate end of line whitespace
- Eliminate blank line whitespace
- Commits and diffs are easier to read
You are not a human code minifier/uglifier, do not try to be one. Leave it to the machines, there's plenty of whitespace for everyone.
Bad
bX = util_chkX('ast': this.asset, 'b': true);
Good
bSubscription = util_checkSubscription('oAsset' = this.asset, 'bToggle': true);
If you do require a global variable, it should be in ALL CAPS. In general, if a module is available from the CMS that does the same thing, just use that. If the information you are attempting to store requires computation, a global variable can be used, following these examples:
TEMPLATE_VERSION = '1.0';
IS_TEMPLATE = cms.request.param('template') | defaultval('no') | strbool;
Local variables should be camel cased with Hungarian Notation. Here are a couple of examples:
bCheck
: variable is a boolean ('b')sUrl
: variable is a string ('s')aList
: variable is an array ('a'), also take note that the plural form is used instead of the singular formoPages
: variable is an array of objects ('o'), also take note that the plural form of the object is used instead of the singular form
Array keys should be lowercase with underscores. Here's an example:
aData = [
'key_1': 'This is a string',
'key_2': bCheck
];
Custom properties should be lowercase with underscores. Here are a couple of examples:
product_oauth_key
site_verification
E. Macros
Macros are namespaced according to the application/component that they belong to. For example, a macro that is located in utilities
component would be namespaced as util_getSomething()
.
A. Opening and Closing UTL Statements
Whenever possible, minimize unnecessary whitespace and premature opening/closing of UTL.
Bad
[%
util_doSomething(this.asset);
%]
Bad
[%
util_doSomething(this.asset); %]
Bad
[% util_doSomething(this.asset);
%]
Good
[% util_doSomething(this.asset); %]
Bad
[%
/* Init variables */
aData = [];
bSubscription = util_checkSubscription(this.asset);
util_doSomething(this.asset);
%]
Bad
[% /* Init variables */
aData = [];
bSubscription = util_checkSubscription(this.asset);
util_doSomething(this.asset);
%]
Bad
[%
/* Init variables */
aData = [];
bSubscription = util_checkSubscription(this.asset);
util_doSomething(this.asset); %]
Good
[%
/* Init variables */
aData = [];
bSubscription = util_checkSubscription(this.asset);
util_doSomething(this.asset); %]
B. Comments
Comments are extremely important as they usually describe the intended function of the code snippet, how it should be used, their limitation, and what they accept and return. Do not leave others guessing as to what the purpose of the non-obvious code is.
- Place comments on a new line above the code snippet.
- Multiline is good an is encourage.
- Keep line-length to a sensible maximum, e.g., 80 columns.
- End of line comments are prohibited.
- Use "sentence case" comments and consistent identation.
- JSDoc style is good, read next item.
- Macro declarations must begin with a comment and must contain the following:
@desc
- Describes what the intended function of the macro is@params
- Each parameter must have its own comment@returns
- What the macro returns e.g., an HTML, an array, etc
Bad
/**
* @desc This is a macro that returns the title of an asset.
* @params {Object} oArticle - Takes an article asset.
* @params {Boolean} bfullWidth - Toggles the output depending on setting.
* @returns {HTML} Returns the presentation mode of the article asset in HTML format.
*/
macro asset_displayPresentation(oArticle = [], bfullWidth = false);
end;
Good
/**
* @desc This is a macro that returns the title of an asset.
*
* @params {Object} oArticle - Takes an article asset.
* @params {Boolean} bfullWidth - Toggles the output depending on setting.
*
* @returns {HTML} Returns the presentation mode of the article asset in HTML format.
*/
macro asset_displayPresentation(oArticle = [], bfullWidth = false);
end;
Bad
oImages = asset_relatedImages(this.asset); /* Store all related images to oImages. */
Good
/* Store all related images to oImages. */
oImages = asset_relatedImages(this.asset);
Good
/**
* Loop through each video in oVideos and create a summary card
* and add a related videos card as well.
*
* TODO: Improve card displays when video asset only has one related video.
*/
foreach oVideos as oVideo;
asset_videoSummaryCard(oVideo);
asset_relatedVideos(oVideo);
end;
C. Macro Declarations and Invocations
You've already learned how to namespace UTL macros. Now it's time to learn how to declare and invoke them. Remember, each macro declaration must have a comment above it.
Bad
macro asset_filterImages;
end;
Good
/**
* @desc Insert horizontal div.
*
* @params {None}
*
* @returns {HTML} Return an HTML element with a horizontal line.
*/
macro asset_horizontalDiv();
end;