Customizations are unavoidable, and we often need to change “Out Of Box” behaviors to fit the needs of the business. This makes us cringe a little, knowing that our modifications will create an upgrade conflict–forever into the future.
So, let’s ponder how we can customize OOB scripts while avoiding these unpleasant upgrade conflicts. Let's consider the worst case scenario–that major OOB script include which needs to change. How do we customize its behavior without modifying it? The solution is actually quite simple, using the object-oriented concept called inheritance.
JavaScript implements inheritance by extending the object, as in this example. Notice ServiceNow is extending the ActivityUtilsSNC object, which is read-only.
Thus, ActivityUtils inherits all the functions of its parent: ActivityUtilsSNC. Even though you don’t see them, you can still invoke them from ActivityUtils. Here’s an example of another script invoking ActivityUtils.
Later in that script, they invoke its function.
ServiceNow has provided this extended object for us so we can 1) add new functions to it and/or 2) modify its functions without incurring a hit on our next upgrade. ServiceNow upgrades the SNC parent object and extends it to an object we can customize. Nice.
But what if ServiceNow doesn’t have an extended object? No problem. We’ll make our own. That way, we can customize the behavior of the OOB object via our custom extended object and avoid an upgrade conflict.
Let’s build a pair of objects to test how this works on the ServiceNow platform. We’ll use a background script as our sandbox. We can thus test parent-child behaviors before we start coding our solution. Here’s our parent object;
Now let’s extend it and override the parent object’s functionOne(). We’ll then instantiate the child object and call our new version of functionOne().
Line 20: We’re invoking the parent object’s functionOne() right inside our override of that function. You don’t have to do this. But it’s sometimes handy, when you want to do all the stuff the parent does and then do more after it.
Line 22: We can invoke other parent object functions as if we were the parent object. Nice. This demonstrates that the child object has full access to everything inside the parent.
Running this in a background script gives us this output:
*** Script: initialize myParentObj. var1: Hello
*** Script: myParentObj.functionOne(): Hello World!
*** Script: myChildObj.functionOne(): WhatsUP World?
*** Script: myParentObj.functionTwo(): HELLO!
If we need to adjust the parent object’s variables in the initialize() function, we can simply override it. Best practice is to invoke invoke the parent’s initialize() function, then add your stuff after, like this:
Notice that line 20 overrides the parent object’s variable by the same name! So, the child object can override parent attributes.
Running this version yields the result:
*** Script: initialize myParentObj. var1: Hello
*** Script: initialize myChildObj. var1: WhatsUP
*** Script: myParentObj.functionOne(): WhatsUP World!
*** Script: myChildObj.functionOne(): WhatsUP World?
*** Script: myParentObj.functionTwo(): HELLO!
Using this object-extension strategy can be helpful, but there’s a rub.
But what if the OOB business rule is invoking the OOB script include and not an extension of it? This is the rub, yes? The upside is that it’s generally easier to remediate a business rule than a script include during the upgrade process–if we ignore those ugly, 200-line business rules, which we won’t talk about.
Several strategies for avoiding–or at least minimizing–an upgrade conflict regarding business rules exist.
I recommend option #3 only if you’re dealing with a before business rule, where you can modify data before it is written to the database. Once data hits the database, there are numerous things in the platform that can trigger other processes. At that point, it’s generally too late to amend the targeted OOB behavior.
As software engineers, we strive to craft solutions that don’t generate additional maintenance overhead. I’ve mentioned a few strategies for minimizing upgrade conflicts, and I’ve included the code for testing object-extension behaviors below. Try it out and see how to employ extended objects in your solutions.
Interested to learn more? Reach out to us at chat@rapdev.io