justin․searls․co

Why I just uninstalled my own VS Code extension

After a little over a year of prodding by Vini Stock to ship a Standard Ruby add-on for Ruby LSP, and thanks to a lot of help from Shopify's Ruby DX team, I've finally done it! In fact, if your Gemfile's version of standard is at least 1.39.1, you already have the new Ruby LSP add-on. It's built-in!

Ruby LSP supports any editor with language server support, but configuration varies from editor to editor. Since VS Code is relatively dominant, I added some docs on how to set it up, but most Ruby LSP users will just need these settings to select Standard as their linter and formatter:

"[ruby]": {
  "editor.defaultFormatter": "Shopify.ruby-lsp"
},
"rubyLsp.formatter": "standard",
"rubyLsp.linters": [
  "standard"
]

I've been using this configuration for a bit over a week and I've decided: it's time to uninstall my own bespoke extension that we launched early last year .

I've also updated Standard's README to explain why the new Ruby LSP add-on is superior to our own built-in language server. In short, the Ruby LSP add-on supports pull diagnostics and code actions, and the built-in server does not.

Standard Ruby's built-in language server and existing VS Code extension will continue to work and be supported for the forseeable future, but it doesn't make much sense to invest heavily into new features, when the Ruby LSP add-on will get them "for free".

Why make the switch?

Three reasons:

  1. Capability. Ruby LSP centralizes the pain of figuring out how to build a full-featured, performant language server. The issue isn't that implementing a basic STDIO server is All That Hard, it's that rolling your own utilities like logging, debugging, and test harnesses are a huge pain in the ass. By plugging into Ruby LSP as an add-on, library authors can integrate with simpler high-level APIs, exploit whatever LSP capabilities it implements and whatever utilities it exposes, and spare themselves from re-inventing Actually Hard things like project-scoped code indexing (instead, leveraging Ruby LSP's robust, well-tested index)
  2. Duplication. RuboCop maintainer Koichi Ito gave the closest thing to a barn-burner presentation about language servers at RubyKaigi that I could imagine, where he discussed the paradoxical wastefulness of every library author hand-rolling the same basic implementation while simultaneously needing their own tightly-integrated language server to push their tools' capabilities forward. In the case of Standard Ruby, we're squeezed on both sides: at one end, a Ruby LSP add-on would be a more convenient, batteries-included solution than publishing our own extension; at the other, nuking our own custom LSP code and delegating to RuboCop's built-in language server would unlock capabilities we couldn't hope to provide ourselves
  3. Maintainability. You think I enjoy maintaining any of this shit?

Embracing defeat

So yeah, in the medium-term future, I see Ruby LSP and RuboCop as being better-positioned to offer a language server than Standard itself. Thanks to Will Leinweber's implementation, we may have been there first, but I have nothing to gain by my spending free time to ensure our server is somehow better than everyone else's. In the long-term, even more consolidation seems likely—which probably means Ruby LSP will become dominant. But ultimately, they're called language servers for a reason, and if Ruby shipped with a built-in language server (and an API that any code could easily plug into), it could prove a competitive advantage over other languages while simultaneously enabling a new class of tools that could each pitch in to enhance the developer experience in distinct, incremental ways.

On a human level, I think it's important not to associate the prospect of retiring one's own work with feelings of failure. Code is a liability, not an asset. Whenever I can get by with less of it, I feel relief after discarding it. If relief isn't your default reaction to a competing approach winning out on the merits (and it's understandable if it isn't; pride of authorship is a thing), I encourage you to figure out how to adopt this mindset. There are far too many problems out there worth solving to waste a single minute defending the wrong solution.

Anyway, go try out Standard with Ruby LSP and tell me how it goes! I'll be bummed if I didn't manage to break at least something.


Got a taste for hot, fresh takes?

Then you're in luck, because you can subscribe to this site via RSS or Mastodon! And if that ain't enough, then sign up for my newsletter and I'll send you a usually-pretty-good essay once a month. I also have a solo podcast, because of course I do.