Chapter 5. Coding Best Practices

In the previous chapters, we learned about Patterns that help us design objects and object elements. Now, we will start adding code to make them work together.

There are Design Patterns about structuring code, but most of the things that we will discuss in this chapter are considered best practices for writing code. Some of them are fundamental basics of object-oriented programming (OOP), such as Encapsulation, although Encapsulation is older than OOP and applies to Microsoft Dynamics NAV as well.

Good coding practices will improve the maintainability of your application, and make it easier to work with a team of developers on the same application, or share the code outside of your team. The latter is very common in the Microsoft Dynamics NAV ecosystem, and starts with Microsoft sharing their code with NAV partners. Partners then again share the code with other partners and also customers. Microsoft Dynamics NAV is a popular ERP system with customers who require a flexible system that can be easily customized.

Coding guidelines

Best practices for writing code in any language start with a set of programming guidelines. This is important for any development team, but crucial for projects that share code with different teams, such as Dynamics NAV.

The programming guidelines for C/AL have hardly changed in 30 years. For Navision Software A/S and later, Microsoft has always had very clear coding guidelines. Throughout the lifecycle of the application, they have been very consistent.

In January 2015, Microsoft released an updated set of guidelines, based on NAV 2015. We will discuss the most important ones.

Code design

The C/AL compiler checks our code for programming errors such as missing object references, and BEGIN/END or REPEAT/UNTIL statements that are wrong.

Code design

The Microsoft Dynamics NAV Development Environment has a limited warning mechanism that only checks the C/AL functions that used to be part of the Classic Client, but no longer worked in the three-tier stack. The examples are BEEP and ENVIRON:

Code design

The code design rules are implemented to add an extra layer of rules that are not enforced by the compiler or generate warnings but when applied, they improve the readability of the code.

Unused Variables

Every variable that is declared global, local, or as a parameter should be used. Unused variables should always be removed by the developer.

By Reference

When assigning a variable as parameter, we have the option to declare the variable as By Reference. When this is applied, changes to the variables also apply to the original, since they share the same memory space. In Microsoft Dynamics NAV, the column is called Var.

By Reference should only be enabled when there is a clear intention of changing the variables.

Match Placeholders

Although C/AL does not support the function with a variable arguments list, there is a limited set of commands that allow the use of multiple parameters. The examples of these functions are MESSAGE, ERROR, and STRSUBSTNO.

When applied, these functions should be called with placeholders in a text string called %1, %2, and more. These placeholders should always match but are not checked at compile time or runtime.

Set Variables

Variables should be used in business logic. If variables are set to a specific value but don't influence the decision tree, they should be removed. For example:

Count := 0;

Vendor.SETFILTER("No.",FilterStr);
IF Vendor.FINDSET THEN
  REPEAT
    "User ID" := USERID;
    "Vendor No." := Vendor."No.";
      IF INSERT THEN
        Count += 1;
  UNTIL Vendor.NEXT = 0;

This is an example of a potential boat anchor anti-pattern. We will discuss more about anti-patterns in Chapter 6, Anti-patterns and Handling Legacy Code.

Variable capacity

Within C/AL there is no compile time to check for a possible overflow scenario. An overflow can occur when a large string is moved in a variable or field with limited storage capacity. The following screenshot shows an error when the length of the string usage is exceeded:

Variable capacity

Since Dynamics NAV version 2013 R2, it is possible to have Text variables with unlimited length, which are mapped to the DotNet string datatype. However, when writing to the database, the maximum length of a string is 250 characters.

The Cyclomatic Complexity

When programming conditions such as IF/ELSE or CASE/OF, and FOR/DO, we add complexity to our code.

The Cyclomatic Complexity is a methodology to calculate the complexity of your C/AL functions. There are multiple officially-documented algorithms, and for Dynamics NAV, we can use Cyclomatic Complexity Three, or CC3.

This means that each IF/ELSE/CASE and FOR condition gets one point. After adding up all the points, a function gets a score. The higher the score, the more complex the function is and therefore, high scores should be avoided.

Tip

You can find more information on Wikipedia at https://en.wikipedia.org/wiki/Cyclomatic_complexity.

Internally, Microsoft programmers working on the product use a threshold of 25 points. I would advise you to use a maximum value of 10.

The function size

Each function that we write in Dynamics NAV, whether it is a built in trigger or manually added function, should not exceed the size of a normal modern computer screen.

When using Microsoft Dynamics NAV 2015 Development Environment on a HD screen, the maximum size of a function should not exceed 40 lines.

Tip

Internally, Microsoft programmers use a threshold of 100 lines. Since a lot of legacy functions in Dynamics NAV have much more than this, another rule internally used at Microsoft is when having to add one line of code to a function that has over 100 lines, two other lines must be moved out, and refactored into a function.

This is considered to be a good methodology for refactoring while avoiding disturbing the upgrade as much as possible.

Using complex data types

