My daughter held a book and asked, “Dad, can you remind me to bring this book to school tomorrow morning?” I replied, “Put it in your bag, I’m not your alarm.” She didn’t and said, “Oh, well, I’ll remember.” The following day, she forgot the book.
This reminds me of a deep discussion I had with Ben yesterday. We were looking at a part of our codebase, which I’ll simplify here:
// Version 1
if (env === "prod") {
return {
API_URL: "prod-url",
STRIPE_KEY: "prod-key",
};
} else {
return {
API_URL: "dev-url",
STRIPE_KEY: "dev-key",
};
}
I suggested a different approach:
// Version 2
return {
API_URL: env === 'prod' ? 'prod-url' : 'non-prod-url',
STRIPE_KEY: env === 'prod' ? 'prod-key' : 'non-prod-key',
}
In Version 1, you might notice the duplication of the `API_URL` line. Reflecting on how I suggested for Version 2, I realise I didn’t use the word duplication. I think this is probably because I know that Ben is a deep thinker. He really digs into the ‘why ‘of things. Simply arguing about duplication might not have been persuasive enough for him.
Instead, I highlighted a potential problem we might face in the future: the risk of forgetting to update the `prod` part of the code when changes are made to the `non-prod` part. From my previous essay, Remove duplication to deliberately forget:
This heuristic, the act of forgetting and remembering, also implies the aspect of time. Time is the primary difference between programming and software engineering. We need to adapt to changing needs over time, and this context of what probabilities might come in the future, helps us make a better judgement.
Imagine a scenario where the prod section is overlooked during an update, the production environment might break:
if (env === "prod") {
return {
API_URL: "prod-url",
KEY: "prod-key",
// <--- not updated
};
} else {
return {
API_URL: "non-prod-url",
KEY: "non-prod-key",
NEW_BUCKET_NAME: "non-prod-bucket",
};
}
In this case, Version 1 requires you to remember well. On the other hand, I describe Version 2 as “forgettable code” (I don’t like this name).
I’ve found that discussing this concept with others leads to more agreement, given that forgetting is a human limitation we share. Debates about duplication often end up like discussions about personal writing styles - “I prefer the code to be centralised” vs “I prefer the code to be shorter”. Such discussions rarely lead to consensus.
Of course, we can see the whole code visually, so you might think, “I’ll remember, I can see them!” But our current codebase has examples where the complete prod config doesn’t fit on one screen.
You might further say, “I’ll still remember, even if it doesn’t fit my screen.” However, consolidating new information into our Long-Term Memory (one of our nine cognitive functions) is challenging. We tend to forget over time. If there’s an option that requires you to spend less cognitive effort, why not do it?
The challenge grows when working in teams. You move from dealing with one head to multiple heads, i.e. multiple Long-Term Memories. With Version 1, you have to ensure that everyone remembers to keep the values in sync. You might note this in a Pull Request or add comments to the code as reminders. You know how the story ends, your teammate will forget.
Would using static type help? Like if you have a configuration as a type that can remind you whenever you missed a new key?
Love the story! You could also explain your preferred style based on coupling. Removing duplication can reduce coupling.