Readability, maintainability

Topics:

  1. No unused declarations/objects or useless code [++]
  2. No "magic numbers" [+]
  3. No multiple use of the same names [+]
  4. Same notation in declaration and implementation [+]
  5. Avoid empty statements (;) [+]
  6. Each assignment in separate line of code [+]

No unused declarations/objects or useless code

A project should contain no unexecutable paths, no "dead" (unnecessary) code, and no unused type declarations or variables.

Unused program elements in a project quickly lead to confusing code structures. During maintenance and extensions, the readability of the code can be greatly enhanced if the project only contains program elements that are actually used.

Static Analysis:

Verify using the following Static Analysis rules:

The rule SA0033 is also included in the license-free variant Static Analysis Light.

Also note the possibility to disable Static Analysis rules and naming conventions locally via pragma or attribute for checked locations where a specific rule/naming convention should no longer be reported (see also: chapter Pragmas and Attributes in TE1200 PLC Static Analysis). Ideally, you should comment on local deactivation with an appropriate explanation.

For example, you can disable the rule SA0002 for intended empty bodies of function blocks locally for this FB body by {analysis -2}.

No unexecutable paths

Negative sample:

IF FALSE THEN                   // NON COMPLIANT
    F_DoSomethingUsefulHere();  // will never be executed
END_IF

Positive sample:

IF bTest THEN                   // COMPLIANT
    F_DoSomethingUsefulHere();  // it's just a sample
END_IF

No "Dead" (unnecessary) code

Negative sample:

FUNCTION F_Sample_neg : INT
VAR_INPUT 
    nA       : INT;             // Variable a in term y = a*a + b
    nB       : INT;             // Variable b in term y = a*a + b
END_VAR
VAR
    nTemp    : INT;             // Used for temporary calculation of a*a
END_VAR
nTemp        := nA * nA;        // NON COMPLIANT: nTemp will not be used later
F_Sample_neg := nA * nA + nB;

Positive sample:

FUNCTION F_Sample_pos : INT
VAR_INPUT 
    nA       : INT;             // Variable a in term y = a*a + b
    nB       : INT;             // Variable b in term y = a*a + b
END_VAR
F_Sample_pos := nA * nA + nB;   // COMPLIANT: no dead code in this sample

No "magic numbers"

Do not use "magic numbers".

Alternatively, constants or other fixed values can be used for comparisons or assignments. Texts such as output or comparison texts should be stored in constants, for example, and not defined directly in the source code.

Note also the following topic of the programming conventions:

Negative sample:

PROGRAM Sample_neg 
VAR 
    nValue   : INT;   // Sample INT-variable that is used for comparison 
    bValueOk : BOOL;  // Indicates if the value of sample INT-variable is OK 
END_VAR 
// NON COMPLIANT: A "magic value" is used for comparison 
bValueOk := (nValue = 125);

Positive sample:

PROGRAM Sample_pos 
VAR 
    nValue    : INT;            // Sample INT-variable that is used for comparison 
    bValueOk  : BOOL;           // Indicates if the value of sample INT-variable is OK 
END_VAR 
VAR CONSTANT 
    cValueOk  : INT   := 125;   // Used to validate the sample INT-variable 
END_VAR 
// COMPLIANT: A constant variable is used for comparison 
bValueOk := (nValue = cValueOk);

No multiple use of the same names

Avoid using the same names more than once. This includes the following cases:

Static Analysis:

Verify using the following Static Analysis rules:

The rule SA0027 is also included in the license-free variant Static Analysis Light.

Same notation in declaration and implementation

For reasons of uniformity, readability and maintainability, you should use the same notation of program elements and variables in the declaration and in the implementation.

Static Analysis:

Check with the help of Static Analysis rule:

General program elements for the following samples:

FUNCTION F_Sample

Negative sample:

PROGRAM Sample
VAR
    bTest  : BOOL;
END_VAR
--------------------------
IF btest THEN
    f_Sample();
END_IF

Positive sample:

PROGRAM Sample
VAR
    bTest  : BOOL;
END_VAR
--------------------------
IF bTest THEN
    F_Sample();
END_IF

Avoid empty statements (;)

Avoid empty statements (;) so as not to expand the code unnecessarily. If an empty statement is absolutely necessary to clarify a particular case, the empty statement should be on a separate line. Additionally, you should comment why this program branch is empty.

Static Analysis:

Check with the help of Static Analysis rule:

General program elements for the following samples:

PROGRAM Sample
VAR
    nTest : INT := 10;  // Test value used in sample
END_VAR

Negative sample:

IF nTest = 10 THEN
    ;                   // NON COMPLIANT without a useful comment
ELSE
    nTest := 10;
END_IF

Positive sample:

IF nTest = 10 THEN
    ;                   // COMPLIANT with a comment: In case that nTest is equal to 10, no action is needed. This status is intended.
ELSE
    nTest := 10;
END_IF

Each assignment in separate line of code

Each assignment should be in a separate line of code. Thus, assignments should not be in conditions and allocation operators should not contain subexpressions.

Static Analysis:

Check with the help of Static Analysis rule:

General program elements for the following samples:

PROGRAM Sample
VAR
    bVar1 : BOOL;
    bVar2 : BOOL;
    nA    : INT;
    nB    : INT;
    nC    : INT;
END_VAR

Negative sample:

// NON COMPLIANT: assignment in condition
IF bVar1 := bVar2 THEN
    DoSomething();
END_IF
 
// NON COMPLIANT: more than one assignment in a single line
nA := nC * (nB := nC + nC);

Positive sample:

IF bVar1 = bVar2 THEN
    DoSomething();
END_IF
 
nB := nC + nC;
nA := nC * nB;