Should I use const?

Alex Bostock
Nerd For Tech
Published in
4 min readMay 26, 2021

--

When writing JavaScript, I often use const.

In terms of technical differences between const and let, there is very little difference. And some people argue that const shouldn’t be used often. I recommend reading these pieces:

But I like to use const a lot, and I’ve been thinking about why.

Code snippet: part of a breadth-first search algorithm written in JavaScript, with a queue defined using const

The team style guide

At work, it was agreed that const should only be used for “actual constants”. If a value is mutated, it should be defined with let instead.

let arr = [];    // arr is mutated, so we use let
arr.push(3);

Following this idea, anywhere const is used should be an actual constant. Rather than blindly using const wherever possible, using const is a way for a developer to communicate their intention. I like that principle.

Why I like const

Why do I use const so often? There are two answers which stand out to me.

Firstly, I tend to write code in a functional style. I prefer to use map and filter rather than push. While thinking in a functional style, I use constant variables, and that signals my intent.

In functional code where all values are immutable (or at least treated as immutable), I don’t think that this is particularly controversial.

But thinking about my other reasons for using const, I want to examine the style guide more closely.

Thoughts about mutation

In my work, I write a lot of what we call workflows. For example, for a process of applying for an extension to a deadline, the workflow would manage passing an application between various approvers. This is modelled essentially as a state machine.

Each particular instance of a workflow is represented by an object, by convention referred to as M. I’ve never heard anybody question the use of const in code like this:

const M = workflow.instanceForRef(ref);

I’m only interested in one particular workflow instance, so I have no intention of reassigning M, so const makes sense technically. But what about style?

Each workflow instance has a state property, which represents the state of the workflow as a string, and cannot be modified directly. Like basic state machines, state is changed by transitioning. For example:

const M = workflow.instanceForRef(ref);
console.log(M.state); // "wait_submit"
M.transition("submit");
console.log(M.state); // "wait_approval_supervisor

Based on a strict reading of the style guide, M is mutated, so I shouldn’t use const. But, to me at least, const feels right for communicating what I’m thinking, and I’ve not heard anybody questioning it before.

Each workflow has a unique ID, and in this code I am only interested in one specific workflow instance. Although its state may change, M is always referring to the very same workflow instance throughout my function. const is a tool I use to communicate that.

So I seem to have an uncontroversial example where it is okay to not follow the letter of the style guide. Is there some way we can clearly define when the rule can be ignored?

Another example which comes to mind is usage of data structures such as JavaScript’s Map and Set. In my opinion, it makes sense to use const here:

const uniqueNames = new Set();
for(const person of people) {
uniqueNames.add(person.name);
}

uniqueNames is being mutated, but it makes sense to me that the set is a constant concept as a whole, rather than a changing value.

Interestingly, that makes more sense to me than something like this:

const results = [];
results.push(something());
if(condition) {
results.push(somethingElse());
}
results.push(yetAnotherThing());
if(skipFirstResult) {
results.shift();
}
return results;

I would (as the style guide dictates) use let result = []; instead.

I wonder whether an important distinction is whether the variable looks like it represents a concrete concept (which seems like a tricky characteristic to define). M refers to a particular workflow instance (with a unique, immutable ID). uniqueNames is a set of all names which have been seen so far. result is just the list of results I’m collecting together.

In the first two examples, the const variable is an instance of some class implemented far away from my code, with a clearly defined interface and a hidden implementation. When I think about M, I don’t think about the exact steps of moving state; I think about the transition method in the docs. When I think about the array results, I think about sticking more elements on the end.

What if I had some kind of queue structure, implemented using a bare array?

const queue = [];
while(queue.length) {
const node = queue.shift();
for(const adjacent of node.children) {
queue.push(adjacent);
}
}

Here, push and shift are the exact same methods as in the results example, but they seems a lot more meaningful. It wouldn’t make sense to swap queue for a different array: that queue is the main part of the algorithm.

In the queue example, I think const makes more sense, but that doesn’t follow the letter of the style guide.

I wonder:

  • Should the style guide be changed?
  • If it was changed, how should it be changed?
  • Can rules in a style guide ever consider every way in which developers want to express ideas?
  • How much value is there in spending time thinking about this? How much value have we lost or gained compared to the previous version of the style guide, when we all used let all the time?

I don’t have answers. But I’m inclined to agree with Dan Abramov: just pick a style (as a team), and work with it.

--

--