Design on AL Guidelineshttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/Recent content in Design on AL GuidelinesHugo -- gohugo.ioen-usBy Reference Parametershttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/by-reference-parameters/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/by-reference-parameters/Do not declare parameters by reference if their values are not intended to be changed. Unintentional value changes might propagate. Also, it might lead people to believe that value changes are intended. Bad code LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text\[250\]); BEGIN Text := GetMessageText; IF (Text <\> '') AND GenJnlLineInserted THEN MESSAGE(Text); END; Good code LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text\[250\]); BEGIN Text := GetMessageText; IF (Text <\> '') AND GenJnlLineInserted THEN MESSAGE(Text); END;Class Couplinghttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/class-coupling/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/class-coupling/Do not write functions that have high class coupling. This makes the code hard to maintain. Bad code Any procedure / trigger that has class coupling of \> 30 Good code Any procedure / trigger that has class coupling of <= 30\. Class coupling is computed by summing the unique instances of the following in a code block: - every unique usage of a complex C/AL data type (table, codeunit, etc) as 1\.Cyclomatic Complexityhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/cyclomatic-complexity/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/cyclomatic-complexity/Do not write functions that have high cyclomatic complexity. This makes the code hard to maintain. Bad code Any procedure / trigger that has a cyclomatic complexity \> 25, using the CC3 version mentioned in [this article][anchor0]. Good code Any procedure / trigger that has a cyclomatic complexity <= 25, using the CC3 version. The CC3 version is computed by summing the following in a code block: - each IF statement as 1\.Encapsulate Local Functionalityhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/encapsulate-local-functionality/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/encapsulate-local-functionality/Any function used local must be defined as local.FINDSET FINDFIRST FINDLASThttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/findset-findfirst-findlast/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/findset-findfirst-findlast/FINDSET, FIND('+') or FIND('-') should only be used when NEXT is used and vice versa. Bad code IF Cust.FIND('-') THEN ERROR(CustIsBlockErr) Good code IF Cust.FINDFIRST THEN ERROR(CustIsBlockErr) Bad code IF Cust.FINDFIRST THEN REPEAT ... UNTIL Cust.NEXT = 0; Good code IF Cust.FINDSET THEN REPEAT ... UNTIL Cust.NEXT = 0;Initialized Variableshttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/initialized-variables/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/initialized-variables/Variables should always be set to a specific value, before they are used. Bad code PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39); VAR Pegging@1001 : Boolean; BEGIN IF Pegging THEN CurrQuantity := CurrentPurchLine."Quantity (Base)" ELSE CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)"; END; Good code PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39); VAR Pegging@1001 : Boolean; BEGIN Pegging := IsPegging(CurrentPurchLine); IF Pegging THEN CurrQuantity := CurrentPurchLine."Quantity (Base)" ELSE CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)"; END; Bad codeMaintainability Indexhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/maintainability-index/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/maintainability-index/Maintainability Index: Do not write functions that have a very low maintainability index. This makes the code hard to maintain. Bad code Any procedure / trigger that has a maintainability index < 20 Good code Any procedure / trigger that has a maintainability index \>= 20\. The Maintainability Index is computed as a function: - Lines Of Code (inverse proportional) - the Halstead Volume - Cyclomatic Complexity (inverse proportional). More infoParameter Placeholdershttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/parameter-placeholders/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/parameter-placeholders/The number of parameters passed to a string must match the placeholders. Bad code CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.'; ... ERROR(CannotDeleteLineErr,TABLECAPTION); Good code CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.'; ... ERROR(CannotDeleteLineErr); Bad code CannotUseThisFieldErr@1020 : TextConst 'ENU=You cannot use this field for %2 fields.'; ... ERROR(CannotUseThisFieldErr,0,Field.Class); Good codeStatic Object Invocationhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/static-object-invocation/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/static-object-invocation/Call objects statically whenever possible. It reduces extra noise and removes extra variables. Downside: changing the name of the object which is called statically will need a code update. Bad code LOCAL PROCEDURE Code@1(); VAR CAJnlPostBatch@1001 : Codeunit 1103; BEGIN CAJnlPostBatch.Run(CostJnlLine); END; Good code LOCAL PROCEDURE Code@1(); BEGIN CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine); END;Unreachable Codehttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unreachable-code/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unreachable-code/Do not write code that will never be hit. It affects code readability and can lead to wrong assumptions. Bad code IF Type <\> Type::FIELD THEN BEGIN ... ERROR(...); RecRef.CLOSE; END; Good code IF Type <\> Type::FIELD THEN BEGIN ... RecRef.CLOSE; ERROR(...); END;Unused Initialized Variableshttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unused-initialized-variables/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unused-initialized-variables/The value assigned to a variable must be used. Else the variable is not necessary. Bad code PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]); VAR Vendor@1001 : Record 23; Count@1002 : Integer; BEGIN 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; END; Good code PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]); VAR Vendor@1001 : Record 23; BEGIN Vendor.Unused Variableshttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unused-variables/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/unused-variables/Do not declare variables that are unused. Unused variables affect readability. Bad code PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text\[50\]); BEGIN IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN ERROR(DateNotAllowedErr,Caption,EntryNo) IF PostingDate \> MaxPostingDate THEN MaxPostingDate := PostingDate; END Good code PROCEDURE CheckPostingDate@23(); BEGIN IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN ERROR(DateNotAllowedErr,Caption,EntryNo); IF PostingDate \> MaxPostingDate THEN MaxPostingDate := PostingDate; END; Bad code PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal; VAR ItemEntry@1000 : Record 32; Quantity@1003 : Integer; BEGIN EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE)); END; Good codeVariable Capacity Mismatchhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/variable-capacity-mismatch/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/variable-capacity-mismatch/Do not assign a value to a variable whose capacity is smaller. It will throw an error at runtime. Bad code FileName@1010 : Text\[250\]; ... UploadedFileName@1016 : Text\[1024\]; ... FileName := UploadedFileName; Good code FileName@1010 : Text\[1024\]; ... UploadedFileName@1016 : Text\[1024\]; ... FileName := UploadedFileName; Bad code FileName@1010 : Text\[250\]; ... UploadedFileName@1016 : Text\[1024\]; ... FileName := UploadedFileName; Good code FileName@1010 : Text\[250\]; ... UploadedFileName@1016 : Text\[1024\]; .WITH Scope Name Collisionhttps://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/with-scope-name-collision/Mon, 01 Jan 0001 00:00:00 +0000https://alguidelines.dev/navpatterns/3-cal-coding-guidelines/design/with-scope-name-collision/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? Bad code PROCEDURE InsertData@1("Contract Type"@1000 : Option...); ... BEGIN ... WITH ServiceContractHeader DO BEGIN .