To avoid complexity in a single function, there is a maximum threshold of complex data types in C/AL, such as Record, Page, Query, and Codeunit, as shown:

Using complex data types

Tip

I advise a maximum threshold of 10. Internally, Microsoft developers use 30.

Localizability

Since Navision version 2.01, 2.60, and 3.00, the application can be translated independently of the code. This can be done using the Text Constants. They can be either declared globally or locally. The following screenshot show the Text Constant tab:

Localizability

These Text Constants should always be used, unless the text constant is used internally only by the application, as illustrated in the following screenshot:

Localizability

Note

Internally, Microsoft always declares the Text Constant as a global variable.

The naming of the Text Constant should be self-explanatory, indicating if it is used as Message, Error, Question, or something else. Errors and Message constants should end with a period, and a Question should end with a question mark always.

Note

The naming conventions for Text Constants have changed since version 2013. Before this, the constants were numbered.

Date formulas

When hardcoded Date Formulas are used, they should be surrounded by the <> characters. When this is applied, Date Formulas are interpreted in the ENU language, which is the default language in which Dynamics NAV is shipped.

Date formulas

Code readability

When working with multiple developers on a single codebase and sharing software as open code with external partners, using a generic set of rules regarding readability is important from a maintenance perspective.

This includes a long list of small things such as using spaces, comments, white-lines, BEGIN/END, TRUE/FALSE, indentation, and parenthesis:

Spaces

This keeps statements together when they belong together; add spaces only if readability becomes an issue:

IF NOT(Condition) THEN
-NegativeValue
Result := A / B;
Complex := Calculate((A + B) + POWER(C));
Type = Type::Item:
IF FIND('<>=') THEN

Comments

Add this only if required; comments should start directly after the code with a single space:

ERROR(ThisIsWrongErr); // Show Error

White lines

Blank lines should only be used when they improve the readability of the function. Remember that adding a blank line is a good indication to break your function into multiple other functions.

They should never be implemented as the first line of a function, or within a conditional block.

BEGIN/END

Only use a BEGIN and END statement if this is required for the code to function in the desired way. If not required, never implement it.

TRUE/FALSE

Boolean operators require no use of TRUE when positive. When negative, the operators are required; use NOT:

IF ThisShouldReturnTrue THEN
IF NOT SomethingHappened THEN

IF/THEN

The THEN keyword should always be on the same line as the IF keyword, except in a multi-line IF statement. In this case, the THEN keyword should be on a new line:

IF Setup.GET THEN
IF DoSomethingWithALongDescription AND
   AlsoSomethingElseWithAnEvenLongerDescription
THEN

Indentation

Indentation is always two spaces or one tab, following each condition:

IF ThisIsTrue AND
   ThatIsTrue
THEN

The only exception is the multi-line IF statement; in which case, the second statement is indented three spaces:

IF ThisIsTrue THEN
  DoSomethingWithIt;
CASE TRUE OF
  A=B+C:
    GoToSchool;
  K=L/M:
    FlyAway;
  X=Y-Z
    EndTheStory;
END;

Parenthesis

Parentheses should only be used if they cannot be avoided. Functions in C/AL that don't have parameters do not have, and should not be called with empty parentheses ().

When applied consistently, these rules will enable the readability of your application, making it easier to share code with people both within and outside your organization.

Variable naming

Although Microsoft Dynamics NAV Development Environment does not have a built-in data dictionary that is enforced by the compiler, it has very strong naming conventions that have been stable throughout the lifecycle of the product:

Complex datatypes

The name of the complex datatype should be the variable name without removing the special characters and spaces; for example:

Sales-Post: SalesPost

G/L Account: GLAccount

IC G/L Account Import/Export - ICGLAccountImportExport

Fundamental datatypes

Simple datatypes should be self-explaining without adding the datatype to the variable name:

  • Busy: boolean
  • Initials: text
  • NoOfApples: integer
  • Size: integer
  • Amount: decimal
  • Students[1]: array

Function Names

A function name should contain a verb and noun. This indicates the intention of business logic:

  • CalculateVat
  • FormatAddress
  • PrintInvoice
  • IssueReminder

Note

In Microsoft Dynamics NAV 2015, the complex variable names are automatically generated, based on the name of the object and the rules.

Self-explaining

When it is required to have multiple instances of the same complex datatype, they should be explained rather than numbered:

MoveReservationFromSalesToPurchase(ReservationEntrySales)
WITH ReservationEntrySales DO
  TRANSFERFIELDS(ReservationEntryPurchase)

Suffix versus prefix

When working with the C/AL symbol menu or Intellisense, using suffixes is easier than prefixes.

Approved abbreviations

Frequently used variable names in Microsoft Dynamics NAV have approved abbreviations. This can enhance the readability of the code, because we avoid very long variable names.

Note

This list contains the abbreviations used by Microsoft Developers, which is available at https://community.dynamics.com/nav/w/designpatterns/162.suggested-abbreviations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset