How ESLint changed my life

Benjamin Chadwick
Criteo Tech Blog
Published in
6 min readApr 4, 2023
Photo by Elisa Ventur on Unsplash

Over the past few months, much has been written about what automated tools can do for software engineers. I’m not jumping on that bandwagon today: I want to talk about something that’s been around a good while longer than ChatGPT. But it’s one that revolutionised my developer experience, and continues to improve it month after month. I want to talk about ESLint.

Before going further, let’s quickly define linting in general, and ESLint in particular. A linter is a static code analysis tool that parses code and checks it against a list of rules intended to make it more readable, more performant and less bug-prone. When it comes to JavaScript, ESLint is the industry standard. Its high degree of configurability, including the ability to write custom rules, has propelled it forward, and today you can find hundreds of open source plugins providing their own useful rules. For more on how ESLint became the go-to linter for both JavaScript and TypeScript, see Josh Goldberg’s brief history.

When I think back to my early days as a software engineer, I remember code reviews littered with comments about code style, use of const vs let, and endless discussions about how best to write a for loop. Now that I work with ESLint, I never have to worry about these anymore.

Even better, the linter catches issues which might otherwise fall through the cracks. Once, we discovered we had merged a focused Cypress test, meaning that almost none of our tests were running in our CI pipelines. It wasn’t until a production issue arose — one which should have been caught by an existing test — that we realised what had happened.

We have a rule for that now.

Screenshot from WebStorm IDE showing a test labelled “it.only(…)”. The “only” is underlined in red, and hovering over it shows the message “ESLint: it.only not permitted (no-only-tests/no-only-tests)”
The ESLint plugin no-only-tests helps us avoid accidentally disabling most of our Cypress tests

With the right rules in place, ESLint can act like an extra member of your team. This teammate is available 24/7 to provide fastidious code reviews. Just like its human counterparts, it won’t have all the context, and it will sometimes make unnecessary suggestions. But it will always be there to spot things humans might miss.

Get the most out of ESLint

Having, I hope, demonstrated the benefits of ESLint, I’d like to share some tips for getting the most out of it.

Be opinionated

Some rules are universally followed. We all agree not to use var in 2023. Some rules are easy to select because they lead to better performance or avoid bugs. But some decisions are purely arbitrary. We could spend hours discussing whether to disallow or require trailing commas, but would that be a good use of our time? It’s better in these situations to just make a decision and enforce it. That’s a big part of the appeal of Prettier. But it also applies to things code formatters can’t catch, like naming conventions and how to sort imports.

Photograph of President Obama giving a speech, wearing a black suit.
Strict linting rules not only make code more consistent. They also allow developers to spend less time on unnecessary decisions. Just like Barack Obama once said he wore the same suits every day — to keep his decision-making faculties fresh for important choices — opinionated ESLint rules allow us to focus on what matters. (White House photo, via Wikimedia Commons)

Stop using warn

The ESLint config allows rules to be switched on (error) or off. It also allows a kind of in-between state called warn. This prints some yellow text to the screen when you run the linter. But it doesn’t block any pipelines and, in my experience, ends up being completely ignored. If a rule is important, it should be blocking. If it isn’t, it shouldn’t be activated at all. warn occupies a strange middle ground that doesn’t help anyone.

New rules can be tricky when working with legacy code. Completely fixing all the errors in the existing files can be time-consuming, and can lead to complicated merge conflicts when other people are working on the same files at the same time. So some teams choose instead to just set the new rule to warn so that their pipelines still pass. The problem here is that developers will continue to break the rule, because nobody ever pays attention to the warnings. The real solution is to cordon off the legacy code, using targeted eslint-disable comments to exclude specific sections from specific rules.

Some rules might be left on the warn setting because while they encourage a best practice, there are legitimate cases where you might want to break that rule. Again here, the real solution is a targeted use of eslint-disable. This ensures that every time the rule is broken, it is a deliberate and reasoned choice.

Screenshot from terminal showing “356 problems (0 errors, 356 warnings)”
Warning: risk of alarm fatigue.

Be careful with eslint-disable

With all that said, two of the most important and helpful ESLint rules are from the plugin eslint-comments: no-unlimited-disable and require-description. Targeted comments to disable specific rules in exceptional circumstances are invaluable — especially if you have as many rules as we do in my team! But it can be tempting to use them to shut ESLint up, preventing it from doing its helpful work.

Disable comments should specify exactly which rule or rules are being disabled, and should always apply only to the lines where it’s strictly necessary to apply them. no-unlimited-disable prevents you from writing “eslint-disable” without specifying any rule, which would end up switching off ESLint altogether for the code in question. require-description insists that you add a comment explaining why you are switching off a particular rule. If it can’t be justified with a short explanation, the rule shouldn’t be disabled at all.

Develop an ESLint mindset

Keep asking yourself the question, “Could ESLint help me here?” A few examples:

  • You’re reviewing a teammate’s code and you spot something weird. Could ESLint have caught this before you? Maybe a rule already exists — or maybe you could write a new one.
  • Someone reviewing your code just spotted something you didn’t think of. Could ESLint have prevented this?
  • You just spent hours fixing a thorny bug only to realise it was all thanks to one missing declaration. Maybe it’s worth investing the time to find or write an ESLint rule so it doesn’t happen again.

Share your preferred rules!

It can be very helpful to keep code consistent across an organisation, as it makes it easier for engineers to move between projects. To that end, many companies use a shared ESLint config or plugin. Some, like Airbnb or Github, have open-sourced theirs. At Criteo, we have done the same thing, bringing together useful rules from a number of other plugins and adding a few of our own. While some of the rules are quite specific to our technologies and use cases, we know that many of the challenges we face are also experienced by other engineers, so we decided to make them publicly available.

I encourage you to take a look at our Github repository. But just to whet your appetite, here are a couple of the custom rules we’ve developed in-house:

  • no-todo-without-ticket enforces that every TODO or FIXME comment must include a reference to a JIRA ticket. We’ve all seen 5-year-old TODOs that never got handled; by ensuring that at least that work is in the backlog, we help to fight that phenomenon.
  • filename and filename-match-export ensure that files are named consistently. It’s much easier to find your way around a codebase with sensibly-named files. We have long had rules about this, but these were enforced only through human code reviews, which wasted everyone’s time and meant violations sometimes fell through the cracks.

Takeaways

If you take one thing away from this article, let it be this: ESLint is about a lot more than just spaces vs tabs. It is genuinely transformational for developer productivity. By developing an ESLint mindset — constantly asking the question “could this be an ESLint rule?” — you can make it even more so.

--

--

Benjamin Chadwick
Criteo Tech Blog

Immigrant. Software engineer. In my spare time I write about Paris at fabricofparis.com.