You don’t get the chance to blog on the 29th of February too much. In fact, you only get one chance in 1461 days .. . So let’s take this opportunity, to bother you with something that I have been thinking about from the moment Microsoft Dynamics NAV 2016 was release:
What do we do .. Keep using hooks? Or use events instead?
Well, one thing for sure: Microsoft Dynamics NAV Events can’t fully replace hooks, just because of the fact that there aren’t enough of them .. or they are not raised on the places we need it to be raised. To give you an easy example: On Sales Line, OnValidate of the field “No.”, there is a lot of checking going on (lots of TESTFIELDS) in the beginning of the trigger. Well, it makes also sense to “hook in” as an OnBeforeValidate – but AFTER these checks. Which actually means: the default (in this case) trigger event can’t be used. Therefore, we’re still using hooks, like you see here:
The “OnBefore” is not really OnBefore, but actually “OnJustAfterAllTheChecks…”
In my opinion, we will always have these kinds of hooks – it will be difficult for Microsoft to foresee all possible places partners would want to hook into anyway. Not any code design or any pattern will foresee every possible hook. Then again .. applying some patterns will sure make up for lots of them ;-).
But anyway …
So, what is it then .. Events or Hooks?
Well .. let’s talk product development for a moment in terms of “execution order of events”. When you’re creating a product, you usually are creating processes, workflows, .. stuff that somewhat have a connection with each other .. although you’re as generic as possible 😉 .. but still, it makes sense that you are in total control over the execution order of about everything in regards to your business logic.
Well .. if you want to be in total control over your execution order .. basically .. you should make sure that you don’t subscribe to the same event too often. Well, how we facilitate this, is basically by not changing too much on our hook-design-pattern. It’s this pattern that actually make sure that we only hook in (or let’s call it “subscribe”) to a certain place within Microsoft-objects only once! And within these hook functions, we can still put our product-business logic. Hook functions would mean: a line of code into default objects (like shown in the picture above). To avoid this, we could basically use hooks in combination with events: subscribe the hook-functions if possible (if the existing events actually make sense).
So, in short – in my opinion – it’s not one or the other – but a combination of each other: why not doing events if possible in combination with hooks. Like:
– we declare a Hook codeunit
– we create an On… subscriber that subscribes to the event.
– all code goes still in this hook (calling out to methods and such…), which means: total control of execution order.
So, subscribing multiple times to one event is evil?
Most certainly not! In fact, there are design patterns that only make sense when using multiple describers .. or let’s say that are intended for it (I will post one soon .. it’s under review as we speak). But it’s just something that you need to be very conscious of. Every single multiple subscriber should be a very conscious decision.
Therefore, we have been implementing something what we call “an Event Helper”. A very simple functionality that is running “OnCompanyOpen” (no, in this case, we’re not using an event subscriber … checking events by using events just doesn’t make too much sense in my opinion – in this case, it’s “just” a hook 😉 .. but anyway.. that’s somehow besides the point). Basically, what the eventing helper does is:
- It gives us a better, more meaningful overview of all subscribers, which are subscribed more than once, errors, .. .
- Generates warnings and errors (depending on type of database (LIVE, TEST, DEV, …)) in case when subscribers contain errors (like mismatching parameters)
As you can see: very simple .. everyone can create this based on the “Event Subscription” table. Here’s a screenshot:
(yes, you can drill down on the “No. of Subscribers” to have a look at the subscribers)
One very important “Gotcha”
When working with hooks as being “subscribers to events”, means that your hook will always be executed as a new instance. You hook isn’t global anymore, so not part of the running instance of (for example) codeunit 80 anymore .. . This is something you need to manage. If your hooks have any globals or kept state – it will be lost! Now, you shouldn’t be dependent of globals in any case .. but fact is, in default NAV, the way it has been written in many cases (usually in the “old” cases), you are just very dependent of the instance of the object, the current context .. and you need this context to be preserved until you access the next part of your hook. Well, in this case, you might not want to do it with events. In this case, hooks are still the only way to go.
Spiderman’s uncle was a wise man. It was him that said: “With great power comes great responsibility“. And it makes sense for developers, doesn’t it? But I must be honest .. I don’t believe that we need to be more responsible now that we have eventing. Before, we could break the business logic just as easily as we can do today. There are just new options to break it :-).
But I love this new option. These events are powerful. And the more Microsoft will restructure their code (let’s assume they will), the more the default events will make sense. I even hope that at a certain time, we will have trigger-events on codeunit functions. This would make a lot of sense :-).
But until then, in general .. I keep on creating hooks, subscribe them whenever I can and keep my execution order under full control. I don’t know whether this is a new pattern or an extension on the Hook Pattern .. but does it matter ;-)?
In the meanwhile, all there is to say about it is: this is just my personal solution based on my personal opinion, which I shared in my personal blog 😉 – basically meaning that I don’t want to force anything upon you (how is that as a disclaimer :-)).