The CreatorCon Call for Content is officially open! Get started here.

Martin Ivanov
Giga Sage
Giga Sage

Hardcoded values: I know that this topic has been discussed many, many times. Hardcoding is something you do not want to have in your code base if you name yourself a good developer. This applies not only to ServiceNow scripting, but to scripting in general.

 

If we assume that loops and conditional statements are the A and B of scripting, then avoiding hardcoded values must be somewhere around C or D. It must be part of the curriculum of every single programming course, and I know it is. My coding teacher was calling them magic numbers. Yet, I find hardcoded sys_ids and encoded queries here and there.

 

That is why I decided to write yet another article on the topic and show how I am doing it.

 

I usually follow two approaches – based on the customer and the established scripting practices, I can decide to use either of them or use them in combination. Both can be found in ServiceNow native production code.

 

Let’s dive in.

 

Option One: Use system properties.

If this the first time you hear of system properties, this is nothing more than a ServiceNow table 'sys_properties' where you can define key-value pairs, on which you can then base your business logic. There is a GlideSystem() method gs.getProperty() which accepts the key (name of the property) and returns its value. For more information, check out the GlideSystem API documentation here.

An example of such property (there are thousands of them OOTB) is 'com.snc.incident.copy.enable'.

It is a system property with the help of which admin personas can enable or disable the copy incident feature, as stated in the description.

MartinIvanov_0-1675350902192.png

 

Naming conventions usually follow the product/scope to which the property relates, but not necessarily. It can be any sequence of characters, also known as a String.

Now let’s see how can we make use of these in our scripting.

Imagine that you have the following business rule, which sets default assignment group for each new incident:

MartinIvanov_1-1675350902195.png

 

Anyone, different from the business rule creator will not be able to identify who is the default assignee, because this is a… hardcoded sys_id and does not speak at all. In fact, the business rule creator will not able too 😊

To make it readable, we can add comments, but still, a hardcoded sys_id – if a change is needed, it must be done by someone with programming knowledge.

We can solve these problems by moving the sys_id into a system property with a proper naming and edit the business rule to get the property value.

MartinIvanov_2-1675350902197.png

 

MartinIvanov_3-1675350902199.png

 

This business rule, along with the newly created system property will work exactly the same way as the first version of the business rule will, but:

  • It does not require pro-coders to change the default assignee.
  • Has proper naming and shows clearly who is behind the sys_id
  • Provides description and guidance on how to quickly change the value

 

Option Тwo: Use script includes to store constants.

This is another popular approach used by ServiceNow in their own code.

Example of such OOTB script include is IncidentState()/IncidentStateSNC(). This is a place where incident states are defined as constants.

MartinIvanov_4-1675350902204.png

 

Looking at that example, one can quickly conclude that this business rule:

MartinIvanov_5-1675350902205.png

 

Is way more readable than this one:

MartinIvanov_6-1675350902213.png

 

 

Looking at the first piece of code, even non-technical person can see that we are aiming to set the state to NEW. Looking at the second, even a technical person cannot be sure what’s behind the magic value of '1'. What the heck is '1'?

Apart from the added value of readability, it also adds value to the maintainability. Imagine that, due to some reason, you have 12 business rules that are setting the incident state to New, but following the second approach – with the '1' hardcoded in the business rule. And imagine that, due to some other reason, you need to modify the incident NEW choice database value from '1' to '11'. You need to go through all these business rules and modify the value in the script with the new value – '11'. Which is as much self-descriptive as its predecessor...

In the same situation, if you have used constants instead, the same thing could have been achieved with by adding a single charecter to the code – in the Constants class (script include), where you would replace the value of the constant IncidentStateSNC.NEW to be equal to '11' instead of '1'. And the magic is done. Everything will work without the need of further changes on the business rules.

Hope that will give enough reasons for more and more people to incorporate scripting best practices in their daily scripting challenges and make not only ours, but their own lives easier too!

Happy coding!

 

Feel free to spread across your network. Thank you!

Martin Ivanov

Developer MVP 2023
Community MVP 2023

Comments
Community Alums
Not applicable

For the sake of conversation:

 

These are good rules of thumb for coding in general but can easily be taken for granted, as in, "We have always done it this way." When inventing a constant, ask yourself some questions:

 

  1. Does using a constant, defined elsewhere, clarify the code? Math.PI is good.  IA.PI = 4 is bad. (Remember Indiana Bill #246 of 1897?)
  2. Is the value unique and does it represent itself clearly?
  3. Would a comment be just as effective?
  4. Will changing the property value break the code? Have I tested the code with alternate values?

I would submit that constants are unhelpful in ServiceNow scripts when defined for:

 

  1. Table Names and Field Names. (1: No, 2: Yes, 3: Meh, 4: Yes)
  2. Descriptive choice values like '1 - Critical' or 'work_in_progress' (1: No, 2: Yes, 3: Meh, 4: Yes)
  3. Sys IDs that represent core system constructs. (1: No, 2: No, 3: Yes, 4: Yes)
  4. Queries that should not be changed because the code relies on them. (If the query establishes a precondition the code relies on, and someone can remove those clauses, the code will break.) (1: No, 2: Yes, 3: Required, 4: Yes)
  5. Messages for Translation. Unnecessary for specific phrases, necessary for common ones.(1: No, 2: Yes, 3: Meh, 4: Yes)

When faced with only a crummy Rhino debugger, a developer typically has to take more manual steps when code they did not write refers to constants defined in a galaxy far, far away. With a proper debugger, I can see the value represented by the constant at the place of reference and confirm that it works how I think it does. Without that, I have to take extra steps to track down the value. I get huffy when I stumble across something like MY.BREADBASKET = 'BREADBASKET' 😁

 

I differ on Sys IDs because they are globally unique and Studio code search is reasonably robust. If the Sys ID represents an out-of-box construct that should never be deleted or replaced, defining a property is misleading. An admin who stumbles across your property could take it as license to mess with the out-of-box construct. A constant can be useful, but a comment is just as effective. If you can find an out-of-box constant, then definitely use that.

For properties like a default user or reference to some other table with natural keys, consider using the natural key (User ID) instead of the Sys ID.

Version history
Last update:
‎02-02-2023 01:00 PM
Updated by:
Contributors