Dynamics NAV

Wednesday, 24 December 2014

Hooks Pattern in NAV

What is Hooks Pattern?

When doing development over years, by different developers with different mind-sets, the standard code base gets changed a lot, adding multiple lines of code, adding local and global variants, adding or changing keys, changing existing  business logic.  In other terms, the standard text objects are being changed all over the place.
After years, it's not clear why a change was done, and what was the place where the change was intended to be done.  And the latter is quite important in an upgrade process, when code in the base product is being refactored: if the exact place of the posting of the Customer Entry is being redesigned to a separate number, the first thing I need to know, is that I did a certain change at the place: "where the posting of the Customer Entry starts".  The definition of that place, we call a "Hook"
Hooks Pattern follows the below process
First of all, name the places in the already existing code where customization is needed, All objects of the default applications that need to be changed
·        Second, place your business logic completely outside the already existing application code.
  On objects that should not hold any customized business logic (like tables, pages, XMLPorts)

Process:

Step1 - create your Hook code unit. This is always a code unit.  We apply the following rules to it:
  • One Hook always hooks into one object.  Which basically means that I will only declare this new code unit in one other object (which is its parent object)
  • The naming convention is: The_Original_Object_Name Hook.  Naming conventions are important, just to find your mapped object, and also to be able to group the Hooks.
Step2- you create the hook, which is basically a method (function) in your hook code unit.  The naming is important:
  • The naming of the hook should NOT describe what it is going to do (So, examples like CheckMandatoryFieldsFillCustomFields should not be used as a hook)
  • The naming of the hook should describe WHERE the hook is placed, not what the hook will be doing (as nobody is able to look into the future 
  • To help with the naming, it is a good convention to use the "On"-prefix for these triggers.  This way, it's very clear what are hooks, and what aren't.
Step 3- it's time to hook it to its corresponding object and right place in the business logic of that object.  You do this by declaring your code unit as a global in your object, and using the created hook function on its place in the business logic.  This way, these one-liners apply:
  • A Hook code unit is only used once in one object only (its corresponding object)
  • A Hook (function) is used only once in that object.  As a consequence, changing the parameters has no consequence: you only need to change one function-call
  • The code unit is declared as a global.  That exact global is the only custom declarations in the existing object. Everything else is pushed to the hook-code unit.
Step 4- implements your business logic in the hook.  Do this in the most atomic way, as there is a good chance that this same hook is going to be used for other business logic as well.  Best is to use a one-line-function-call to business logic, so that the Hook Function itself stays readable.

Example

Suppose, we want to add business logic just before posting a sales document.  In that case, we have to look for the most relevant place, which is somewhere in the "Sales-Post" codeunit.  So:
Step 1: create code unit Sales-Post Hook:

 

 Step 2: create the hook function OnBeforePostDocument:
Step 3: declare a global in the "Sales-Post"-codeunit, called "SalesPostHook".  Then, call the Hook Function that you created in Step 2 in the right place.
 
Step 4: implement the business logic, by calling out to a new function.  And implement the test-code unit. 

Pros:

·        It will make the upgrade process much easier.
·        It will be very readable what is being customized on a certain place in an existing part of the application.
·        It is specially help full in handling large customization.
·        It easy, elegant, and very manageable.
·        Some time we can re-use the code.
Cons:
·        We have to keep Standard function and hook functions in sync always.
·        It is mostly not useable, when most changes happen in the more places in one object.
·        Making tricks and putting code in different places is making code hard to read and un-necessary complex.
·        It may increase the add-on cost because of extra objects and extra time(Assumption)
·        We can’t use in-built functions in Hook code units like currPage.xxx,
·        Test the whole functionality.
·        More investment and less benefit, because Microsoft already released merge tool from NAV2015, it saves our merging time.
Risks: 
·        Time factor, only the add-on is already developed without hook
·        Cost, it needs to more time for refactoring the whole logic.
·        Hook code unit naming conventions might collide when the application is using more than one add-on from different partners. Suppose three different partners are using the same hook name like sales post-hook with three different ID, system doesn’t allow while importing the objects.
·        Hook functions naming conventions is always as challenge. It must be easily understandable when we have multiple hooks in the same trigger.
·        It is always complex while merging\upgrading objects when the source version doesn’t have the hook pattern and destination version has, in case of customer has more add-ons from different partners.

·        Current record fields return variable and global variable handling is very complex.

No comments:

Post a Comment