loyalty.dev

Stop trying to please RuboCop

RuboCop can be a tremendously useful tool, but despite being created by some very smart people, it itself is not that smart, and treating it as if it were can often lead us astray.

RuboCop can be a tremendously useful tool, but despite being created by some very smart people, it itself is not that smart, and treating it as if it were can often lead us astray.

Disclaimer: I am part of the RuboCop core team, but any opinions and advice expressed here are my own, and are based in the experience I have had working with and on RuboCop over the past 5 years.

Just a brainless tool

One of the most common questions I still get asked is: "How do I please RuboCop?" And after 5 years, I still can't help but shudder whenever I hear it. Do they not know that, despite the cute, anthropomorphising name, RuboCop is not an actual person, doesn't have a brain, and can't reasonably have any conception about what "being pleased" even means?

The most obvious constraint of RuboCop is that it's scope is limited to style. It doesn't care about semantics or substance. It also can't reason about code. It checks the formatting of our code using patterns and heuristics to see if it fits the instructions. Perhaps the best metaphor here would be autocorrect. Heck, there's even an entire feature baked in which is named after this. But (so far) I never heard anyone talk about "pleasing autocorrect."

Most people are intuitively aware that autocorrect is just there as a support, to fix small mistakes and give us suggestions, so we can focus on the message. But we're the arbiters of whether those suggestions make sense or not, depending on their context. In the cases where they don't, we have several options for how to deal with it, and RuboCop is no different. We can configure cops to use a different style, exclude certain files or directories, use inline disables to allow one-off exceptions, etc.

Granted, sometimes RuboCop will get tripped up because we have modelled our code in some strange way. This will usually take us for a spin, where fixing one issue will result in one or several new ones, ultimately leading us in a large circle. Unfortunately RuboCop is not smart enough to tell us that our design is off somehow—it operates on a level lower than that—but it's worth noting that when we end up in this kind of strange loop, it might be a good time to pull back and check that what we're doing makes sense.

Legacy

This is a bit of a segway, but I think understanding the history of RuboCop and its goals can help understand the sometimes irrational behaviour we just described. It is very likely that one of the reasons why some people are careful to follow RuboCop's every instruction to a T is that the original goal was to have RuboCop enforce The Ruby Community Style Guide, a crowd-sourced effort for standardising the way Ruby is formatted for maximum legibility.

However, this quickly became a bottleneck for RuboCop. Discussions in the style guide could often (and still do) rage on for years without any conclusion in sight. Meanwhile, people just wanted a tool to help them get consistent formatting in their projects. So the direction of RuboCop changed to focus on configurability. You want to have your hashes aligned as a table? Fine by me. You prefer single quotes? Knock yourself out. And in the spirit of open source, if your preferred format isn't supported, by all means, please submit a PR and it will be.

However, despite RuboCop being nearly infinitely configurable, a lot of people still treat the default configuration as a form of scripture. Nearly every week an issue will pop up with someone fervently arguing that their pet style should be made the default, incorrectly thinking that the default configuration holds some authority, or indicates some form of "best practice." (It doesn't. It's either arbitrary or a result of historical decisions.)

For better or for worse?

Ultimately, our job is to write better code. How we define that is one of the key questions of our craft, but at the very least, we should "know it when we see it." Despite this, I see people frequently take a piece of code that they deliberately crafted for legibility and change it for the worse just in order to "please RuboCop." This is a damning mindset. You are (hopefully) a discerning craftsman, and RuboCop is a mindless tool. Between the two of you, you must ultimately decide what's better for your code. Don't be afraid to call out good code when you see it, regardless of what RuboCop might have to say about it.

Put simply: RuboCop doesn't have a brain, so you still need to use your own. (Sorry.)