formatted nav patterns 2 to 4

This commit is contained in:
christianbraeunlich 2022-02-05 19:44:44 +01:00
parent 2fad891a77
commit f1f4aab1d7
55 changed files with 788 additions and 506 deletions

View file

@ -18,8 +18,6 @@ If the table is empty, it means that either the upgrade has run, or there was no
**Solution:** if using an upgrade table, always validate that the table contains data before doing anything. **Solution:** if using an upgrade table, always validate that the table contains data before doing anything.
****
### Upgrade code, can it be rerun safely? ### Upgrade code, can it be rerun safely?
**Problem**: if the upgrade code is not written in a way that makes it runnable twice ([idempotent][anchor1]), then several failures can happen, including something as critical as data corruption. **Problem**: if the upgrade code is not written in a way that makes it runnable twice ([idempotent][anchor1]), then several failures can happen, including something as critical as data corruption.

View file

@ -8,18 +8,18 @@ Unintentional value changes might propagate. Also, it might lead people to belie
Bad code Bad code
LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text\[250\]); LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text[250]);
BEGIN BEGIN
Text := GetMessageText; Text := GetMessageText;
IF (Text <\> '') AND GenJnlLineInserted THEN IF (Text <> '') AND GenJnlLineInserted THEN
MESSAGE(Text); MESSAGE(Text);
END; END;
Good code Good code
LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text\[250\]); LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text[250]);
BEGIN BEGIN
Text := GetMessageText; Text := GetMessageText;
IF (Text <\> '') AND GenJnlLineInserted THEN IF (Text <> '') AND GenJnlLineInserted THEN
MESSAGE(Text); MESSAGE(Text);
END; END;

View file

@ -6,7 +6,7 @@ Do not write functions that have high class coupling. This makes the code hard t
Bad code Bad code
Any procedure / trigger that has class coupling of \> 30 Any procedure / trigger that has class coupling of > 30

View file

@ -6,7 +6,7 @@ Do not write functions that have high cyclomatic complexity. This makes the code
Bad code Bad code
Any procedure / trigger that has a cyclomatic complexity \> 25, using the CC3 version mentioned in [this article][anchor0]. Any procedure / trigger that has a cyclomatic complexity > 25, using the CC3 version mentioned in [this article][anchor0].

View file

@ -7,23 +7,23 @@ FINDSET, FIND('+') or FIND('-') should only be used when NEXT is used and vice v
Bad code Bad code
IF Cust.FIND('-') THEN IF Cust.FIND('-') THEN
ERROR(CustIsBlockErr) ERROR(CustIsBlockErr)
Good code Good code
IF Cust.FINDFIRST THEN IF Cust.FINDFIRST THEN
ERROR(CustIsBlockErr) ERROR(CustIsBlockErr)
Bad code Bad code
IF Cust.FINDFIRST THEN IF Cust.FINDFIRST THEN
REPEAT REPEAT
... ...
UNTIL Cust.NEXT = 0; UNTIL Cust.NEXT = 0;
Good code Good code
IF Cust.FINDSET THEN IF Cust.FINDSET THEN
REPEAT REPEAT
... ...
UNTIL Cust.NEXT = 0; UNTIL Cust.NEXT = 0;

View file

@ -8,25 +8,25 @@ Bad code
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39); PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
VAR VAR
Pegging@1001 : Boolean; Pegging@1001 : Boolean;
BEGIN BEGIN
IF Pegging THEN IF Pegging THEN
CurrQuantity := CurrentPurchLine."Quantity (Base)" CurrQuantity := CurrentPurchLine."Quantity (Base)"
ELSE ELSE
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)"; CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
END; END;
Good code Good code
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39); PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
VAR VAR
Pegging@1001 : Boolean; Pegging@1001 : Boolean;
BEGIN BEGIN
Pegging := IsPegging(CurrentPurchLine); Pegging := IsPegging(CurrentPurchLine);
IF Pegging THEN IF Pegging THEN
CurrQuantity := CurrentPurchLine."Quantity (Base)" CurrQuantity := CurrentPurchLine."Quantity (Base)"
ELSE ELSE
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)"; CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
END; END;
Bad code Bad code
@ -34,16 +34,16 @@ Bad code
// In the example below, the function will always return FALSE. // In the example below, the function will always return FALSE.
PROCEDURE GetItemsToPlan@22() : Boolean; PROCEDURE GetItemsToPlan@22() : Boolean;
BEGIN BEGIN
SETRANGE("Document Type","Document Type"::Order); SETRANGE("Document Type","Document Type"::Order);
... ...
FINDSET FINDSET
END; END;
Good code Good code
PROCEDURE GetItemsToPlan@22() : Boolean; PROCEDURE GetItemsToPlan@22() : Boolean;
BEGIN BEGIN
SETRANGE("Document Type","Document Type"::Order); SETRANGE("Document Type","Document Type"::Order);
... ...
EXIT(FINDSET) EXIT(FINDSET)
END; END;

View file

@ -12,11 +12,11 @@ Bad code
Good code Good code
Any procedure / trigger that has a maintainability index \>= 20\. Any procedure / trigger that has a maintainability index >= 20\.
The Maintainability Index is computed as a function: The Maintainability Index is computed as a function:
- Lines Of Code (inverse proportional) - Lines Of Code (inverse proportional)
- the Halstead Volume - the Halstead Volume
- Cyclomatic Complexity (inverse proportional). - Cyclomatic Complexity (inverse proportional).
More info More info
@ -25,7 +25,7 @@ More info
Bad code Bad code
Any procedure / trigger that is \> 100 lines of code Any procedure / trigger that is > 100 lines of code

View file

@ -4,8 +4,6 @@ weight = 920
+++ +++
The number of parameters passed to a string must match the placeholders. The number of parameters passed to a string must match the placeholders.
****
Bad code Bad code
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.'; CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
@ -18,7 +16,7 @@ Good code
... ...
ERROR(CannotDeleteLineErr); ERROR(CannotDeleteLineErr);
###
Bad code Bad code

View file

@ -8,14 +8,14 @@ Bad code
LOCAL PROCEDURE Code@1(); LOCAL PROCEDURE Code@1();
VAR VAR
CAJnlPostBatch@1001 : Codeunit 1103; CAJnlPostBatch@1001 : Codeunit 1103;
BEGIN BEGIN
CAJnlPostBatch.Run(CostJnlLine); CAJnlPostBatch.Run(CostJnlLine);
END; END;
Good code Good code
LOCAL PROCEDURE Code@1(); LOCAL PROCEDURE Code@1();
BEGIN BEGIN
CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine); CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine);
END; END;

View file

@ -8,18 +8,18 @@ It affects code readability and can lead to wrong assumptions.
Bad code Bad code
IF Type <\> Type::FIELD THEN BEGIN IF Type <> Type::FIELD THEN BEGIN
... ...
ERROR(...); ERROR(...);
RecRef.CLOSE; RecRef.CLOSE;
END; END;
Good code Good code
IF Type <\> Type::FIELD THEN BEGIN IF Type <> Type::FIELD THEN BEGIN
... ...
RecRef.CLOSE; RecRef.CLOSE;
ERROR(...); ERROR(...);
END; END;

View file

