2
One of the biggest elephants in the room and an undocumented feature in AL is the fact that a good old Record variable type can completely change behaviour depending on what code has executed before it, when inside the same database transaction.
Given that the entire extension model of MS for the baseapp and all ISVs is built upon using event subscribers, this is a platform gap that makes it harder to address technical compatibility between apps in a robust manner.
An example that explains what I mean:

procedure InnocentLookingFunction()
begin
OnBeforeInnocentLookingFunction();

Item.SetRange("Unindexed Boolean Field", true);
if not Item.FindSet() then
exit;

repeat
//Read data from item record and write into another table. No modifications or writes on Item here!
until Item.Next() = 0;
end;


The problem arises if another app subscribes to OnBeforeInnocentLookingFunction() and touches the Item table in any way, even using its own local record variable: By doing Item.Modify() on a single record or Item.Insert() on a single record.
This will escalate the Item table to generate "UPDLOCK" SQL queries in the remainder of the entire active transaction meaning that the loop in the function above will now be locking records with a filter that is unindexed.

When this happens on the boundary between two (or more) extensions you have this risk of breaking the result of all the code routines that can each look fine when read independently of each other. If you stop and think about more realistic examples than the one above you will realize that this would most likely happen between two different developers in two different companies that didn't even realize the risk until it occurs. And there might be no one to blame, because developer A changes extension A slightly with what should have been a non-breaking change, but since developer B had done extension B with a subscriber to A ages ago for one specific use case, it blows up in prod with huge locking issues.

Today, the only way to get out of this risk of implicit magic of the record variables, would be to either Commit() or use Query objects instead of FIND functions everywhere where events are published, to avoid the risk of context being modified from a subscriber.
It is obviously not best-practice AL code to use Commits() or Query objects EVERYWHERE, and the BaseApp has this risk in many places.

A slightly different version of the same problem occurs when multiple subscribers to the same publisher modify the overall record context for each other, even though they all use local record variables.
This can again, make code that "works fine" independently of each other, work terrible when installed as multiple apps on the same tenant.

Suggestion:
Allow more control in the language via a new attributes that could be placed on EventPublishers to isolate any record context to the inner scope of any event subscribers:

[IsolateLockingContext]

This would fit perfectly together with the new [CommitBehavior] attribute that you recently added, allowing more precise and robust design of public AL APIs.
An example of what a library developer could do with above features:

procedure PopularFunctionThatEveryoneWantsToExtend()
begin
OnBeforePopularFunction(); //This publisher would have [IsolateLockingContext] to prevent later code being impacted by the "record variable magic" described in this Idea.

//Do work

OnAfterPopularFunctionBeforeCommit() //This publisher would have both [IsolateLockingContext] and [CommitBehavior::Error] to isolate the context of each subscriber and prevent any of them from committing manually.

Commit();

OnAfterPopularFunctionCommit(); //This publisher would be intended for subscribers that want to process the final result, i.e. for invoking another system via HTTP when data is known to be committed.
end;
Category: Development
STATUS DETAILS
Needs Votes
Ideas Administrator

Thank you for this suggestion! Currently this is not on our roadmap. We are tracking this idea and if it gathers more votes and comments we will consider it in the future. Best regards, Business Central Team

Comments

M

This idea was implemented in BC20.0:

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-events-isolated


Thanks!

Category: Development