JavaScript Style Guide for VMware vRealize Orchestrator [CB10096]

Canonical link: https://cloudblogger.co.in/2022/06/25/vro-javascript-style-guide-cb10096/

Introduction

If you are new to vRealize Orchestrator and want to look for some code style references, this post can help you with some basic guidelines to write the perfect JavaScript code in your vRO Workflows and Actions. These are industry standards are preferred by almost every industry. Keep in mind that this guide won’t help you with writing your first vRO code, instead can be used as style reference while writing your vRO JavaScript code. In short, helps you to achieve 7 things:

  1. Code that’s easier to read
  2. Provide clear guidelines when writing code
  3. Predictable variable and function names
  4. Improve team’s efficiency to collaborate
  5. Saves time and makes communication between teams more efficient
  6. Reduces redundant work
  7. Enables each team member to share the same clear messaging with potential customers

vRealize Orchestrator uses JavaScript 1.7 as its classic language of choice for all the automation tasks that gets executed inside Mozilla Rhino 1.7R4 Engine along with some limitations listed here. This style guide is a list of dos and don’ts for JavaScript programs that you write inside your vRO. Let’s have a look.

JavaScript Language Rules

var

Always declare variables with var, unless it’s a const.

Constants

  • Use NAMES_LIKE_THIS for constant values, that start with const keyword.

Semicolons

Always use semicolons.

Why?

JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence. In each of these examples, a function declaration or object or array literal is used inside a statement. The closing brackets are not enough to signal the end of the statement. JavaScript never ends a statement if the next token is an infix or bracket operator.

This has really surprised people, so make sure your assignments end with semicolons.

Clarification: Semicolons and functions

Semicolons should be included at the end of function expressions, but not at the end of function declarations. The distinction is best illustrated with an example:

var foo = function() {
return true;
}; // semicolon here.
function foo() {
return true;
} // no semicolon here.

Nested functions

Yes

Nested functions can be very useful, for example in the creation of continuations and for the task of hiding helper functions. Feel free to use them.

Function Declarations Within Blocks

No

Do not do this:

if (x) {
function foo() {}
}

ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable initialized with a Function Expression to define a function within a block:

if (x) {
var foo = function() {};
}

Exceptions

Yes

You basically can’t avoid exceptions. Go for it.

Custom exceptions

Yes

Sometimes, It becomes really hard to troubleshoot inside vRealize Orchestrator. But, custom exceptions can certainly help you there. Feel free to use custom exceptions when appropriate.

Standards features

Always preferred over non-standards features

For maximum portability and compatibility, always prefer standards features over non-standards features (e.g., string.charAt(3) over string[3].

Wrapper objects for primitive types

No

There’s no reason to use wrapper objects for primitive types, plus they’re dangerous:

var x = new Boolean(false);
if (x) {
alert('hi'); // Shows 'hi'.
}

Don’t do it!

However type casting is fine.

var x = Boolean(0);
if (x) {
alert('hi'); // This will never be alerted.
}
typeof Boolean(0) == 'boolean';
typeof new Boolean(0) == 'object';

This is very useful for casting things to number, string and boolean.

delete

Prefer this.foo = null.

var dispose = function() {
this.property_ = null;
};

Instead of:

var dispose = function() {
delete this.property_;
};

Changing the number of properties on an object is much slower than reassigning the values. The delete keyword should be avoided except when it is necessary to remove a property from an object’s iterated list of keys, or to change the result of if (key in obj).

JSON.parse()

You can always use JSON and read the result using JSON.parse().

var userInfo = JSON.parse(feed);
var email = userInfo['email'];

With JSON.parse, invalid JSON will cause an exception to be thrown.

with() {}

No

Using with clouds the semantics of your program. Because the object of the with can have properties that collide with local variables, it can drastically change the meaning of your program. For example, what does this do?

with (foo) {
var x = 3;
return x;
}

Answer: anything. The local variable x could be clobbered by a property of foo and perhaps it even has a setter, in which case assigning 3 could cause lots of other code to execute. Don’t use with.

this

Only in object constructors, methods, and in setting up closures

The semantics of this can be tricky. At times it refers to the global object (in most places), the scope of the caller (in eval), a newly created object (in a constructor), or some other object (if function was call()ed or apply()ed).

Because this is so easy to get wrong, limit its use to those places where it is required:

  • in constructors
  • in methods of objects (including in the creation of closures)

for-in loop

Only for iterating over keys in an object/map/hash

for-in loops are often incorrectly used to loop over the elements in an Array. This is however very error prone because it does not loop from 0 to length - 1 but over all the present keys in the object and its prototype chain. Here are a few cases where it fails:

function printArray(arr) {
for (var key in arr) {
print(arr[key]);
}
}
printArray([0,1,2,3]); // This works.var a = new Array(10);
printArray(a); // This is wrong.
a = [0,1,2,3];
a.buhu = 'wine';
printArray(a); // This is wrong again.
a = new Array;
a[3] = 3;
printArray(a); // This is wrong again.

Always use normal for loops when using arrays.

function printArray(arr) {
var l = arr.length;
for (var i = 0; i < l; i++) {
print(arr[i]);
}
}

Multiline string literals

No

Do not do this:

var myString = 'A rather long string of English text, an error message \
actually that just keeps going and going -- an error \
message to make the Energizer bunny blush (right through \
those Schwarzenegger shades)! Where was I? Oh yes, \
you\'ve got an error and all the extraneous whitespace is \
just gravy. Have a nice day.';

The whitespace at the beginning of each line can’t be safely stripped at compile time; whitespace after the slash will result in tricky errors.

Use string concatenation instead:

var myString = 'A rather long string of English text, an error message ' +
'actually that just keeps going and going -- an error ' +
'message to make the Energizer bunny blush (right through ' +
'those Schwarzenegger shades)! Where was I? Oh yes, ' +
'you\'ve got an error and all the extraneous whitespace is ' +
'just gravy. Have a nice day.';

Array and Object literals

Yes

Use Array and Object literals instead of Array and Object constructors.

Array constructors are error-prone due to their arguments.

// Length is 3.
var a1 = new Array(x1, x2, x3);
// Length is 2.
var a2 = new Array(x1, x2);
// If x1 is a number and it is a natural number the length will be x1.
// If x1 is a number but not a natural number this will throw an exception.
// Otherwise the array will have one element with x1 as its value.
var a3 = new Array(x1);
// Length is 0.
var a4 = new Array();

Because of this, if someone changes the code to pass 1 argument instead of 2 arguments, the array might not have the expected length.

To avoid these kinds of weird cases, always use the more readable array literal.

var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];

