cwhaley
Kilo Expert

One of the most consistent development activities related to ServiceNow implementations and enhancements is integrations.   As ServiceNow becomes more and more entrenched in the critical operations of an enterprise, the more important it is to make information readily available to users and other systems.   This not only enables better collaboration between business units and customers, but also oftentimes results in significant efficiency improvements and cost avoidance. In this blog article, we will be exploring a few essential practices that will help you ensure that your integration planning and development efforts result in a quality product that is both scalable and supportable.

Essential #1:   Good Preparation and Planning

We developers have all been there at one point or another.   A task must be done, it's urgent, and the time is now.   You have the technology, you can (re)build it.   Make it so.   (Ok, sorry, no more Sci-Fi references)   Unfortunately, these 'go fast' directives often result in a sacrificed end-result.   For most of us, the actual development is the fun-part, so these directives also tend to meet little resistance.   We turn on some tunes (Turn Me Loose perhaps?) and get at it.

Ah, fun times!   Until that burst of short-term fun switches to become long-term misery for everyone involved, especially the developer. Avoiding that misery simply takes a little bit of patience on the front end.   Step back and take time to think through every aspect of what is being requested.   Ask yourself:

  • Who will be contributing to this integration?
  • Who will be benefiting from it?
  • Which systems "own" the data and which ones need to see that data?
  • How much data will be searched or exchanged?
  • How often does data need to be seen or exchanged?
  • What technology options are available (SOAP, REST, FTP, etc.)?
  • How will any of the above change in the next 6, 12, 36 months?

All valid questions, but none more critical than that last one!   A change to any of those bullets could significantly alter your design and approach to integrating.   Understanding the future needs and demands of your client/customer is a key factor in ensuring what you develop can grow and mature along with their business.


Essential #2:   Logging Consistency

Troubleshooting a solution shouldn't be like attempting a play-through of Oregon Trail…where you have to decide between opening the entire syslog or navigating through pages and pages of debug mode content, either of which could result in a broken arm or dying from dysentery (or even from dissing Terry).   You can still take a choose-your-own-adventure approach to developing your logging, but it needs to be the most boring version of a choose-your-own-adventure ever created.   It should be one where:

  • The questions are always the same.
  • The number of possible answers is always one.
  • The successful (winning) path is obvious and known to everyone.
  • In essence, it never changes…

So yes, you can still leverage debug mode, use the syslog, generate alerts, pop in a few addInfo/ErrorMessage lines.   Go for it and knock yourself out (not literally though, that would totally cost you like 400 food and make it impossible to make it 42 miles to that next landmark).   The point is that you should use these consistently and in a way that is intuitive to both users and other developers.   Here are the general rules I live by, take them for what you will. One caveat, this is mostly server-side development oriented, because integration development tends to be almost entirely server-side when it comes to the actual integration work.

  • Debug mode — I always build a debug mode into my Script Includes to allow me to set varying levels of verbosity to my logging.   Why do I do this?   See the next bullet…
  • Using .log() — I simply don't bother using .print() and, instead, use .log() in a way that won't fill up the syslog with garbage log messages.   In order for this to work efficiently, two critical pieces need to be in place.   First, I need to use the "source" field (gs.log("my log message", "MyIntegrationSource")).   This will allow me to create pre-filtered modules and links to quickly access only the relevant log messages.   Secondly, you need to incorporate the debug approach mentioned above.   Using a debug mode allows me to do this in a way that gets me an easily reference-able log without cluttering up said log.   This works especially well for the moment because many companies still aren't on the Dublin release (or newer) yet.   It will be less so once everyone is on Dublin.
  • Using .addInfoMessage() and .addErrorMessage() — Ok, don't get me started on why there is no ".addWarningMessage()," but I often used to get asked when to or not to use these methods.   My general response has always been to use them whenever you need to inform a user that something has happened (info) "on their behalf" or broken (error) "without their knowledge" in the background.   For example, if you created an additional task because of how they categorized something, you use an info message to inform them of it.   The big point here is to NEVER USE .addInfoMessage() or .addErrorMessage() for logging purposes.

Essential #3:   Event Management and Error Handling

So we've talked about good planning and logging, but what happens when something goes wrong? Unless Batman decides to change careers by becoming the "caped developer," (and, you know, becomes a real person) I don't think generating a light in the sky with the outline of a bug in it is really going to accomplish much.

No, unfortunately it's up to us and it's not an easy task.   Knowing programmatically the difference between when something is a simple informational bit of data versus an event and when that event becomes an incident/problem is one of the most difficult (and hotly debated) concepts in event management implementation.

Much like logging, there is no one answer here, but there are some general guidelines you can go by when it comes to integrations:

  • Validate your data — When data exchanges hands in an integration, it is important to validate that what you got is what you expected.   Check for errors in the data by comparing it to the known data model you are expecting, something SOAP and REST (using json or xml) make particularly easy to do.
  • Don't be afraid to retry — Yes, it failed, that doesn't mean it will fail again.   Always retry (within reason) before assuming all is lost.   As far as event vs. incident goes, I typically perform 2 retries (total of 3 attempts) with a small wait in between.   After 3 concurrent failure events, I consider it an incident and open an incident ticket.
  • Give it time — Timeouts are a necessary evil with integrations, and it is critical that you build these into your integrations and react to them appropriately. ServiceNow will protect you by timing out sessions, but you still have to timeout your own background tasks and retry cycles.   Treat a timeout similarly to a failure whereas 3 concurrent timeouts results in an incident.

