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

NameDefault ValueDescriptionMultivalued
allowIffalseAllow assignment within the conditional expression of an if statementno
allowForfalseAllow assignment within the conditional expression of a for statementno
allowWhilefalseAllow assignment within the conditional expression of a while statementno
allowTernaryfalseAllow assignment within the conditional expression of a ternary operatorno
allowTernaryResultsfalseAllow assignment within the result expressions of a ternary operatorno
allowIncrementDecrementfalseAllow increment or decrement operators within the conditional expression of an if, for, or while statementno

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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode 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

NameDefault ValueDescriptionMultivalued
rhinoLanguageVersionES6Specifies the Rhino Language Version to use for parsing. Defaults to ES6.no
recordingLocalJsDocCommentstrueSpecifies that JsDoc comments are produced in the AST.no
recordingCommentstrueSpecifies 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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode 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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode 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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode 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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode 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


NameDefault ValueDescription
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
checkParameterstrueCheck constructor and method parameter variables
checkLocalstrueCheck local variables
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode Climate Block Highlighting
checkMemberstrueCheck 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

NameDefault ValueDescription
cc_categories[Style]Code Climate Categories
cc_remediation_points_multiplier1Code Climate Remediation Points multiplier
cc_block_highlightingfalseCode Climate Block Highlighting

What's here

Related content

 PMD: best practices




Last modified on Jul 14, 2020