@ -6,33 +6,33 @@ The value assigned to a variable must be used. Else the variable is not necessar
Bad code Bad code
PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]); PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
VAR VAR
Vendor@1001 : Record 23; Vendor@1001 : Record 23;
Count@1002 : Integer; Count@1002 : Integer;
BEGIN BEGIN
Count := 0; Count := 0;
Vendor.SETFILTER("No.",FilterStr); Vendor.SETFILTER("No.",FilterStr);
IF Vendor.FINDSET THEN IF Vendor.FINDSET THEN
REPEAT REPEAT
"User ID" := USERID; "User ID" := USERID;
"Vendor No." := Vendor."No."; "Vendor No." := Vendor."No.";
IF INSERT THEN IF INSERT THEN
Count += 1; Count += 1;
UNTIL Vendor.NEXT = 0; UNTIL Vendor.NEXT = 0;
END; END;
Good code Good code
PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]); PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
VAR VAR
Vendor@1001 : Record 23; Vendor@1001 : Record 23;
BEGIN BEGIN
Vendor.SETFILTER("No.",FilterStr); Vendor.SETFILTER("No.",FilterStr);
IF Vendor.FINDSET THEN IF Vendor.FINDSET THEN
REPEAT REPEAT
"User ID" := USERID; "User ID" := USERID;
"Vendor No." := Vendor."No."; "Vendor No." := Vendor."No.";
IF INSERT THEN; IF INSERT THEN;
UNTIL Vendor.NEXT = 0; UNTIL Vendor.NEXT = 0;
END; END;

View file

@ -8,37 +8,37 @@ Unused variables affect readability.
Bad code Bad code
PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text\[50\]); PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text[50]);
BEGIN BEGIN
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
ERROR(DateNotAllowedErr,Caption,EntryNo) ERROR(DateNotAllowedErr,Caption,EntryNo)
IF PostingDate \> MaxPostingDate THEN IF PostingDate > MaxPostingDate THEN
MaxPostingDate := PostingDate; MaxPostingDate := PostingDate;
END END
Good code Good code
PROCEDURE CheckPostingDate@23(); PROCEDURE CheckPostingDate@23();
BEGIN BEGIN
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
ERROR(DateNotAllowedErr,Caption,EntryNo); ERROR(DateNotAllowedErr,Caption,EntryNo);
IF PostingDate \> MaxPostingDate THEN IF PostingDate > MaxPostingDate THEN
MaxPostingDate := PostingDate; MaxPostingDate := PostingDate;
END; END;
Bad code Bad code
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal; PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
VAR VAR
ItemEntry@1000 : Record 32; ItemEntry@1000 : Record 32;
Quantity@1003 : Integer; Quantity@1003 : Integer;
BEGIN BEGIN
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE)); EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
END; END;
Good code Good code
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal; PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
BEGIN BEGIN
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE)); EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
END; END;

View file

@ -8,52 +8,52 @@ It will throw an error at runtime.
Bad code Bad code
FileName@1010 : Text\[250\]; FileName@1010 : Text[250];
... ...
UploadedFileName@1016 : Text\[1024\]; UploadedFileName@1016 : Text[1024];
... ...
FileName := UploadedFileName; FileName := UploadedFileName;
Good code Good code
FileName@1010 : Text\[1024\]; FileName@1010 : Text[1024];
... ...
UploadedFileName@1016 : Text\[1024\]; UploadedFileName@1016 : Text[1024];
... ...
FileName := UploadedFileName; FileName := UploadedFileName;
Bad code Bad code
FileName@1010 : Text\[250\]; FileName@1010 : Text[250];
... ...
UploadedFileName@1016 : Text\[1024\]; UploadedFileName@1016 : Text[1024];
... ...
FileName := UploadedFileName; FileName := UploadedFileName;
Good code Good code
FileName@1010 : Text\[250\]; FileName@1010 : Text[250];
... ...
UploadedFileName@1016 : Text\[1024\]; UploadedFileName@1016 : Text[1024];
... ...
FileName := COPYSTR(UploadedFileName,1,250); // In case only the first 250 chars are needed. Similar for fields FileName := COPYSTR(UploadedFileName,1,250); // In case only the first 250 chars are needed. Similar for fields
Bad code Bad code
VAR VAR
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests' ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
Subject@1002 : Text\[50\]; Subject@1002 : Text[50];
... ...
BEGIN BEGIN
... ...
Subject := ExceededNumberTxt; Subject := ExceededNumberTxt;
Good code Good code
VAR VAR
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests' ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
Subject@1002 : Text\[100\]; Subject@1002 : Text[100];
... ...
BEGIN BEGIN
... ...
Subject := ExceededNumberTxt'; Subject := ExceededNumberTxt';

View file

@ -4,17 +4,18 @@ weight = 1450
+++ +++
Do not use the WITH scope when it has a variable whose name is the same as a local variable. This can lead to wrong code assumptions. Do not use the WITH scope when it has a variable whose name is the same as a local variable. This can lead to wrong code assumptions.
**Given that** "Contract Type" is a field on table ServiceContractHeader, then in the following example there is a parameter name clash with the field name. Which one will be used? **Given that**
"Contract Type" is a field on table ServiceContractHeader, then in the following example there is a parameter name clash with the field name. Which one will be used?
Bad code Bad code
PROCEDURE InsertData@1("Contract Type"@1000 : Option...); PROCEDURE InsertData@1("Contract Type"@1000 : Option...);
... ...
BEGIN BEGIN
... ...
WITH ServiceContractHeader DO BEGIN WITH ServiceContractHeader DO BEGIN
... ...
DimMgt.InsertServContractDim(...,"Contract Type","Contract No.",0,...); DimMgt.InsertServContractDim(...,"Contract Type","Contract No.",0,...);
END; END;
Good code Good code
@ -22,8 +23,8 @@ Good code
PROCEDURE InsertData@1(ContractType@1000 : Option...); PROCEDURE InsertData@1(ContractType@1000 : Option...);
... ...
BEGIN BEGIN
... ...
WITH ServiceContractHeader DO BEGIN WITH ServiceContractHeader DO BEGIN
... ...
DimMgt.InsertServContractDim(...,ContractType,"Contract No.",0,...); DimMgt.InsertServContractDim(...,ContractType,"Contract No.",0,...);
END; END;

View file

@ -2,15 +2,16 @@
title = "Using Calcdate" title = "Using Calcdate"
weight = 1370 weight = 1370
+++ +++
CALCDATE should only be used with DateFormula variables. Alternatively the string should be enclosed using the <\> symbols. CALCDATE should only be used with DateFormula variables. Alternatively the string should be enclosed using the <> symbols.
Bad code Bad code
IF ReservEntry."Expected Receipt Date" \> IF ReservEntry."Expected Receipt Date" >
CALCDATE('-' + FORMAT("Dampener (Time)") + FirstDate) CALCDATE('-' + FORMAT("Dampener (Time)") + FirstDate)
THEN THEN
Good code Good code
IF ReservEntry."Expected Receipt Date" \> IF ReservEntry."Expected Receipt Date" >
CALCDATE('<-' + FORMAT("Dampener (Time)") + FirstDate + '\>') CALCDATE('<-' + FORMAT("Dampener (Time)") + FirstDate + '>')
THEN THEN

View file

@ -11,8 +11,12 @@ Reason:
Bad code Bad code
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDNAME("Location Code"),...) ```al
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDNAME("Location Code"),...)
```
Good code Good code
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDCAPTION("Location Code"),...) ```al
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDCAPTION("Location Code"),...)
```

View file