Finally, make sure you know WHOM to engage and with WHAT detail WHEN errors happen.   Creating an incident with very little detail (i.e. did it timeout or fail, what was the error code) and assigning it to a Level 1 — Help Desk for routing isn't going to make that Help Desk very happy and certainly won't result in a swift restoration of service.

…note to self:   become a fictional person and see if Commissioner Gordon can help me convince Batman to change careers.

Essential #4:   Developing for Instance Awareness

Ever notice how men stereotypically never want to ask for directions?   Well, your ServiceNow instance won't either.   I can't begin to count the number of times I've heard horror stories about issues with an integration caused by code promotions from a dev/test environment to prod.   Most of the time, the issues caused are related to the fact that a dev or test environment is "integrated" with another dev or test environment (and subsequently prod to prod).   If your code isn't aware enough to tell the difference between environments, you are likely to run into the case of a small change causing a big problem.   Yep, your coworker's addition of a single field to the integration has now inadvertently caused production ServiceNow to start integrating with development ACMESoftware.   Another good example is a clone of Prod over Dev…great, now ServiceNow Dev and Prod are BOTH talking to ACMESoftware Prod.     Fun times…

Luckily, this is easily avoidable using a few simple methods.

  • Use system properties — Create system properties for your endpoints and major connection information and be sure to incorporate the INSTANCE NAME into your property name (more on that later).   So, for a SOAP integration, you may end up with 3 different endpoints saved in system properties.   Examples:
    • snowprod.acmeprod.endpoint
    • snowtest.acmetest.endpoint
    • snowdev.acmedev.endpoint
  • Generate your endpoints — Now that you have your system properties for your endpoints (and other connection details), you can use instance-specific data like, say the instance_name system property to automatically pull the correct endpoint based on the instance you are in.   Example:
    • In this example, the value of the instance_name system property is "snowprod"
    • var myEndpoint = gs.getProperty('instance_name');
    • myRESTConnection.setEndPoint(myEndPoint);

There you have it.   By using system properties, aligning multiple system properties with the instance names, and writing your code to leverage this assumption, you have essentially made your integration instance aware. Congratulations, you'll never have to ask for directions again…cliché "I'm not lost, I'm just exploring" conversation averted.

Essential #5:   Finding your Complexity Balance

Ever seen those power yard tools that have "attachments" for everything under the sun?   Look!   It's an all in one weed eater, saw, hedge trimmer, auger, pressure washer, blah blah blah.   I'm not sure about you, but I'm not looking forward to the day where my lawn mower can also brew my morning coffee.   Sure, having everything rolled into one can seem really nice and simple, but break one component and now you can't weed eat, saw, hedge trim, dig holes, etc. Need to find and fix that one component? Hahahahahaha...

All joking aside, this is an amazingly easy problem to run into when developing integrations.   We want to automate as much as we can (see Essential #4), but we can get carried away.   Even the tools at our disposal almost seem geared toward encouraging this behavior.   Look at the REST Message module in ServiceNow, for example.   It breaks out the REST Message functions based on the core HTTP methods of GET, PUT, POST, and DELETE.   Rather than let you define custom ones and assign what method to use. What if my endpoint changes depending on the resource I'm using?   Well, there are two routes:

  1. VARIABLIZE! — Yes, the time-honored tradition of using a bunch of variables and lines of code to automatically build something…an endpoint in this case.   Using this approach you would build out the endpoint using variable parameters and then, in your code, manually build your endpoints.
  2. SIMPLIFIZE! — Ok, I made up a word…I do this once daily, get over it.   Taking a complex component and breaking it up into simpler components shouldn't be a foreign concept to developers.   We do this all the time with classes in Script Includes by breaking out pieces of work and automation into smaller reusable methods.   In the case of our example here, the result would be multiple REST Message records, one for each resource and endpoint structure being worked with.


Ok, so you get that, but why one or the other and when?   Well, they each have their benefits and weaknesses:

  • VARIABLIZE!
    • Key Strength — Highly automated and typically scales well, no need for extra 'data entry'.
    • Key Weakness — Susceptible to major outages due to centralization of connectivity.
  • SIMPLIFIZE!
    • Key Strength — Easier to troubleshoot/fix, less susceptible to bugs and outages because an issue with one resource won't affect all others.
    • Key Weakness — It doesn't look as cool or is as hard (read: fun) to develop! NOOOOOOOOOOOO!!!   Seriously though, scale can be a problem here if there are hundreds of resources…but that's rare.

There is no right or wrong answer here, because both paths will get you to your destination.   It's up to you to decide with his more appropriate based on the scale and scope of the integration as well as the skill level of the individuals you intend to support it.

If you aren't sure which path to take, imagine writing a support manual (runbook) for a Level 1 helpdesk on how to troubleshoot a connectivity issue.   Do you want to have to document easy step-by-step do-this-then-that directions for the variable approach or the simplified one?   Yea...me too.

Disclaimer 1:   Yes, my Essentials #4 and #5 are a bit hypocritical when discussed in the same context.   No, I don't care…I'm still a developer at heart, so I get to do these things.   Give me that much.

Disclaimer 2:   No, I didn't specifically say which way I would go with #5.   I like to be mysterious…but obvious is obvious, obviously.

Disclaimer 3:   Pointless Disclaimer is pointless

6 Comments