Object constructors don’t have the same problems, but for readability and consistency object literals should be used.

var o = new Object();var o2 = new Object();
o2.a = 0;
o2.b = 1;
o2.c = 2;
o2['strange key'] = 3;

Should be written as:

var o = {};var o2 = {
a: 0,
b: 1,
c: 2,
'strange key': 3
};

Modifying prototypes of built-in objects

Modifying builtins like Object.prototype and Array.prototype are strictly forbidden in vRO. Doing so will result in an error.

JavaScript Style Rules

Naming

In general, use functionNamesLikeThis, variableNamesLikeThis, EnumNamesLikeThis, CONSTANT_VALUES_LIKE_THIS.

Method and function parameter

Optional function arguments start with opt_.

Getters and Setters

EcmaScript 5 getters and setters for properties are discouraged. However, if they are used, then getters must not change observable state.

/**
* WRONG -- Do NOT do this.
*/
var foo = { get next() { return this.nextId++; } };

Accessor functions

Getters and setters methods for properties are not required. However, if they are used, then getters must be named getFoo() and setters must be named setFoo(value). (For boolean getters, isFoo() is also acceptable, and often sounds more natural.)

Deferred initialization

OK

It isn’t always possible to initialize variables at the point of declaration, so deferred initialization is fine.

Code formatting

Curly Braces

Because of implicit semicolon insertion, always start your curly braces on the same line as whatever they’re opening. For example:

if (something) {
// ...
} else {
// ...
}

Array and Object Initializers

Single-line array and object initializers are allowed when they fit on a line:

var arr = [1, 2, 3];  // No space after [ or before ].
var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.

Multiline array initializers and object initializers are indented 2 spaces, with the braces on their own line, just like blocks.

Indenting wrapped lines

Except for array literals, object literals, and anonymous functions, all wrapped lines should be indented either left-aligned to a sibling expression above, or four spaces (not two spaces) deeper than a parent expression (where “sibling” and “parent” refer to parenthesis nesting level).

someWonderfulHtml = '' +
getEvenMoreHtml(someReallyInterestingValues, moreValues,
evenMoreParams, 'a duck', true, 72,
slightlyMoreMonkeys(0xfff)) +
'';
thisIsAVeryLongVariableName =
hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();
thisIsAVeryLongVariableName = siblingOne + siblingTwo + siblingThree +
siblingFour + siblingFive + siblingSix + siblingSeven +
moreSiblingExpressions + allAtTheSameIndentationLevel;
thisIsAVeryLongVariableName = operandOne + operandTwo + operandThree +
operandFour + operandFive * (
aNestedChildExpression + shouldBeIndentedMore);
someValue = this.foo(
shortArg,
'Some really long string arg - this is a pretty common case, actually.',
shorty2,
this.bar());
if (searchableCollection(allYourStuff).contains(theStuffYouWant) &&
!ambientNotification.isActive() && (client.isAmbientSupported() ||
client.alwaysTryAmbientAnyways())) {
ambientNotification.activate();
}

Blank lines

Use newlines to group logically related pieces of code. For example:

doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);
nowDoSomethingWith(y);andNowWith(z);

Binary and Ternary Operators

Always put the operator on the preceding line. Otherwise, line breaks and indentation follow the same rules as in other Google style guides. This operator placement was initially agreed upon out of concerns about automatic semicolon insertion. In fact, semicolon insertion cannot happen before a binary operator, but new code should stick to this style for consistency.

var x = a ? b : c;  // All on one line if it will fit.// Indentation +4 is OK.
var y = a ?
longButSimpleOperandB : longButSimpleOperandC;
// Indenting to the line position of the first operand is also OK.
var z = a ?
moreComplicatedB :
moreComplicatedC;

This includes the dot operator.

var x = foo.bar().
doSomething().
doSomethingElse();

Parentheses

Only where required

Use sparingly and in general only where required by the syntax and semantics.

Never use parentheses for unary operators such as delete, typeof and void or after keywords such as return, throw as well as others (case, in or new).

Strings

For consistency single-quotes (‘) are preferred to double-quotes (“). This is helpful when creating strings that include HTML:

var msg = 'This is some message';

Comments

Use JSDoc if you want.

Tips and Tricks

JavaScript tidbits

True and False Boolean Expressions

The following are all false in boolean expressions:

  • null
  • undefined
  • '' the empty string
  • 0 the number

But be careful, because these are all true:

  • '0' the string
  • [] the empty array
  • {} the empty object

This means that instead of this:

while (x != null) {

you can write this shorter code (as long as you don’t expect x to be 0, or the empty string, or false):

while (x) {

And if you want to check a string to see if it is null or empty, you could do this:

if (y != null && y != '') {

But this is shorter and nicer:

if (y) {

Caution: There are many unintuitive things about boolean expressions. Here are some of them:

  • Boolean('0') == true
    '0' != true
  • 0 != null
    0 == []
    0 == false
  • Boolean(null) == false
    null != true
    null != false
  • Boolean(undefined) == false
    undefined != true
    undefined != false
  • Boolean([]) == true
    [] != true
    [] == false
  • Boolean({}) == true
    {} != true
    {} != false

Conditional (Ternary) Operator (?:)

Instead of this:

if (val) {
return foo();
} else {
return bar();
}

you can write this:

return val ? foo() : bar();

&& and ||

These binary boolean operators are short-circuited, and evaluate to the last evaluated term.

“||” has been called the ‘default’ operator, because instead of writing this:

function foo(opt_win) {
var win;
if (opt_win) {
win = opt_win;
} else {
win = window;
}
// ...
}

you can write this:

function foo(opt_win) {
var win = opt_win || window;
// ...
}

“&&” is also useful for shortening code. For instance, instead of this:

if (node) {
if (node.kids) {
if (node.kids[index]) {
foo(node.kids[index]);
}
}
}

you could do this:

if (node && node.kids && node.kids[index]) {
foo(node.kids[index]);
}

or this:

var kid = node && node.kids && node.kids[index];
if (kid) {
foo(kid);
}

vRO Element Naming Rules

Actions

should be named like actionNameLikeThis and must start with a verb like get, create, set, delete, fetch, put, call, and so forth. Then, describe what the action is doing.

Workflows

should be a short statement which briefly tells what the Workflow is doing.

Action Modules

naming should be similar to com.[company].library.[component].[interface].[parent group].[child group]

Where

[company] = company name as a single word

library — Optional

[component] = Examples are: NSX, vCAC, Infoblox, Activedirectory, Zerto.

[interface] — Optional — Examples are: REST, SOAP, PS. Omit this if you are using the vcenter or vcac plugins.

[parent group] — Optional — Parent group i.e. Edges, Entities, Networks, vm.

[child group] — Optional — A group containing collections of child actions that relate to the parent group.

Resource Elements and Configuration Elements

Resource element’s name is actually the filename at time of uploading. It should be clear enough.

Configuration Elements are used for various purposes like Password Containers (Credential store), Environment specific variables, location information, or can be a used as global variables get\set by various workflows. Hence, the name should define its purpose.

Attributes inside Configuration Elements

attribute’s name should have some suffix like DC_ or CONF_. when mapped with variable inside workflow, we should keep that variable’s name same as well. While using it in scripts, pass its value to another variable.

In this example, a attribute DC_EAST_LOCATION inside a Configuration element (named Location Variables) is mapped to a variable DC_EAST_LOCATION in a workflow and this variable is being used in a scriptable task.

//CORRECT WAY
var location = DC_EAST_LOCATION; //pass value to a local variable
System.log("Current location: " + location);
//WRONG WAY
System.log("Current location: " + DC_EAST_LOCATION);

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store