Developer Digest Vol. 500: Not-so-Random Thoughts on Simplifying AL Code DevelopmentĀ
Calling Business Logic in a Codeunit from a Rec VariableĀ
The other day a colleague and I differed in our opinion of calling business logic in a codeunit from a Record variableĀ rather than calling the business logic from some other place, a Page for instance.Ā Ā
As he was debugging my code, he didnāt like that I had a Rec.DoSomething() which then calls MyCodeUnit.DoSomething(Rec), where the business logic resides.Ā
So, I thought about it and came to some conclusions:Ā
Encapsulation with Flexibility
- By adding a method toāÆRecāÆlikeāÆRec.DoSomething(), you provide a convenient way for other parts of the system to trigger the behavior directly on theāÆRecāÆvariable.Ā
- Internally, callingāÆMyCodeUnit.DoSomething(Rec)āÆkeeps the business logic centralized and decoupled from the record itself, promoting better separation of concerns.Ā
Reusability
- The business logic resides in the codeunit, making it reusable across different contexts or even other record types.Ā
- The method on theāÆRecāÆserves as a convenient wrapper, making it easy to use without requiring every caller to know about the codeunit.
Maintainability
- Since the core logic is in the codeunit, any changes to the logic require updates only in the codeunit, reducing the risk of inconsistencies and making the system easier to maintain.Ā
- The method on theāÆRecāÆcan remain simple, just passingāÆRecāÆto the codeunit.Ā
Testability
- You can still easily test the logic ināÆMyCodeUnit.DoSomething(Rec)āÆindependently, which is particularly useful for unit testing.Ā
- The method onāÆRecāÆcan be tested as part of Integration and Unit tests to ensure it correctly delegates to the codeunit.Ā
Readability and Usability
- The method on theāÆRecāÆ(Rec.DoSomething()) makes the code more readable and easier to use from the perspective of the Rec API consumers.Ā
- It hides the complexity of needing to know which codeunit to call, simplifying the interface for developers.Ā
Code ExampleĀ
Hereās how you would implement this in AL:Ā
Somewhere in code:Ā
Var SalesHeader: Record āSales Headerā;Ā
BeginĀ
Ā SalesHeader.DoSomething();Ā
EndĀ
table 36 “Sales Header”Ā
{Ā
Ā Ā Ā procedure DoSomething()Ā
Ā Ā Ā varĀ
Ā Ā Ā Ā Ā Ā Ā MyCodeUnit: Codeunit 50100;Ā
Ā Ā Ā beginĀ
Ā Ā Ā Ā Ā Ā Ā MyCodeUnit.DoSomething(Rec);Ā
Ā Ā Ā end;Ā
}Ā
codeunit 50100 MyCodeUnitĀ
{Ā
Ā Ā Ā procedure DoSomething(Rec: Record “Sales Header”)Ā
Ā Ā Ā beginĀ
Ā Ā Ā Ā Ā Ā Ā // Business logic hereĀ
Ā Ā Ā end;Ā
}Ā
Why use this technique?
This simple example shows how this pattern can be used and is a quite common practice by AL developers. In a real customer solution, you would see dozens of examples of this pattern with much more complexity. You can see that by calling the function from the Record variable, the developer doesnāt need to know about the complexity that exists in the business logic or even care if a codeunit is involved.Ā
Using this approach is often a best practice in Business Central development. It combines the strengths of encapsulation and separation of concerns, leading to a codebase that is easier to understand, test, maintain, and extend.Ā
Donāt miss these upcoming events
- Jon will present on āAutomated Testing in the Wildā at Directions for Partners: Days of Knowledge Americas 2024 in Atlanta, Georgia, September 12-14, 2024.Ā
- Be sure to join us at Community Summit North America 2024 in San Antonio, Texas, October 13-17, 2024.Ā