If there was a Pattern of the year award, last year the Arguments table would have won. The year before the Hook pattern. Or maybe that was the year before.
This year in my opinion it is the Handled pattern by Thomas Hejlsberg in combination with Events. It is not yet published by Microsoft on the wiki, but let me try to explain how it works and why I like it.
Before explaining the pattern we have to talk about events. For this I would like to refer to a previous blog I wrote about this. In this blog I explain the challenges we have with multiple subscribers being executed in random order without each knowing that there are other subscribers.
There is quite an easy way to “handle” this. Which is the handles pattern. Briliant in simplicity.
At various events such as Directions and NAVTechDays Thomas used a calculator as example. The idea is to make a calculator extendable.
Normally a calculator has the possibility to add up and subtract. We allow others to extend our calculator hence we put in an event. However, if someone “handles” the math, we don’t want our code to execute.
Also if there are multiple events, only one is allowed to handle the event. We don’t want multiple calculations to be done, only one.
For this to be ensured, the event is extended with a “Handled” parameter. Each subscriber should question this flag and exit if someone else has already done the math.
Nice example and easy to understand but it kinda sucks from a business case perspective, so let’s lookt at it in the “traditional” Partner Ready Software example. The weighing scale.
At almost all Partner Ready Software presentations and at my NAV Skills workshop I use the example of what if you have a business case where you need to know the weight of an item. Your customers have scales that have different interfaces. As a software architect you are only interested in the weight, not how to get the weight. It is a perfect example for loosely coupled code.
For this in NAV2016 we can leverage events. During one of the Knowledge Transfer sessions (AKA Katie Sessions) I made a comment that events would replace Façade. And it does to a certain extend together with the Handled pattern.
If you expose your weight requirement as an event you implement loose coupling and others can subscribe to the event and return the weight.
BUT! You only want one weight. You don’t want two events to return it.
This is where the pattern comes in.
Yeah Mark, a lot of bla-bla-bla. How do I implement this you ask. Let me explain you in the same way I explain the attendees of my Master Class. For free. ;-)
Note: I am open to suggestions. Please provide feedback. I understand that this is not the perfect example so I am also open to other (better) business cases.
The first step is to implement the setup requirements. The customer (end user) should be able to setup which scale they have. Hence we need a scale table and a setup table to store the scale code.
This is displayed in this image:
Now we have a table with multiple scales and one selected preferred scale. Now we need the event and a caller for the event. Let’s start with the event publisher.
You can see that I call the codeunit Façade. Reasoning is that it is still a Façade codeunit, but instead of hardcoding the options we can now call a published event. We do that from a global function that we can call from each table in the system. I’ll come back to the details later.
The event is a Business Event. Another concept that is too much to explain in this post, but bottom line is that a Business Event never changes. If you look at the signature of the event this makes sense. A variant, an Arguments table and the Handled flag. Chance of this event ever changing is next to nothing.
Now we can have event subscribers. Let’s look at the code for one of these guys.
The event subscriber has a default code pattern which we know from other blog posts and videos. Test Near, Test Far, Do It, Clean Up.
If someone has handled the event, do nothing
Am I the scale in the setup? If not then exit.
Calculate the Weight, this is where you will probably call a Web Service or a DLL.
Set the Handled flag so you are sure nobody else gives another weight
While Do Repeat
Each Scale Codeunit has a similar structure. Let’s see what happens if we call the code from a table and a page. We will do this using the Class-Method-Property model. The code is on the table and called from a page.
We can very simply copy and paste this function to other tables that have the same requirement.
Holes in this example
This example has a couple of holes. First of all, I don’t use the variant. I just show it as an example of how to be flexible, and turn this into a Business Event. If ever I need it in the future it is there.
Another thing is that the setup also take care of the fact that only one scale can return weight. The handled is only implemented as an extra safety and to check if there are any subscribers.
The Handled flag can also be added to the Arguments table. For this I am looking for feedback. Do you think that makes sense? Or should the signature for this pattern always be “Variant”, “Arguments”, “Handled”
My Arguments table only has one field. Weight. This allows also for future flexibility.
Façade & Arguments
The Façade is one of the early Partner Ready Software patterns but the problem with the pattern previous to NAV2016 was that we could only have CODEUNIT.RUN for ultimate flexibility. This is, also according to Microsoft feedback, just a little too much flexibility. If your contract is only the parent record you cannot ensure code execution for what it was designed. There was a workaround for that which I used to teach in my Master Class before NAV2016 came out.
Variant, Arguments & Handled
The combination of Variant, Arguments and Handled with Events finaly gives us the option of implementing loosely coupled code while having a strong contract, which is the Arguments table. The arguments table should only be used for one event. Each event has its own Arguments table.
Once you start reusing the arguments table people can mix events and subscribe to events without guaranteeing that the code was intended to do what the business case required.
You can enhance this pattern by changing the Handled from a Boolean to an Integer. This way the caller can count the number of event subscribers if that makes sense from a business case perspective.
You can read more about the Variant Façade pattern on the Microsoft Wiki. Nicola did a great job explaining the pattern.
The arguments table is explained on my blog, and was published a week later on the Microsoft wiki, again by Nicola. You can also learn about this on the recording from NAVTechDays 2014 and on one of my How Do I videos.
As you might have noticed the code is written in my example database I also used for my book and the Microsoft How Do I videos.
I’ll put those files on my Git asap.