Thoughts on optimizing
Roughly twenty years ago I was flown to Santa Monica for an in-person interview with Yahoo!. I flew in and out on the same day with a notepad and pencil. I showed the interviewers an image browser I had recently built and walked them through the code in the developer console. They asked, "How could you optimize it?" "What do you mean?" I asked naively. They pointed out some places where things could be sped up a bit. I remember feeling incredulous. How could they possibly want this to go faster?! This is a perfectly fine interview question and a good window into thought processes and understanding your code. But at the time I was in love with this piece of code. I showed them that the gains would be imperceptable. I clicked through the images as fast as my mouse clicking finger could go. The image viewer kept pace. In fact, back in the office they wanted me to slow it down so the ads could load between images. It's a classic premature optimization story.
Postmature (?) optimization
Fast-foward to today. Another company, another product. Users are reporting performance problems when loading datasets of 10,000 or more items. The browser will hang and sometimes crash. There are a lot of moving pieces involved and my coworker wants to refactor to use a library over our custom data handling solution. It solves the problem. The data can be loaded and visualized. But, something doesn't sit right with me. I encourage some detective work and lo and behold, we find the culprit. Loops. It's always loops. (Unless it's DNS.)
It turns out we were unnecessarily looping in a loop.
const nextItems = action.data.reduce(
(items, item) => ({
...items,
[item.id]: item,
}),
state.items,
);
When we wrote this bit of code years ago, it was the pattern to follow when using Redux with React. It's readable and avoids mutating state.items. Avoiding data mutation was all the rage in the early React days. But this has one of those infamous big 0 problems. It even shows up in the when to avoid .reduce() section on MDN. 😅
The fix is simple.
const nextItems = { ...state.items };
for (const item of action.data) {
nextItems[item.id] = item;
}
In fact it's so simple that it triggers feelings of imposter syndrome. Now we can keep feeding the machine more data, our users can find the next weakest link, and I can see my name next to the offending code in the logs.