Expand your SuiteScript skills in the Sustainable SuiteScript community for NetSuite developers.

Magic Strings - the Anti-Pattern

Created: October 22, 2020

Having just told you I'll be writing about design patterns, I'm immediately coming to you with an anti-pattern - the magic string.

A "magic" value in development is a seemingly arbitrary literal value in your code ("eric", 72, "abdc1324") with no explanation as to what the value means. They can be a gigantic code smell.

I see magic values all the time in SuiteScript.

Can you spot the magic values here?

if (rec.getValue({ fieldId: 'entity' }) === '358725') {

The first one is "entity". Now personally, I don't mind at all using magic strings when specifying field, filter, or column IDs - basically any of the values that come from the NetSuite record/search schema. These are extremely unlikely to change and are generally self-descriptive enough that you'll know what they mean if you have just a bit of SuiteScript experience under your belt.

But what about "358725"; what the heck is that? Based on the context we can probably reason that it's the internal ID of an Entity, but which one? We don't even know which type of entity it is. Customer? Vendor? Contact? Without detailed commenting in every single place this value occurs, we are left clueless, and requiring detailed commenting of simple code like this in multiple places is itself a code smell.

Wherever possible, code should be self-descriptive, not requiring extensive comments to explain. Also, I hope the internal ID of that Entity never changes - say, after a Sandbox refresh. Find/Replace isn't foolproof.

What if instead, this same condition looked like this:

if (rec.getValue({ fieldId: 'entity' }) === enums.Vendors.Printful) {

That should make it pretty obvious - with no comments necessary - exactly which Entity we're looking for.

What's probably not obvious is enums. First, it's the alias I give my enumerations module - a module I create in every single SuiteScript project. More importantly, it's a great solution for the Magic anti-pattern.

In _most_languages, an enumeration - "enum" for short - is a really simple data structure that maps a literal value (e.g. "358725") to a programmatic reference (e.g. enums.Vendors.Printful). Unfortunately in JavaScript, we don't have a formal structure to build enumerations; we have to fake it, but we can fake it pretty easily. The enums module is extremely simple; we return an Object literal with properties as deep as we need to describe the various fixed values (like internal IDs) in our Project:

define([], () => ({
  Vendors: {
    Printful: '358725',
    Printify: '778923',
    PrintAura: '123123'
  }
}))

Now whenever I need the Printful Vendor ID (a pretty common need when you're building an integration to Printful), I load the enums module and reference enums.Vendors.Printful instead of having to remember and document "358725". Oh and by the way, when we do drop that Sandbox refresh, I have exactly one spot in my code to change: the enums module. Everywhere else in the project is using the programmatic reference enums.Vendors.Printful; the only place that needs to change is the literal value "358725".

If I wanted to get super cute, I could even add N/runtime and use it to detect the environment and decide which ID to use, though I generally find this unnecessary. Avoid the environment drift and refresh your Sandboxes regularly!

Save all your magic for solving important problems for your clients/users; use enumerations to replace your magic values.