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.