How ESLint Saved Our Soul

I admit, it’s not on my list of “great times” to hear that the code style you’ve spent weeks defining will require “having to suck the soul out of the codebase”.

But truthfully, it was a breath of fresh air.

Okay, maybe the messaging could have been less dramatic. Maybe less “Fire and brimstone”. But we’ve all been there, right? A new person joins a team and starts changing the way things have been done for what seems like no good reason at all. While they may not be huge changes, they can feel like the end of the world.

That’s the difficulty: many of our judgements come from an emotional response, and it’s hard to quantify those feelings. We know there’s a reason for our discomfort, but can’t always describe why. It’s tough to speak up when we’re not able to objectively state our hesitation, and sometimes we end up stating things a little more dramatically than we intended.

So I knew my co-worker had just taken a big risk by expressing concerns about “the soul” of the project. I had to respect that risk by looking past the specific delivery of the message. Nothing in our collective past indicated malice behind the meaning (I’m fortunate to work with some great engineers), so it was only reasonable to assume good intentions.

With that in mind, I indulged my co-worker. What did they mean by their words? Did they dislike the entire concept of linting, or just a specific implementation of the rules? I didn’t focus on the emotional response, but rather took it as a sign that something wasn’t quite right with the setup we came up with.

Tabs vs. Spaces; Single Quotes vs. Double; Blue bikeshed vs Red.

It turns out, they weren’t crazy about the choice to use tabs instead of spaces and double quotes instead of single. Honestly, it wasn’t my personal preference either. Most of my career had been spent using two spaces for indention, and I often found myself replacing single quotes due to muscle memory when typing. It wasn’t the style I personally wanted, but for legacy code reasons, tabs and double quotes were the choices we made.

I knew that switching everyone to spaces wasn’t the answer. No matter the decision, there would always be someone who preferred it one way over the other. And if we did switch over, we’d have to update hundreds of lines of stable code just to use a different indention, introducing risk of breaking production due to some weird error.

Thankfully, ESLint is perfectly set up for this situation. When you import a common configuration, you can add individual overrides as needed. Here’s an example .eslintrc file:

The majority of rules follow the global pattern, but for individual instances where a team prefers something special, they can have their specific configuration. This ensures the project team is 99% compliant, rather than 0%. And really, that 1% matters as much as the color of a bikeshed. Seriously, tabs vs. spaces is a minor detail compared to code architecture and overall structure.

With this in mind, we created a hierarchy for style compliance:

New common code would strictly follow the company standard

Legacy code would follow the company standard, with exceptions made when updating files isn’t worth the risk.

Individual project teams reserve the right to modify any style they choose, so long as they’re the sole owners of the code and they accept the “risk of non-compliance”.

Opening Up Discussion

Along with individually meeting teams through lunch and learns, we also worked on building a community across the company through an internal ESLint Slack channel. This channel is open to anyone at InVision to comment or question the configs, or just to say that something isn’t working for them (or that it is).

Additionally, we’ve published our configuration as an open-source package on NPM. If you have an opinion on code style, check ours out. Feedback is welcome (although we can’t promise we’ll change it for you). You’re always welcome to roll your own though.

Taking Time

It’s been over a year since we switched from duplicating the same .jshintrc and .jscsrc files in our repos to standardizing on a common ESLint config. I’d love to say it was an overnight success, but it took time. Time to make the initial choice, then time to work those choices in with reality.

It also took time to get feedback. People were quiet at first. But by staying open to reactions after the implementation, we allowed people time to experience how the new configs worked and felt to them. Many times things look great on paper, but until you actually experience them, you don’t really know how it works.

The Soft Side Matters

It’s easy to focus on the hard evidence of a codebase. Is it well maintained? Does it have too many bugs? Is documentation accurate?

But a large majority of the success of a project (and team) comes down to the softer, more human side of the codebase. Is opposition encouraged? Are contrary viewpoints welcomed? Can folks change little things they don’t like, so that they can achieve bigger goals together?

Our goal is to promote a healthy project ecosystem. To do that, we have to realize that sometimes only part of an argument is the actual truth. The rest is just needing to be heard. We focus on the truth, work on the compromise and understand that even though it sometimes requires concession, it’s for a better result in the end.

When that co-worker spoke out against the new lint rules, I had to take a step back and view the situation a little more empathetically. By digging in to what they really meant, we were able to come to a great compromise, which avoided weeks of disagreeing about which style is better. By using a tool that’s open to this flexibility, we were able to adapt to each project’s desires.

In your work you’ll rarely get it perfect the first try. This is true for both the technical and communication aspects of projects. Know this, stay open to feedback, search for dissidence, and with it, make the “soul-saving” choice in the end.