At The Gnar we are always reading, watching, and listening in order to keep our skills sharp and our perspectives fresh. Here are some of the resources we learned from this month.
Types in Ruby: Discussion with a Lead Sorbet Developer at Stripe
Type systems can be a divisive topic. Some people love them and some people hate them.
This particular podcast was fascinating to me because he discussed the pros and cons of types in Ruby with a high level of detail.
For instance, he spent much time talking about why Sorbet was developed in the first place:
[08:02] I think a huge part of it was people would switch back and forth between writing Typescript in the frontend, or Flow in the frontend, and then Ruby in the backend, and to know what could have been the case, what they were missing out on….[09:15] But I think that the biggest motivating factor for us was just at the time we were getting up to the place where we had hundreds of developers, and even if we were building new code, it was hard to make sense of it all. We really just wanted “jump to definition”, to be able to follow paths of control flow through the codebase, and connect things together. So it was more about understanding the code, I would say.
This really rings true for me personally. I’ve worked with TypeScript and Ruby on the same project and it can be jarring switching context between the two codebases.
As software consultants, we’re also frequently jumping into new codebases. In my experience, types make onboarding faster and less painful, allowing me to become productive more quickly.
And Stripe appears to have shared this opinion! Jake mentioned that the vast majority of the Stripe codebase is typed:
[15:45] Less than 1% is not using Sorbet…There’s kind of various strictness levels to what it means to have Sorbet turned on. So at the very bottom level it’s what we call typed false. And even still, even though it says “typed false”, it’s still doing some kind of sanity checking, which - it’ll make sure that all of the classes and modules and constant references in the codebase resolve, and it will obviously check that your syntax is valid. But then up from that, there’s “typed true”, and that’s the point where Sorbet will start doing actual type inference on method bodies, and tell you if you have any classical type errors, like “expect integer found string” sort of type errors. And then one level up from that is “typed strict”. And that “typed strict” - not only will it do the type inference, but it’ll require that you put explicit type annotations on every method in your file.
I think we even have that typed strict level - so it’s like 99% typed true or higher, but at typed strict I think we’re somewhere close to like 80%, or something like that. It’s the sort of thing where over time people encounter the file that doesn’t have type annotations, and encounter the files that do have type annotations, and they find that it’s a lot easier to edit, and understand, and refactor the code that has the type annotations. And so they’ve self-selected to opt their files into these stricter checking levels.
Type systems are far from universally loved, so his comment about developers “self-selecting” for type-checking (let alone strict type-checking) is interesting. When one of our software consultants is working in an embedded team, for instance, it's common that some of the client’s team members will gladly implement types while others are more reluctant.
And there are certainly valid arguments against types. José Valim's 2022 ElixirConf EU Keynote was, in my opinion, a fantastic discussion of the benefits and challenges that arise from type systems.
In that same vein, Jake also thoroughly discussed the tradeoffs that need to be made when adopting Sorbet:
[19:57]...the kind of dynamism of Ruby is both a huge strength, and that it’s been what’s let communities like the Rails community succeed, but also a big challenge, just because those sorts of – like, when you can only understand what the code is doing at runtime, obviously that stands in the way of static analysis. So that’s definitely a big problem. And I wouldn’t say it’s a fully solved problem in Sorbet, by any means. That’s probably still one of the biggest reasons why you might evaluate whether your company or your codebase should switch to using Sorbet and you decided against it. Your team really gets a ton of value out of the super-dynamic metaprogramming sorts of features of Ruby, and Sorbet would, in many cases, ask you to give that up. It’s interesting, because Stripe actually started – Stripe has never used Rails, but it has used a lot of metaprogramming, in especially its early history… And as people have started to adopt Sorbet at Stripe, it’s kind of been this incremental rejection of the metaprogramming parts of Ruby. Part of this is because people see the value, again, that they get; all these features, all these safety guards that they get when people are using type checking in their files.”
Or to put this a little more bluntly: you’re probably going to run into issues with Sorbet if you make use of Ruby metaprogramming. If you think that doesn’t apply to you, make sure to account for any place where you take advantage of
method_missing as that’s a pretty common implementation of metaprogramming in Ruby code!
Jake also notes that Sorbet has very little support in the community when compared against something like TypeScript:
[42:35] Most libraries that you pull off of npm are already going to work with TypeScript just out of the box. There’s kind of nowhere near that level of support for typing in Ruby Gems that you’ll encounter most commonly.
So the current implementation of types in Ruby via Sorbet is imperfect and may not be well-supported for your use case. As noted in the podcast, the esteemed Justin Searls has recently highlighted some of the pain points with adding types to Mocktail.
Finally, and perhaps most importantly, Jake revealed in this podcast that he doesn’t even like sorbet.
Listen to the full podcast here:
ElixirConf EU (2023): Scaling Teams, Impact & Education with Elixir
Elixir is a niche functional language that has a Ruby-like syntax and offers some advantages over Ruby in the areas of speed, concurrency, and error handling. When combined with the popular Phoenix framework (analogous to Rails for Ruby developers), Elixir would seem to be a great alternative to Ruby for building some types of web applications. In fact, The Gnar is using Elixir to build products for our clients right now!
But the language unfortunately suffers from a dearth of developers and expertise. Jack Rhodes spoke at ElixirConf EU and described this problem with a hilarious graphic:
In the presented graph, the blue line represents the number of Java developers, while the pink line represents the number of Elixir developers.
Despite the fact that the Phoenix framework was voted the most-loved framework amongst developers, the number of developers is ludicrously small when compared against something like Java.
So how did Jack and Multiverse surmount this problem?
First, they focused on finding people who had expertise in programming (or related fields) and interest in learning Elixir; in other words, they looked for generalists.
[8:55] Where Java has a big population and declining popularity, we have a small population and an increasing popularity. And what that means for us and Multiverse, was when we were looking to scale our team to 60 people and more in the future, we looked to hire generalists.
Second, they expanded their pool of potential candidates by enabling and encouraging hybrid work:
[12:05] What we’ve done at Multiverse is embraced hybrid. You can work where you want to within the U.K.; unfortunately not within anywhere else right now, other than the U.S.. But what that means is we can open up to this much bigger hiring pool and increase our chances even more so.
Perhaps most importantly, they focused on finding and providing good learning materials for their developers.
[13:36] There’s been a gap in our community content around opinionated stuff. Elixir is a super flexible language and our documentation around APIs and how to use stuff is phenomenal, but occasionally what our juniors have been telling us is that it’s really hard to know…it’s really hard to find opinionated stuff on how to structure Phoenix contexts well; how to manage changesets without introducing vulnerabilities in your code while sharing those changesets.
In my experience, finding vetted, reputable learning resources for Elixir can be a challenge in and of itself.
One of the resources they highlighted – Pragmatic Studio courses – has been recommended to me by several developers. Likewise, I’ve personally been reading The Phoenix Files blog for several months and found it to be full of helpful tidbits.
See the full video here:
Navigating Legacy Infrastructure: A CISO’s Actionable Strategy for Success
Whether you’re a chief information security officer (CISO) or a junior developer, suggesting overhauls of existing technology can be challenging. “Navigating Legacy Infrastructure: A CISO’s Actionable Strategy for Success" provides a few great tips for how to broach these topics with leadership. One of the crucial things mentioned:
When you bring these insights to the leadership team, be conscientious about how you frame the conversation….Prepare for objections in advance.
When an objection is made on an unfounded assumption, that objection should be analyzed and addressed with current facts-on-the-ground (i.e., from a recent security audit).
However, I’d also add that we should approach these conversations with a collaborative mindset. That is, we should prepare for objections with the understanding that those objections may be completely valid.
Engaging with client leadership teams is a daily part of our work as consultants and it’s imperative that we always listen to our client’s concerns with an open mind.
Another important point made in the article is to present your security concerns in the context of broader business concerns:
Leadership teams are driven by quantifiable business implications. The best way to get support for updating or replacing legacy technology is to make the risk to the business real - and measurable - in a language they understand.
As with any presentation, you should tailor your content and arguments to your audience.
For example, when we discuss the benefits of a specific technology with a client, we wouldn’t talk about fast compilation times, better developer experience, or better end-to-end testing support; we’d focus on the outcomes, such as a more secure and reliable application.
The article writers also mention that we should investigate the effect of security changes on other teams.
Earning buy-in from other departments can help you further your case….Depending on the technology at hand, you may find supporters across your legal team, warehouse team, distribution team, marketing team, or even your finance partners.
In other words: don’t be afraid to reach out to other teams! This is especially true at larger organizations where teams can often become siloed.
When we’re not in frequent communication, it’s easy to overlook overlapping areas of concern. Those other teams may have even already looked into the security issue you’re investigating! By reaching out, you can bring in more stakeholders and consequently bolster the case for migrating to more secure technologies.
Learn more about how The Gnar builds software.