@ -6,15 +6,19 @@ Declare Text Constant as global variables.
Bad code Bad code
PROCEDURE GetRequirementText@6(...) : Text\[50\]; ```al
VAR PROCEDURE GetRequirementText@6(...) : Text\[50\];
VAR
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away'; RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
BEGIN BEGIN
```
Good code Good code
VAR ```al
VAR
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away'; RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
... ...
PROCEDURE GetRequirementText@6(...) : Text\[50\]; PROCEDURE GetRequirementText@6(...) : Text\[50\];
BEGIN BEGIN
```

View file

@ -6,32 +6,40 @@ Pass user messages using Text Constants. It makes translation easy.
Bad code Bad code
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment "'; ```al
... ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment "';
IF CONFIRM(ImportAttachmentQst + Caption +'?',TRUE) THEN BEGIN ...
IF CONFIRM(ImportAttachmentQst + Caption +'?',TRUE) THEN BEGIN
```
Good code Good code
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment %1?"'; ```al
... ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment %1?"';
IF CONFIRM(STRSUBSTNO(ImportAttachmentQst, Caption),TRUE) THEN BEGIN ...
IF CONFIRM(STRSUBSTNO(ImportAttachmentQst, Caption),TRUE) THEN BEGIN
```
Bad code Bad code
... ```al
...
IF NOT IF NOT
CONFIRM( CONFIRM(
STRSUBSTNO( STRSUBSTNO(
'Difference on Periodic entries: %1 on %2' + 'Difference on Periodic entries: %1 on %2' +
'Do you want to continue?',Balance,Date), 'Do you want to continue?',Balance,Date),
TRUE) TRUE)
THEN THEN
ERROR('Program terminated by the user'); ERROR('Program terminated by the user');
```
Good code Good code
DiffOnPeriodEntiesQst@100 : TextConst 'ENU="Difference on Periodic entries: %1 on %2\\ Do you want to continue?"'; ```al
ProgramTerminatedErr@200 : TextConst 'ENU="Program terminated by the user"'; DiffOnPeriodEntiesQst@100 : TextConst 'ENU="Difference on Periodic entries: %1 on %2\\ Do you want to continue?"';
... ProgramTerminatedErr@200 : TextConst 'ENU="Program terminated by the user"';
...
IF NOT CONFIRM(STRSUBSTNO(DiffOnPeriodEntiesQst,Balance,Date),TRUE) THEN IF NOT CONFIRM(STRSUBSTNO(DiffOnPeriodEntiesQst,Balance,Date),TRUE) THEN
ERROR(ProgramTerminatedErr); ERROR(ProgramTerminatedErr);
```

View file

@ -2,15 +2,21 @@
title = "Begin as an 'After Word'" title = "Begin as an 'After Word'"
weight = 230 weight = 230
+++ +++
When BEGIN follows THEN, ELSE, DO, it should be on the same line, preceded by one space character. Bad code When BEGIN follows THEN, ELSE, DO, it should be on the same line, preceded by one space character.
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN Bad code
```al
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN
BEGIN BEGIN
... ...
END; END;
```
Good code Good code
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN BEGIN ```
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN BEGIN
... ...
END; END;
```

View file

@ -3,52 +3,67 @@ title = "Begin-End - Compound Only"
weight = 240 weight = 240
+++ +++
Only use BEGIN..END to enclose compound statements. Only use BEGIN..END to enclose compound statements.
Bad code Bad code
IF FINDSET THEN BEGIN ```al
IF FINDSET THEN BEGIN
REPEAT REPEAT
... ...
UNTIL NEXT = 0; UNTIL NEXT = 0;
END; END;
```
Good code Good code
IF FINDSET THEN ```al
IF FINDSET THEN
REPEAT REPEAT
... ...
UNTIL NEXT = 0; UNTIL NEXT = 0;
```
Bad code Bad code
IF IsAssemblyOutputLine THEN BEGIN ```al
IF IsAssemblyOutputLine THEN BEGIN
TESTFIELD("Order Line No.",0); TESTFIELD("Order Line No.",0);
END; END;
```
Good code Good code
IF IsAssemblyOutputLine THEN ```al
IF IsAssemblyOutputLine THEN
TESTFIELD("Order Line No.",0); TESTFIELD("Order Line No.",0);
```
Bad code Bad code
IF FINDSET THEN ```al
IF FINDSET THEN
REPEAT REPEAT
BEGIN BEGIN
... ...
END; END;
UNTIL NEXT = 0; UNTIL NEXT = 0;
```
Good code Good code
IF FINDSET THEN ```al
IF FINDSET THEN
REPEAT REPEAT
... ...
UNTIL NEXT = 0; UNTIL NEXT = 0;
```
Exception Exception
// Except for this case ```al
IF X THEN BEGIN // Except for this case
IF X THEN BEGIN
IF Y THEN IF Y THEN
DO SOMETHING; DO SOMETHING;
END ELSE (not X) END ELSE (not X)
```

View file

@ -2,14 +2,20 @@
title = "Binary Operator to Start Line" title = "Binary Operator to Start Line"
weight = 250 weight = 250
+++ +++
Do not start a line with a binary operator. Bad code Do not start a line with a binary operator.
"Quantity to Ship" := Bad code
```al
"Quantity to Ship" :=
Quantity Quantity
- "Quantity Shipped" - "Quantity Shipped"
```
Good code Good code
"Quantity to Ship" := ```al
"Quantity to Ship" :=
Quantity - Quantity -
"Quantity Shipped" "Quantity Shipped"
```

View file

@ -2,30 +2,43 @@
title = "Blank Lines" title = "Blank Lines"
weight = 260 weight = 260
+++ +++
Do not use blank lines at the beginning or end of any functions, after BEGIN, before END, or inside multiline expressions. Bad code Do not use blank lines at the beginning or end of any functions, after BEGIN, before END, or inside multiline expressions.
PROCEDURE MATRIX\_OnDrillDown@1133(MATRIX\_ColumnOrdinal : Integer);
BEGIN
SetupDrillDownCol(MATRIX\_ColumnOrdinal);
DrillDown(FALSE,ValueType);
END;
Good code
PROCEDURE MATRIX\_OnDrillDown@1133(MATRIX\_ColumnOrdinal : Integer);
BEGIN
SetupDrillDownCol(MATRIX\_ColumnOrdinal);
DrillDown(FALSE,ValueType);
END;
Bad code Bad code
IF NameIsValid AND ```al
Name2IsValid PROCEDURE MATRIX_OnDrillDown@1133(MATRIX_ColumnOrdinal : Integer);
THEN BEGIN
SetupDrillDownCol(MATRIX_ColumnOrdinal);
DrillDown(FALSE,ValueType);
END;
```
Good code Good code
IF NameIsValid AND ```al
PROCEDURE MATRIX_OnDrillDown@1133(MATRIX_ColumnOrdinal : Integer);
BEGIN
SetupDrillDownCol(MATRIX_ColumnOrdinal);
DrillDown(FALSE,ValueType);
END;
```
Bad code
```al
IF NameIsValid AND
Name2IsValid Name2IsValid
THEN THEN
```
Good code
```al
IF NameIsValid AND
Name2IsValid
THEN
```

View file

@ -2,16 +2,22 @@
title = "CASE Action" title = "CASE Action"
weight = 310 weight = 310
+++ +++
A CASE action should start on a line after the possibility. Bad code A CASE action should start on a line after the possibility.
CASE Letter OF Bad code
```al
CASE Letter OF
'A': Letter2 := '10'; 'A': Letter2 := '10';
'B': Letter2 := '11'; 'B': Letter2 := '11';
```
Good code Good code
CASE Letter OF ```al
CASE Letter OF
'A': 'A':
Letter2 := '10'; Letter2 := '10';
'B': 'B':
Letter2 := '11'; Letter2 := '11';
```

View file

@ -2,14 +2,20 @@
title = "Colon usage in CASE" title = "Colon usage in CASE"
weight = 340 weight = 340
+++ +++
The last possibility on a CASE statement must be immediately followed by a colon. Bad code The last possibility on a CASE statement must be immediately followed by a colon.
CASE DimOption OF Bad code
```al
CASE DimOption OF
DimOption::"Global Dimension 1" : DimOption::"Global Dimension 1" :
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code"; DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
```
Good code Good code
CASE DimOption OF ```al
CASE DimOption OF
DimOption::"Global Dimension 1": DimOption::"Global Dimension 1":
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code"; DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
```

View file

@ -2,38 +2,45 @@
title = "Comments inside Curly Brackets" title = "Comments inside Curly Brackets"
weight = 350 weight = 350
+++ +++
Never use curly bracket comments. During development, the "Block comment" functionality can be used instead. However, in production code, block comments are not recommended. Bad code Never use curly bracket comments. During development, the "Block comment" functionality can be used instead. However, in production code, block comments are not recommended.
PeriodTxt: {Period} Bad code
```al
PeriodTxt: {Period}
```
Good code Good code
PeriodTxt: // Period ```al
PeriodTxt: // Period
```
Bad code Bad code
PROCEDURE MATRIX\_OnAfterGetRecord@10(MATRIX\_ColumnOrdinal : Integer); ```al
BEGIN PROCEDURE MATRIX_OnAfterGetRecord@10(MATRIX_ColumnOrdinal : Integer);
BEGIN
{ {
IF ShowColumnName THEN IF ShowColumnName THEN
MatrixHeader := MatrixRecords\[MATRIX\_ColumnOrdinal\].Name MatrixHeader := MatrixRecords[MATRIX_ColumnOrdinal].Name
ELSE ELSE
MatrixHeader := MatrixRecords\[MATRIX\_ColumnOrdinal\].Code; MatrixHeader := MatrixRecords[MATRIX_ColumnOrdinal].Code;
} }
MatrixRecord := MatrixRecords\[MATRIX\_ColumnOrdinal\]; MatrixRecord := MatrixRecords[MATRIX_ColumnOrdinal];
AnalysisValue := CalcAmt(ValueType,TRUE); AnalysisValue := CalcAmt(ValueType,TRUE);
MATRIX\_CellData\[MATRIX\_ColumnOrdinal\] := AnalysisValue; MATRIX_CellData[MATRIX_ColumnOrdinal] := AnalysisValue;
END; END;
```
Good code Good code
PROCEDURE MATRIX\_OnAfterGetRecord@10(MATRIX\_ColumnOrdinal : Integer); ```al
BEGIN PROCEDURE MATRIX_OnAfterGetRecord@10(MATRIX_ColumnOrdinal : Integer);
MatrixRecord := MatrixRecords\[MATRIX\_ColumnOrdinal\]; BEGIN
MatrixRecord := MatrixRecords[MATRIX_ColumnOrdinal];
AnalysisValue := CalcAmt(ValueType,TRUE); AnalysisValue := CalcAmt(ValueType,TRUE);
MATRIX\_CellData\[MATRIX\_ColumnOrdinal\] := AnalysisValue; MATRIX_CellData[MATRIX_ColumnOrdinal] := AnalysisValue;
END; END;
```

View file

@ -3,12 +3,16 @@ title = "Comment Spacing"
weight = 360 weight = 360
+++ +++
Always start comments with // followed by one space character. Always start comments with // followed by one space character.
Bad code Bad code
RowNo += 1000; //Move way below the budget ```al
RowNo += 1000; //Move way below the budget
```
Good code Good code
RowNo += 1000; // Move way below the budget ```al
RowNo += 1000; // Move way below the budget
```

View file

@ -3,19 +3,24 @@ title = "END ELSE Pair"
weight = 540 weight = 540
+++ +++
The END ELSE pair should always appear on the same line. The END ELSE pair should always appear on the same line.
Bad code Bad code
IF OppEntry.FIND('-') THEN ```al
IF OppEntry.FIND('-') THEN
IF SalesCycleStage.FIND('-') THEN BEGIN IF SalesCycleStage.FIND('-') THEN BEGIN
... ...
END END
ELSE ELSE
... ...
```
Good code Good code
IF OppEntry.FIND('-') THEN ```al
IF OppEntry.FIND('-') THEN
IF SalesCycleStage.FIND('-') THEN BEGIN IF SalesCycleStage.FIND('-') THEN BEGIN
...
END ELSE
... ...
END ELSE ```
...

View file

@ -3,82 +3,110 @@ title = "Indentation"
weight = 650 weight = 650
+++ +++
In general, use an indentation of two space characters. Logical expressions in the IF, WHILE, and UNTIL parts are indented at least 3, 6, and 6 spaces respectively. In general, use an indentation of two space characters. Logical expressions in the IF, WHILE, and UNTIL parts are indented at least 3, 6, and 6 spaces respectively.
Bad code Bad code
IF GLSetup."Unrealized VAT" OR ```al
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment) IF GLSetup."Unrealized VAT" OR
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
Good code ```
IF GLSetup."Unrealized VAT" OR Good code
```al
IF GLSetup."Unrealized VAT" OR
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment) (GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
```
Bad code Bad code
IF GenJnlLine."Account No." <\> ICPartner.Code THEN ```al
ICPartner.GET("Account No."); IF GenJnlLine."Account No." <> ICPartner.Code THEN
IF GenJnlLine.Amount \> 0 THEN BEGIN ICPartner.GET("Account No.");
IF GenJnlLine.Amount \> 0 THEN BEGIN
... ...
```
Good code Good code
IF GenJnlLine."Account No." <\> ICPartner.Code THEN ```al
ICPartner.GET("Account No."); IF GenJnlLine."Account No." <> ICPartner.Code THEN
IF GenJnlLine.Amount \> 0 THEN BEGIN ICPartner.GET("Account No.");
... IF GenJnlLine.Amount > 0 THEN BEGIN
...
```
Bad code Bad code
Dialog.OPEN(WindowTxt + ```al
'@1@@@@@@@@@@@@@@@@@@@@@@@'); Dialog.OPEN(WindowTxt +
'@1@@@@@@@@@@@@@@@@@@@@@@@');
```
Good code Good code
Dialog.OPEN( ```al
Dialog.OPEN(
WindowTxt + WindowTxt +
'@1@@@@@@@@@@@@@@@@@@@@@@@'); '@1@@@@@@@@@@@@@@@@@@@@@@@');
```
Bad code Bad code
TempOldCustLedgEntry.DELETE; ```al
// Find the next old entry for application of the new entry TempOldCustLedgEntry.DELETE;
// Find the next old entry for application of the new entry
```
Good code Good code
TempOldCustLedgEntry.DELETE; ```al
// Find the next old entry for application of the new entry TempOldCustLedgEntry.DELETE;
// Find the next old entry for application of the new entry
```
Bad code Bad code
IF NOT ("Applies-to Doc. Type" IN ```al
\["Applies-to Doc. Type"::Receipt, IF NOT ("Applies-to Doc. Type" IN
"Applies-to Doc. Type"::"Return Shipment"\]) ["Applies-to Doc. Type"::Receipt,
"Applies-to Doc. Type"::"Return Shipment"])
```
Good code Good code
IF NOT ("Applies-to Doc. Type" IN ```al
\["Applies-to Doc. Type"::Receipt, IF NOT ("Applies-to Doc. Type" IN
"Applies-to Doc. Type"::"Return Shipment"\]) ["Applies-to Doc. Type"::Receipt,
"Applies-to Doc. Type"::"Return Shipment"])
```
Bad code Bad code
WHILE (RemAmt \> 0) OR ```al
(RemAmtLCY \> 0) WHILE (RemAmt > 0) OR
DO (RemAmtLCY > 0)
DO
```
Good code Good code
WHILE (RemAmt \> 0) OR ```al
(RemAmtLCY \> 0) WHILE (RemAmt > 0) OR
DO (RemAmtLCY > 0)
DO
```
Bad code Bad code
UNTIL (RemAmt \> 0) AND ```al
(RemAmtLCY \> 0); UNTIL (RemAmt > 0) AND
(RemAmtLCY > 0);
```
Good code Good code
UNTIL (RemAmt \> 0) AND ```al
(RemAmtLCY \> 0) UNTIL (RemAmt > 0) AND
(RemAmtLCY > 0)
```

View file

@ -2,13 +2,19 @@
title = "Keyword Pairs - Indentation" title = "Keyword Pairs - Indentation"
weight = 730 weight = 730
+++ +++
The IF..THEN pair, WHILE..DO pair, and FOR..DO pair must appear on the same line or the same level of indentation. Bad code The IF..THEN pair, WHILE..DO pair, and FOR..DO pair must appear on the same line or the same level of indentation.
IF (x = y) AND Bad code
(a = b) THEN
```al
IF (x = y) AND
(a = b) THEN
```
Good code Good code
IF (x = y) AND ```al
(a = b) IF (x = y) AND
THEN (a = b)
THEN
```

View file

@ -2,19 +2,25 @@
title = "Line Start Keywords" title = "Line Start Keywords"
weight = 740 weight = 740
+++ +++
The END, IF, REPEAT, FOR, WHILE, ELSE and CASE statement should always start a line. Bad code The END, IF, REPEAT, FOR, WHILE, ELSE and CASE statement should always start a line.
IF IsContactName THEN ValidateContactName Bad code
ELSE IF IsSalespersonCode THEN ValidateSalespersonCode
```al
IF IsContactName THEN ValidateContactName
ELSE IF IsSalespersonCode THEN ValidateSalespersonCode
ELSE IF IsSalesCycleCode THEN ValidatSalesCycleCode; ELSE IF IsSalesCycleCode THEN ValidatSalesCycleCode;
```
Good code Good code
IF IsContactName THEN ```al
ValidateContactName IF IsContactName THEN
ELSE ValidateContactName
IF IsSalespersonCode THEN ELSE
IF IsSalespersonCode THEN
ValidateSalespersonCode ValidateSalespersonCode
ELSE ELSE
IF IsSalesCycleCode THEN IF IsSalesCycleCode THEN
ValidatSalesCycleCode; ValidatSalesCycleCode;
```

View file

@ -3,13 +3,18 @@ title = "Lonely Repeat"
weight = 760 weight = 760
+++ +++
The REPEAT statement should always be alone on a line. The REPEAT statement should always be alone on a line.
Bad code Bad code
IF ReservEntry.FINDSET THEN REPEAT ```al
IF ReservEntry.FINDSET THEN REPEAT
```
Good code Good code
IF ReservEntry.FINDSET THEN ```al
REPEAT IF ReservEntry.FINDSET THEN
REPEAT
```

View file

@ -3,12 +3,16 @@ title = "Named Invocations"
weight = 830 weight = 830
+++ +++
When calling an object statically use the name, not the number When calling an object statically use the name, not the number
Bad code Bad code
PAGE.RUNMODAL(525,SalesShptLine) ```al
PAGE.RUNMODAL(525,SalesShptLine)
```
Good code Good code
PAGE.RUNMODAL(PAGE::"Posted Sales Shipment Lines",SalesShptLine) ```al
PAGE.RUNMODAL(PAGE::"Posted Sales Shipment Lines",SalesShptLine)
```

View file

@ -3,19 +3,24 @@ title = "Nested WITHs"
weight = 850 weight = 850
+++ +++
Do not nest WITHs that reference different types of objects. Do not nest WITHs that reference different types of objects.
Bad code Bad code
WITH PostedWhseShptLine DO BEGIN ```al
... WITH PostedWhseShptLine DO BEGIN
WITH ItemLedgEntry DO ...
WITH ItemLedgEntry DO
InsertBufferRec(...,"Serial No.","Lot No.",...); InsertBufferRec(...,"Serial No.","Lot No.",...);
... ...
END; END;
```
Good code Good code
WITH PostedWhseShptLine DO BEGIN ```al
... WITH PostedWhseShptLine DO BEGIN
InsertBufferRec(...,ItemLedgEntry."Serial No.",ItemLedgEntry."Lot No.",...); ...
... InsertBufferRec(...,ItemLedgEntry."Serial No.",ItemLedgEntry."Lot No.",...);
END; ...
END;
```

View file

@ -3,26 +3,34 @@ title = "One Statement Per Line"
weight = 910 weight = 910
+++ +++
A line of code should not have more than one statement. A line of code should not have more than one statement.
Bad code Bad code
IF OppEntry.FIND('-') THEN EXIT ```al
IF OppEntry.FIND('-') THEN EXIT
```
Good code Good code
IF OppEntry.FIND('-') THEN ```al
EXIT IF OppEntry.FIND('-') THEN
EXIT
```
Bad code Bad code
TotalCost += Cost; TotalAmt += Amt; ```al
TotalCost += Cost; TotalAmt += Amt;
```
Good code Good code
TotalCost += Cost; ```al
TotalAmt += Amt; TotalCost += Cost;
TotalAmt += Amt;
```

View file

@ -2,16 +2,22 @@
title = "Separate IF and ELSE" title = "Separate IF and ELSE"
weight = 1050 weight = 1050
+++ +++
IF and ELSE statements should be on separate lines. Bad code IF and ELSE statements should be on separate lines.
IF Atom\[i+1\] = '\>' THEN HasLogicalOperator := TRUE ELSE BEGIN Bad code
```al
IF Atom[i+1] = '>' THEN HasLogicalOperator := TRUE ELSE BEGIN
... ...
END; END;
```
Good code Good code
IF Atom\[i+1\] = '\>' THEN ```al
IF Atom[i+1] = '>' THEN
HasLogicalOperator := TRUE HasLogicalOperator := TRUE
ELSE BEGIN ELSE BEGIN
... ...
END; END;
```

View file

@ -3,36 +3,44 @@ title = "Spacing Binary Operators"
weight = 1120 weight = 1120
+++ +++
There must be exactly one space character on each side of a binary operator such as = + - AND OR =. The parameter comma operator however, should have no spaces. There must be exactly one space character on each side of a binary operator such as = + - AND OR =. The parameter comma operator however, should have no spaces.
Bad code Bad code
"Line Discount %" := "Line Discount Amount"/"Line Value"\*100 ```al
"Line Discount %" := "Line Discount Amount"/"Line Value"*100
```
Good code Good code
"Line Discount %" := "Line Discount Amount" / "Line Value" \* 100; ```al
"Line Discount %" := "Line Discount Amount" / "Line Value" * 100;
```
Bad code Bad code
StartDate := CALCDATE('<+'+FORMAT(Days + i)+'D\>', StartDate); ```al
StartDate := CALCDATE('<+'+FORMAT(Days + i)+'D>', StartDate);
```
Good code Good code
StartDate := CALCDATE('<+' + FORMAT(Days + i) + 'D\>',StartDate); ```al
StartDate := CALCDATE('<+' + FORMAT(Days + i) + 'D>',StartDate);
```
Bad code Bad code
StartDate := 0D; // Initialize ```al
StartDate := 0D; // Initialize
```
Good code Good code
StartDate := 0D; // Initialize ```al
StartDate := 0D; // Initialize
```

View file

@ -3,36 +3,44 @@ title = "Spacing Brackets and ::"
weight = 1130 weight = 1130
+++ +++
There must be no spaces characters before and after \[\] dimension brackets symbols or :: option symbols. There must be no spaces characters before and after \[\] dimension brackets symbols or :: option symbols.
Bad code Bad code
A\[i\] \[j\] := Amt; ```al
A[i] [j] := Amt;
```
Good code Good code
A\[i\]\[j\] := Amt; ```al
A[i][j] := Amt;
```
Bad code Bad code
"Currency Exchange Rate"."Fix Exchange Rate Amount" :: Currency: ```al
"Currency Exchange Rate"."Fix Exchange Rate Amount" :: Currency:
```
Good code Good code
"Currency Exchange Rate"."Fix Exchange Rate Amount"::Currency: ```al
"Currency Exchange Rate"."Fix Exchange Rate Amount"::Currency:
```
Bad code Bad code
IF FIND (Which) THEN ```al
IF FIND (Which) THEN
```
Good code Good code
IF FIND(Which) THEN ```al
IF FIND(Which) THEN
```

View file

@ -3,24 +3,30 @@ title = "Spacing Unary Operators"
weight = 1140 weight = 1140
+++ +++
There must be no space between a unary operator and its argument (except for the NOT keyword). There must be no space between a unary operator and its argument (except for the NOT keyword).
Bad code Bad code
IF NOT(Type = Type::Item) THEN ```al
IF NOT(Type = Type::Item) THEN
```
Good code Good code
IF NOT (Type = Type::Item) THEN ```al
IF NOT (Type = Type::Item) THEN
```
Bad code Bad code
DiscAmt := - "Discount Amount"; ```al
DiscAmt := - "Discount Amount";
```
Good code Good code
DiscAmt := -"Discount Amount"; ```al
DiscAmt := -"Discount Amount";
```

View file

@ -2,23 +2,30 @@
title = "Temporary Variable Naming" title = "Temporary Variable Naming"
weight = 1200 weight = 1200
+++ +++
The name of a temporary variable must be prefixed with the word Temp and not otherwise. Bad code The name of a temporary variable must be prefixed with the word Temp and not otherwise.
JobWIPBuffer@1002 : TEMPORARY Record 1018;
Good code
TempJobWIPBuffer@1002 : TEMPORARY Record 1018;
Bad code Bad code
TempJobWIPBuffer@1002 : Record 1018; ```al
JobWIPBuffer@1002 : TEMPORARY Record 1018;
```
Good code Good code
CopyOfJobWIPBuffer@1002 : Record 1018; ```al
TempJobWIPBuffer@1002 : TEMPORARY Record 1018;
```
Bad code
```al
TempJobWIPBuffer@1002 : Record 1018;
```
Good code
```al
CopyOfJobWIPBuffer@1002 : Record 1018;
```

View file

@ -3,88 +3,113 @@ title = "TextConst Suffixes"
weight = 1210 weight = 1210
+++ +++
TextConst variable names should have a suffix (an approved three-letter suffix: Msg, Tok, Err, Qst, Lbl, Txt) describing usage. TextConst variable names should have a suffix (an approved three-letter suffix: Msg, Tok, Err, Qst, Lbl, Txt) describing usage.
Bad code Bad code
CannotDeleteLine@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.'; ```al
... CannotDeleteLine@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
ERROR(CannotDeleteLine,TABLECAPTION); ...
ERROR(CannotDeleteLine,TABLECAPTION);
```
Good code Good code
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.'; ```al
... CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
ERROR(CannotDeleteLineErr,TABLECAPTION); ...
ERROR(CannotDeleteLineErr,TABLECAPTION);
```
Bad code Bad code
Text000@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"'; ```al
... Text000@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
SalesLine.FIELDERROR(Type,STRSUBSTNO(Text000,...); ...
... SalesLine.FIELDERROR(Type,STRSUBSTNO(Text000,...);
...
```
Good code Good code
TypeHasBeenChangedErr@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"'; ```al
... TypeHasBeenChangedErr@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
SalesLine.FIELDERROR(Type,STRSUBSTNO(TypeHasBeenChangedErr,...); ...
... SalesLine.FIELDERROR(Type,STRSUBSTNO(TypeHasBeenChangedErr,...);
...
```
Bad code Bad code
Text004@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.'; ```al
... Text004@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
Window@1007 : Dialog; ...
... Window@1007 : Dialog;
...
Window.OPEN(Text004); Window.OPEN(Text004);
```
Good code Good code
IndentingMsg@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.'; ```al
... IndentingMsg@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
Window@1007 : Dialog; ...
... Window@1007 : Dialog;
...
Window.OPEN(IndentingMsg); Window.OPEN(IndentingMsg);
```
Bad code Bad code
Text002@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?'; ```al
... Text002@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
IF CONFIRM(Text002,TRUE,GLAcc.TABLECAPTION) THEN ...
IF CONFIRM(Text002,TRUE,GLAcc.TABLECAPTION) THEN
```
Good code Good code
OpenWhereUsedWindowQst@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?'; ```al
... OpenWhereUsedWindowQst@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
IF CONFIRM(OpenWhereUsedWindowQst,TRUE,GLAcc.TABLECAPTION) THEN ...
IF CONFIRM(OpenWhereUsedWindowQst,TRUE,GLAcc.TABLECAPTION) THEN
```
Bad code Bad code
Selection := STRMENU(Text003,2); ```al
... Selection := STRMENU(Text003,2);
Text003@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components'; ...
Text003@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
```
Good code Good code
```al
Selection := STRMENU(CopyFromQst,2); Selection := STRMENU(CopyFromQst,2);
... ...
CopyFromQst@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components'; CopyFromQst@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
```
Bad code Bad code
DATASET ```al
{ DATASET
... {
{ 1 ;1 ;Column ;Chart\_of\_AccountsCaption; ...
SourceExpr=Chart\_of\_AccountsCaption } { 1 ;1 ;Column ;Chart_of_AccountsCaption;
... SourceExpr=Chart_of_AccountsCaption }
Chart\_of\_AccountsCaption@9647 : TextConst 'ENU=Chart of Accounts'; ...
Chart_of_AccountsCaption@9647 : TextConst 'ENU=Chart of Accounts';
```
Good code Good code
DATASET ```al
{ DATASET
... {
{ 1 ;1 ;Column ;Chart\_of\_AccountsCaption; ...
SourceExpr=ChartOfAccountsLbl } { 1 ;1 ;Column ;Chart_of_AccountsCaption;
... SourceExpr=ChartOfAccountsLbl }
ChartOfAccountsLbl@9647 : TextConst 'ENU=Chart of Accounts'; ...
ChartOfAccountsLbl@9647 : TextConst 'ENU=Chart of Accounts';
```

View file

@ -3,12 +3,17 @@ title = "Unary Operator Line End"
weight = 1250 weight = 1250
+++ +++
Do not end a line with unary operator. Do not end a line with unary operator.
Bad code Bad code
"Quantity Handled (Base)" := - ```al
"Quantity Handled (Base)" := -
"Quantity Handled (Base)"); "Quantity Handled (Base)");
```
Good code Good code
"Quantity Handled (Base)" := ```al
"Quantity Handled (Base)" :=
- "Quantity Handled (Base)"); - "Quantity Handled (Base)");
```

View file

@ -3,26 +3,30 @@ title = "Unnecessary Compound Parenthesis"
weight = 1260 weight = 1260
+++ +++
Use parenthesis only to enclose compound expressions inside compound expressions. Use parenthesis only to enclose compound expressions inside compound expressions.
Bad code Bad code
IF ("Costing Method" = "Costing Method"::Standard) THEN ```al
IF ("Costing Method" = "Costing Method"::Standard) THEN
```
Good code Good code
IF "Costing Method" = "Costing Method"::Standard THEN ```al
IF "Costing Method" = "Costing Method"::Standard THEN
```
####
Bad code Bad code
ProfitPct = -(Profit) / CostAmt \* 100; ```al
ProfitPct = -(Profit) / CostAmt * 100;
```
Good code Good code
ProfitPct = -Profit / CostAmt \* 100; ```al
ProfitPct = -Profit / CostAmt * 100;
```

View file

@ -2,15 +2,21 @@
title = "Unnecessary ELSE" title = "Unnecessary ELSE"
weight = 1270 weight = 1270
+++ +++
ELSE should not be used when the last action in the THEN part is an EXIT, BREAK, SKIP, QUIT, ERROR. Bad code ELSE should not be used when the last action in the THEN part is an EXIT, BREAK, SKIP, QUIT, ERROR.
IF IsAdjmtBinCodeChanged THEN Bad code
```al
IF IsAdjmtBinCodeChanged THEN
ERROR(AdjmtBinCodeChangeNotAllowedErr,...) ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
ELSE ELSE
ERROR(BinCodeChangeNotAllowedErr,...); ERROR(BinCodeChangeNotAllowedErr,...);
```
Good code Good code
IF IsAdjmtBinCodeChanged THEN ```al
IF IsAdjmtBinCodeChanged THEN
ERROR(AdjmtBinCodeChangeNotAllowedErr,...) ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
ERROR(BinCodeChangeNotAllowedErr,...); ERROR(BinCodeChangeNotAllowedErr,...);
```

View file

@ -3,24 +3,30 @@ title = "Unnecessary Function Parenthesis"
weight = 1280 weight = 1280
+++ +++
Do not use parenthesis in a function call if the function does not have any parameters. Do not use parenthesis in a function call if the function does not have any parameters.
Bad code Bad code
IF ReservMgt.IsPositive() THEN ```al
IF ReservMgt.IsPositive() THEN
```
Good code Good code
IF ReservMgt.IsPositive THEN ```al
IF ReservMgt.IsPositive THEN
```
Bad code Bad code
IF ChangeStatusForm.RUNMODAL() <\> ACTION::Yes THEN ```al
IF ChangeStatusForm.RUNMODAL() <> ACTION::Yes THEN
```
Good code Good code
IF ChangeStatusForm.RUNMODAL <\> ACTION::Yes THEN ```al
IF ChangeStatusForm.RUNMODAL <> ACTION::Yes THEN
```

View file

@ -2,12 +2,17 @@
title = "Unnecessary Separators" title = "Unnecessary Separators"
weight = 1290 weight = 1290
+++ +++
There should be no unnecessary separators. Bad code There should be no unnecessary separators.
IF Customer.FINDFIRST THEN;; Bad code
```al
IF Customer.FINDFIRST THEN;;
```
Good code Good code
IF Customer.FINDFIRST THEN; ```al
IF Customer.FINDFIRST THEN;
```

View file

@ -3,24 +3,30 @@ title = "Unnecessary TRUE/FALSE"
weight = 1300 weight = 1300
+++ +++
Do not use TRUE or FALSE keywords unnecessarily if the expression is already an logical expression. Do not use TRUE or FALSE keywords unnecessarily if the expression is already an logical expression.
Bad code Bad code
IF IsPositive() = TRUE THEN ```al
IF IsPositive() = TRUE THEN
```
Good code Good code
IF IsPositive THEN ```al
IF IsPositive THEN
```
Bad code Bad code
IF Complete <\> TRUE THEN ```
IF Complete <> TRUE THEN
```
Good code Good code
IF NOT Complete THEN ```al
IF NOT Complete THEN
```

View file

@ -3,30 +3,37 @@ title = "Variable Already Scoped"
weight = 1400 weight = 1400
+++ +++
Do not use scope ''.'' qualifier unnecessarily when a variable is already implicitly or explicitly scoped. It keeps the code simpler. Do not use scope ''.'' qualifier unnecessarily when a variable is already implicitly or explicitly scoped. It keeps the code simpler.
Bad code Bad code
ReturnRcptHeader.SETRANGE(ReturnRcptHeader."Return Order No.","Document No."); ```al
ReturnRcptHeader.SETRANGE(ReturnRcptHeader."Return Order No.","Document No.");
```
Good code Good code
ReturnRcptHeader.SETRANGE("Return Order No.","Document No."); ```al
ReturnRcptHeader.SETRANGE("Return Order No.","Document No.");
```
Bad code Bad code
WITH ChangeLogSetupTable DO BEGIN ```al
WITH ChangeLogSetupTable DO BEGIN
... ...
IF ChangeLogSetupTable.DELETE THEN IF ChangeLogSetupTable.DELETE THEN
... ...
END; END;
```
Good code Good code
WITH ChangeLogSetupTable DO BEGIN ```al
WITH ChangeLogSetupTable DO BEGIN
... ...
IF DELETE THEN IF DELETE THEN
... ...
END; END;
```

View file

@ -9,48 +9,61 @@ A variable must begin with a capital letter.
Blanks, periods, and other characters (such as parentheses) that would make quotation marks around a variable necessary must be omitted. Blanks, periods, and other characters (such as parentheses) that would make quotation marks around a variable necessary must be omitted.
If a variable is a compound of two or more words or abbreviations, each word or abbreviation should begin with a capital letter. If a variable is a compound of two or more words or abbreviations, each word or abbreviation should begin with a capital letter.
Bad code Bad code
... ```al
...
WIPBuffer@1002 : Record 1018 WIPBuffer@1002 : Record 1018
... ...
OBJECT Table Job WIP Buffer OBJECT Table Job WIP Buffer
```
Good code Good code
... ```al
...
JobWIPBuffer@1002 : Record 1018 JobWIPBuffer@1002 : Record 1018
... ...
OBJECT Table Job WIP Buffer OBJECT Table Job WIP Buffer
```
Bad code Bad code
... ```al
...
Postline@1004 : Codeunit 12; Postline@1004 : Codeunit 12;
... ...
OBJECT Codeunit Gen. Jnl.-Post Line OBJECT Codeunit Gen. Jnl.-Post Line
```
Good code Good code
... ```al
...
GenJnlPostLine@1004 : Codeunit 12; GenJnlPostLine@1004 : Codeunit 12;
... ...
OBJECT Codeunit Gen. Jnl.-Post Line OBJECT Codeunit Gen. Jnl.-Post Line
```
Bad code Bad code
LOCAL PROCEDURE HandleCustDebitCredit@17(...;"Amount (LCY)"@1001 : Decimal;...); ```al
BEGIN LOCAL PROCEDURE HandleCustDebitCredit@17(...;"Amount (LCY)"@1001 : Decimal;...);
BEGIN
IF ((... ("Amount (LCY)" \> 0)) ...) OR IF ((... ("Amount (LCY)" \> 0)) ...) OR
((... ("Amount (LCY)" < 0)) ...) ((... ("Amount (LCY)" < 0)) ...)
THEN BEGIN THEN BEGIN
... ...
```
Good code Good code
LOCAL PROCEDURE HandleCustDebitCredit@17(...;AmountLCY@1001 : Decimal;...); ```al
BEGIN LOCAL PROCEDURE HandleCustDebitCredit@17(...;AmountLCY@1001 : Decimal;...);
BEGIN
IF ((... (AmountLCY \> 0)) ...) OR IF ((... (AmountLCY \> 0)) ...) OR
((... (AmountLCY < 0)) ...) ((... (AmountLCY < 0)) ...)
THEN BEGIN THEN BEGIN
... ...
```

View file

@ -2,12 +2,18 @@
title = "Variables Declarations Order" title = "Variables Declarations Order"
weight = 1430 weight = 1430
+++ +++
Variables declarations should be ordered by type. In general, object and complex variable types are listed first followed by simple variables. The order should be the same as the object list in the object designer for C/AL objects. Afterwards come the complex variables like RecordRef, .NET, FieldRef etc. At the end come all the simple data types in no particular order. Bad code Variables declarations should be ordered by type. In general, object and complex variable types are listed first followed by simple variables. The order should be the same as the object list in the object designer for C/AL objects. Afterwards come the complex variables like RecordRef, .NET, FieldRef etc. At the end come all the simple data types in no particular order.
StartingDateFilter@1002 : Text\[30\]; Bad code
Vend@1003 : Record 23;
```al
StartingDateFilter@1002 : Text[30];
Vend@1003 : Record 23;
```
Good code Good code
Vend@1003 : Record 23; ```al
StartingDateFilter@1002 : Text\[30\]; Vend@1003 : Record 23;
StartingDateFilter@1002 : Text[30];
```

View file

@ -3,15 +3,20 @@ title = "Actions - Images"
weight = 200 weight = 200
+++ +++
All actions must have an image assigned to them. All actions must have an image assigned to them.
Bad code Bad code
{ 7 ;1 ;Action ; ```al
CaptionML=ENU=Customer - &Balance; { 7 ;1 ;Action ;
RunObject=Report 121 } CaptionML=ENU=Customer - &Balance;
RunObject=Report 121 }
```
Good code Good code
{ 7 ;1 ;Action ; ```al
CaptionML=ENU=Customer - &Balance; { 7 ;1 ;Action ;
RunObject=Report 121 } CaptionML=ENU=Customer - &Balance;
Image=Report } RunObject=Report 121 }
Image=Report }
```

View file

@ -3,14 +3,19 @@ title = "CONFIRM"
weight = 380 weight = 380
+++ +++
Always end CONFIRM with a question mark. Always end CONFIRM with a question mark.
Bad code Bad code
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked'; ```al
... ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked';
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN ...
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
```
Good code Good code
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked?'; ```al
... ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked?';
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN ...
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
```

View file

@ -3,14 +3,19 @@ title = "FIELDERROR"
weight = 590 weight = 590
+++ +++
Never use FIELDERROR with a period as it is automatically inserted. Never use FIELDERROR with a period as it is automatically inserted.
Bad code Bad code
InvalidValue@1025 : TextConst 'ENU=is invalid.'; ```al
... InvalidValue@1025 : TextConst 'ENU=is invalid.';
Cust.FIELDERROR("No.",InvalidValue); ...
Cust.FIELDERROR("No.",InvalidValue);
```
Good code Good code
InvalidValue@1025 : TextConst 'ENU=is invalid'; ```al
... InvalidValue@1025 : TextConst 'ENU=is invalid';
Cust.FIELDERROR("No.",InvalidValue); ...
Cust.FIELDERROR("No.",InvalidValue);
```

View file

@ -3,14 +3,19 @@ title = "MESSAGE and ERROR"
weight = 790 weight = 790
+++ +++
Always end MESSAGE or ERROR with a period. Always end MESSAGE or ERROR with a period.
Bad code Bad code
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3'; ```al
... CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3';
ERROR(CustIsBlockedErr,...); ...
ERROR(CustIsBlockedErr,...);
```
Good code Good code
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3.'; ```al
... CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3.';
ERROR(CustIsBlockedErr,...); ...
ERROR(CustIsBlockedErr,...);
```

View file

@ -29,14 +29,14 @@ We are working on creating a set of rules, which would help keeping the content
[anchor0]: /nav/w/designpatterns/74.no-series.aspx "No. Series" [anchor0]: /navpatterns/1-patterns/no-series/ "No. Series"
[anchor1]: /nav/w/designpatterns/76.single-record-setup-table.aspx "Setup Table" [anchor1]: /navpatterns/1-patterns/singleton/singleton-table/setup-table/ "Setup Table"
[anchor2]: /nav/w/designpatterns/117.hooks-pattern.aspx "Hooks" [anchor2]: /navpatterns/1-patterns/hooks/ "Hooks"
[anchor3]: /nav/w/designpatterns/122.implementation-of-surrogate-keys-using-autoincrement-pattern.aspx [anchor3]: /navpatterns/1-patterns/implementation-of-surrogate-keys-using-autoincrement-pattern/
[anchor4]: /nav/w/designpatterns/104.easy-update-of-setup-or-supplementary-information.aspx [anchor4]: /navpatterns/1-patterns/easy-update-of-setup-or-supplementary-information/
[anchor5]: /nav/w/designpatterns/155.totals-and-discounts-on-subpages-sales-and-purchases.aspx [anchor5]: /navpatterns/1-patterns/totals-and-discounts-on-subpages-sales-and-purchases/
[anchor6]: /nav/w/designpatterns/123.using-cal-query-objects-instead-of-nested-loops.aspx [anchor6]: /navpatterns/1-patterns/queries/use-queries-to-replace-nested-loops/
[anchor7]: /members/bogdana-botez/default.aspx [anchor7]: /members/bogdana-botez/default.aspx
[anchor8]: /nav/w/designpatterns/107.template-for-writing-nav-design-patterns.aspx [anchor8]: /navpatterns/4-get-involved/template-for-writing-nav-design-patterns/
[anchor9]: /members/bogdana-botez/default.aspx "Bogdana Botez" [anchor9]: /members/bogdana-botez/default.aspx "Bogdana Botez"
[anchor10]: /nav/w/designpatterns/239.rules-of-conduct.aspx "Find the rules here" [anchor10]: /navpatterns/4-get-involved/code-of-conduct/ "Find the rules here"

View file

@ -163,5 +163,5 @@ And last but not least, we have collaborated with Plataan who hired Eric Wauters
[anchor0]: /nav/w/designpatterns/106.be-a-nav-pattern-author.aspx [anchor0]: /navpatterns/4-get-involved/
[anchor1]: /members/bogdana-botez/default.aspx "NAV Design Patterns project administrator" [anchor1]: /members/bogdana-botez/default.aspx "NAV Design Patterns project administrator"