Apex code style best practices
This article is based on the PMD documentation article. See the original article on the PMD site: PMD: best practices.
Best practices which enforce a specific coding style.
AssignmentInOperand
Avoid assignments in operands; this can make code more complicated and harder to read. This is sometime indicative of the bug where the assignment operator ‘=’ was used instead of the equality operator ‘==’.
This rule is defined by the following XPath expression:
//IfStatement[$allowIf = false()]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]] | //WhileLoop[$allowWhile = false()]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]] | //DoLoop[$allowWhile = false()]/child::node()[2]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]] | //ForLoop[$allowFor = false()]/child::node()[2]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]] | //ConditionalExpression[$allowTernary = false()]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]] | //ConditionalExpression[$allowTernaryResults = false()]/child::node()[position() = 2 or position() = 3]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = false() and (@Image = "--" or @Image = "++")]]
Example
var x = 2; // Bad if ((x = getX()) == 3) { alert('3!'); } function getX() { return 3; }
Properties
Name | Default Value | Description | Multivalued |
---|---|---|---|
allowIf | false | Allow assignment within the conditional expression of an if statement | no |
allowFor | false | Allow assignment within the conditional expression of a for statement | no |
allowWhile | false | Allow assignment within the conditional expression of a while statement | no |
allowTernary | false | Allow assignment within the conditional expression of a ternary operator | no |
allowTernaryResults | false | Allow assignment within the result expressions of a ternary operator | no |
allowIncrementDecrement | false | Allow increment or decrement operators within the conditional expression of an if, for, or while statement | no |
AvoidWithStatement
Avoid using with - it’s bad news
This rule is defined by the following XPath expression:
//WithStatement
Example
with (object) { property = 3; // Might be on object, might be on window: who knows. }
ClassNamingConventions
Class names should always begin with an upper case character.
This rule is defined by the following Java class:
net.sourceforge.pmd.lang.apex.rule.codestyle.ClassNamingConventionsRule
Example
public class Foo {}
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
ConsistentReturn
ECMAScript does provide for return types on functions, and therefore there is no solid rule as to their usage. However, when a function does use returns they should all have a value, or all with no value. Mixed return usage is likely a bug, or at best poor style.
This rule is defined by the following Java class:
net.sourceforge.pmd.lang.ecmascript.rule.bestpractices.ConsistentReturnRule
Example
// Ok function foo() { if (condition1) { return true; } return false; } // Bad function bar() { if (condition1) { return; } return false; }
Parameters
Name | Default Value | Description | Multivalued |
---|---|---|---|
rhinoLanguageVersion | ES6 | Specifies the Rhino Language Version to use for parsing. Defaults to ES6. | no |
recordingLocalJsDocComments | true | Specifies that JsDoc comments are produced in the AST. | no |
recordingComments | true | Specifies that comments are produced in the AST. | no |
ForLoopsMustUseBraces
Avoid using ‘for’ statements without using surrounding braces. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
//ForLoopStatement/BlockStatement[@CurlyBrace='false']
|
//ForEachStatement/BlockStatement[@CurlyBrace='false']
Example
for (int i = 0; i < 42; i++) // not recommended foo(); for (int i = 0; i < 42; i++) { // preferred approach foo(); }
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
GlobalVariable
This rule helps to avoid using accidently global variables by simply missing the "var" declaration. Global variables can lead to side-effects that are hard to debug.
This rule is defined by the following XPath expression:
//Assignment[Name/@GlobalName = true()]
Example
function(arg) { notDeclaredVariable = 1; // this will create a global variable and trigger the rule var someVar = 1; // this is a local variable, that's ok window.otherGlobal = 2; // this will not trigger the rule, although it is a global variable. }
IfElseStmtsMustUseBraces
Avoid using if..else statements without using surrounding braces. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
//IfBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
|
//IfElseBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
Example
// this is OK if (foo) x++; // but this is not if (foo) x = x+1; else x = x-1;
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
IfStmtsMustUseBraces
Avoid using if statements without using braces to surround the code block. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
//IfBlockStatement/BlockStatement[@CurlyBrace='false']
Example
if (foo) // not recommended x++; if (foo) { // preferred approach x++; }
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
MethodNamingConventions
Method names should always begin with a lower case character, and should not contain underscores.
This rule is defined by the following Java class:
net.sourceforge.pmd.lang.apex.rule.codestyle.MethodNamingConventionsRule
Example
public class Foo { public void fooStuff() { } }
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
NoElseReturn
The else block in a if-else-construct is unnecessary if the if
block contains a return. Then the content of the else block can be put outside.
See also: http://eslint.org/docs/rules/no-else-return
This rule is defined by the following XPath expression:
//IfStatement[@Else=true()][Scope[1]/ReturnStatement]
Example
// Bad: if (x) { return y; } else { return z; } // Good: if (x) { return y; } return z;
UnnecessaryBlock
An unnecessary Block is present. Such Blocks are often used in other languages to introduce a new variable scope. Blocks do not behave like this in ECMAScipt, and using them can be misleading. Considering removing this unnecessary Block.
This rule is defined by the following XPath expression:
//Block[not(parent::FunctionNode or parent::IfStatement or parent::ForLoop or parent::ForInLoop or parent::WhileLoop or parent::DoLoop or parent::TryStatement or parent::CatchClause)] | //Scope[not(parent::FunctionNode or parent::IfStatement or parent::ForLoop or parent::ForInLoop or parent::WhileLoop or parent::DoLoop or parent::TryStatement or parent::CatchClause)]
Example
if (foo) { // Ok } if (bar) { { // Bad } }
UnnecessaryParentheses
Unnecessary parentheses should be removed.
This rule is defined by the following XPath expression:
//ParenthesizedExpression/ParenthesizedExpression
Example
var x = 1; // Ok var y = (1 + 1); // Ok var z = ((1 + 1)); // Bad
UnreachableCode
A ‘return’, ‘break’, ‘continue’, or ‘throw’ statement should be the last in a block. Statements after these will never execute. This is a bug, or extremely poor style.
This rule is defined by the following XPath expression:
//ReturnStatement[following-sibling::node()] | //ContinueStatement[following-sibling::node()] | //BreakStatement[following-sibling::node()] | //ThrowStatement[following-sibling::node()]
Example
// Ok function foo() { return 1; } // Bad function bar() { var x = 1; return x; x = 2; }
UseBaseWithParseInt
This rule checks for usages of parseInt. While the second parameter is optional and usually defaults to 10 (base/radix is 10 for a decimal number), different implementations may behave differently. It also improves readability, if the base is given.
See also: parseInt()
This rule is defined by the following XPath expression:
//FunctionCall/Name[ @Image = 'parseInt' and count(../*) < 3 ]
Example
parseInt("010"); // unclear, could be interpreted as 10 or 7 (with a base of 7) parseInt("10", 10); // good
VariableNamingConventions
A variable naming conventions rule - customize this to your liking. Currently, it checks for final variables that should be fully capitalized and non-final variables that should not include underscores.
This rule is defined by the following Java class:
net.sourceforge.pmd.lang.apex.rule.codestyle.VariableNamingConventionsRule
Example
public class Foo { public static final Integer MY_NUM = 0; public String myTest = ''; DataModule dmTest = new DataModule(); }
Properties
Name | Default Value | Description |
---|---|---|
parameterSuffix | [] | Method parameter variable suffixes |
parameterPrefix | [] | Method parameter variable prefixes |
localSuffix | [] | Local variable suffixes |
localPrefix | [] | Local variable prefixes |
memberSuffix | [] | Member variable suffixes |
memberPrefix | [] | Member variable prefixes |
staticSuffix | [] | Static variable suffixes |
staticPrefix | [] | Static variable prefixes |
checkParameters | true | Check constructor and method parameter variables |
checkLocals | true | Check local variables |
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |
checkMembers | true | Check member variables |
WhileLoopsMustUseBraces
Avoid using ‘while’ statements without using braces to surround the code block. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
//WhileLoopStatement/BlockStatement[@CurlyBrace='false']
Example
while (true) // not recommended x++; while (true) { // preferred approach x++; }
Properties
Name | Default Value | Description |
---|---|---|
cc_categories | [Style] | Code Climate Categories |
cc_remediation_points_multiplier | 1 | Code Climate Remediation Points multiplier |
cc_block_highlighting | false | Code Climate Block Highlighting |