top | item 38688453

I Love Ruby

429 points| mooreds | 2 years ago |eliseshaffer.com

291 comments

order
[+] bakuninsbart|2 years ago|reply
I think the point about expressiveness is exactly what makes ruby so divisive: It is great when you are deep within the ecosystem or do exactly what the ecosystem expects you to want to do, and an absolute pain if you want to do anything non-standard.

The supports_feature-method is probably defined somewhere 5 abstractions deep. If you are lucky that is, it might also be part of some library's weird meta-programming of supports-* that no LSP can point you towards. I've never worked in an ecosystem that celebrates implicitness as much as ruby does, and it is driving me nuts.

The fact that finished code looks great and reads well doesn't balance the scales in my book.

[+] rezonant|2 years ago|reply
> The supports_feature-method is probably defined somewhere 5 abstractions deep.

Yes, but pro tip: you can do object.method(:supports_feature).source_location to inspect where it comes from. It may be a module included into the class, the class itself or one of its super classes, or a concept built on modules like ActiveSupport "concerns". But source_location works in almost all cases.

> might also be part of some library's weird meta-programming of supports-* that no LSP can point you towards

Yes, if this comes from method_missing, you can't check it's source_location. You need to use your knowledge that the method name works and that method_missing is how such things are done, and then you do object.method(:method_missing).source_location and read the logic there.

The lack of safe and reliable IDE introspection and design-time type support are my number one issue with Ruby, and why I tend to use typed languages instead.

However, there are workflows for inspecting a codebase that work, they just don't fit in well to the usual LSP+IDE pattern. You are expected to use irb/rails console to do your inspection of the structure and behavior of your programs.

[+] pqdbr|2 years ago|reply
In my experience this is almost never the case. #supports_feature? would be defined right there where you'd expect - in that Subscription model.

Even tough you can reach for metaprogramming (like define_method or method_missing), that's really not how the entire ecosystem of guides and tutorials will point you.

Anyways, when in doubt, just plug a debugger and call "@subscription.method(:supports_feature?).source_location`, and generally that's all it takes.

[+] notjoemama|2 years ago|reply
> The fact that finished code looks great and reads well doesn't balance the scales in my book.

IMO this is because software engineers both get bored and feel a need to compete. The more abstract they can make code the better (more safe?) they feel. That lets them play chess on their terms and eliminate the competition. But that's just my take, I may be wrong. Fortunately the most commonly used gems wrap this abstraction into usable APIs, and most have good documentation.

While this can be correctly attributed to ruby or the devs in its ecosystem, I've been on teams with staff using other languages and stacks that let their completion/anxiety fly making it hard to read and understand their code. I guess my point is it's a good critique, but it falls beyond the meta programming in ruby.

[+] Doctor_Fegg|2 years ago|reply
> The supports_feature-method is probably defined somewhere 5 abstractions deep

This is the classic mistake of confusing Ruby with Rails. That might be true of Rails. It absolutely isn't true of vanilla Ruby. The article was not "I love Rails".

[+] znpy|2 years ago|reply
Weird that nobody is mentioning how poorly ruby is documented on its main site.

There is no proper tutorial, only links to external resources of varying accuracy and levels of update-ness.

It really doesn’t help with grasping such a customisable runtime.

[+] pdntspa|2 years ago|reply
It's a pretty simple heuristic to track down the source of metaprogrammed functions... just check for method_missing() or define_function() or a handful of other keywords. I believe the regular syntax is just shorthand for these features anyway.

edit- as another comment points out, you can just do `@subscription.method(:supports_feature?).source_location` too

[+] eliseshaffer|2 years ago|reply
Hello everyone. I'm Elise, the author of the post. This is just wild. I mostly write for myself and never imagined I'd make it onto Hacker News.

I think an overlooked part of my point in this post is that the language felt intuitive to me from the beginning. It really matches the way my brain was already thinking about code. Think in messages, focus on small objects and what messages they can receive. There's a lot of comments about not understanding Ruby or finding it hard to maintain, but we're all different. I know people who feel the same way I do, but about Javascript, or Kotlin, or even Objective-C(which I find impossible to follow).

I get that Ruby isn't everyone's cup of tea, but for me it's pure joy. And when I'm working with other Rubyists, it feels like we're flying along effortlessly.

I wasn't really trying to comment on other languages. And everything we choose is based on our own design sensibilities, our constraints, and our experience. I really just wanted to put down in writing, what sparks joy for me about Ruby.

[+] vertis|2 years ago|reply
I've been through lots of languages at this point over 20+ years, everything from C/C++ and (early) Java onwards. Ruby was one of the first languages that felt like it was designed to try and make life enjoyable for a programmer, at the time, circa 2007, that was in short supply.

I've moved on to other languages now, but I treasure the time I spent doing Ruby, and I've carried many valuable things onwards with me.

Things might change for you too, over time, but that won't lessen the positive impact that Ruby has had being so close to the way you naturally think about programming.

[+] brightball|2 years ago|reply
I can speak from both sides of it now.

When I first took on a project that was written in Ruby I was extremely annoyed. Once I learned my way around and really understood it better, I loved it. It's still my go-to for just about everything just because of how productive and readable it is.

The performance optimizer in me fights a constant inner battle about the fastest way to do things vs the most productive way to do them. With more time and experience, productivity wins just about every time.

I'm also a huge fan of Elixir and it's always interesting to watch the language discussions because there are people who are absolute "static typing is the only way" zealots out there. I don't use zealots lightly either. Preference is one thing. "Any other way is wrong" is entirely another. Elixir gives you a different way of achieving the same thing with strong typing, pattern matching, guard clauses and type inference via symbols...but it's still not enough for the static typing crowd, no matter how perfect the balance of concerns.

When you find your language, enjoy it. There's always going to be people who find a reason to dislike your choice because it wasn't their choice.

[+] phatskat|2 years ago|reply
I appreciate the quick and passionate read! Ruby was one of the languages I sought out when I was trying to figure out if I should switch from PHP before getting on a “set” professional path. At that stage, I’d been doing PHP and web programming for about 4-5 years and just getting through college. Now, some 15+ years later, I’ve (recently) shifted mostly to frontend.

Your blog post made me really consider giving Ruby another shot, and I’m curious if you have any good places to start for someone familiar with programming but not Ruby.

Thank you, and I’ll definitely be reading more of your blog :)

[+] atomicnumber3|2 years ago|reply
I love Ruby too. It's a great language, and as a language I like many things about Ruby a lot more than python. In particular, chains of functional operations like:

    arr
       .map{|o| ... }
       .reject{|o| ...}
       .reduce(init_acculm){|init_acculm, o| ...}
are super super clean and expressive. Very similar to what I like about Java streams.

And the library ecosystem is great, I like how it shares spiritual similarities with python where libraries are very "no nonsense" (you don't need extensive configuration and builders and researching a million configuration items etc etc... looking at you, Java) and you typically just import and go. Rails, of course.

I keep picking python over ruby though, for things I'm going to have to actually maintain. And I typically pick Java over python if I smell I'm going to care even an iota about performance. (Often I don't, though). But ruby vs python, I keep coming back to the divergent opinions they've taken on gradual typing. I like that python3 lets you include the types as part of the program, part of the grammar. Ruby relegates them to a separate file. I guess the intent is that it's more for libraries, like how js libs will ship typescript type files? But I don't like that, I want types for myself. Sorbet exists, of course, but I don't like that it's a) a gem and b) still not a first-class part of the grammar but is instead just operating "in-language". I know it works and e.g. Stripe uses it to great effect (I worked there) but I just don't like it, personally, and I find that python3 with its built-in type hinting tends to get typed more readily than ruby where it's a much further reach away.

But I really love ruby. I hope it improves its type-hinting story because I like most other things about it. But I was pretty unenthusiastic about python prior to it getting its type hinting built-in, so apparently this is a big deal for me.

[+] jupp0r|2 years ago|reply
I hate Ruby with a passion (it's also the language I mostly use in my day job currently).

It's not necessarily the language itself, which is a reasonable language, it's the patterns that are common in the ecosystem:

1. Use of inheritance for code sharing. It makes it extremely hard to reason about any piece of code I am looking at. Where does the `param` variable come from? Is it injected by any ancestors of the class I'm looking at? Who knows, I have to use the debugger to find out. I cannot reason about the code without it. Of course you can use Ruby while preferring composition over inheritance, it's just rarely done by the community. Other modern languages like Go and Rust wisely leave out inheritance for code sharing in their object model and arguably have much more readable (albeit verbose) code.

2. Global mutable state is everywhere. Not sure if it's Rails architecture that encouraged using global state as request local state (until they found out that this makes concurrency hard), but Ruby codebases are full of global mutable state. It's everywhere and again makes it hard to reason about dependencies between objects and how they interact with each other. Again, this is nothing that the language forces people to do, it's conventions.

3. Overuse of meta programming. Ruby's metaprogramming is really well done in my opinion. The problem is that lots of people want to use it and do so in places where it doesn't provide enough value to justify the costs. It's an authentication library. It doesn't need it's own DSL.

[+] soulbadguy|2 years ago|reply
It's interesting how different languages resonate so differently with each of us. I have tried a bunch of languages, and got pretty deep into ruby at one point in time when rails was the main web framework i was using. However ruby is probably my least favorite language. Most of the features which actually make ruby unique are exactly the one that turned me away and toward something like F# when i want funtional goodness, C++ when i feel adventurous and scheme/racket when i want dynamic language fix.

> Ruby is probably the most expressive programming language on Earth

I wonder if there is a generally accepted quantifiable definition of programming language expressiveness. Here the author seems to equate it to closeness to natural languages.

In my experience, ruby code is easy to write, but hard to follow without being familiar with the code base and it's idom. A lot of the information required to understand it is passed through implicit context.

[+] brink|2 years ago|reply
After 10 years in Ruby, I moved onto Rust four years ago, and don't plan on really looking back. But with that said, I'm glad you love Ruby! There are certainly things to love.

Personally, I just can't do without a good type system anymore. I think Rust has spoiled me. I do miss Ruby's powerful reflection features though.

[+] oglop|2 years ago|reply
Maintaining Ruby is a nightmare. Trying to escape that hell now.

I do like Ruby for my own projects. But I hate working on Ruby with others. It becomes more messy faster and then all that supposed “getting out of your way” goes out the window and you have to know about 9 objects, one of which is an iceberg which will need to quack at some point.

Overall, it obliterates a programmers ability at local reasoning in code, which is where I really want speed.

[+] Cthulhu_|2 years ago|reply
Is that due to Ruby the language or the developers and/or their culture?

I mean I personally believe maintainability is a combination of the language itself and the culture around it; Go is a great example of a language and culture aimed for readability and maintainability, eschewing cleverness. That is, the language is limited in how much cleverness you can write, and the culture is opposed to people trying.

[+] jwestbury|2 years ago|reply
> Maintaining Ruby is a nightmare. Trying to escape that hell now.

The problem with maintaining Ruby is that Ruby is heavily influenced by Perl.

[+] impulser_|2 years ago|reply
Maybe this is just my experience, but the thing that sucks a lot about programming to me it that the most enjoyable programming languages are often the ones with the smallest job market.

My job as a programmer would be infinitely better if I could spend it programming Elixir all day, but there is basically no Elixir jobs compared to Typescript, Python, and Java.

But instead I hate my job working in Typescript all day solving problems that I wouldn't have to if I could just use Elixir.

Ruby use to an exception to this, but almost no one is building on Rails anymore compared to how many people build on React, and NextJS.

I'm talking about full stack application market, this is probably different for Rust users for systems, and Python for Data/AI.

[+] anonyfox|2 years ago|reply
By default this is because the skill bell curve in programmers including their managers. Most developers simply don't really care too much about their profession. They use what they've been taught at university or whats already used at $CORP job, fulfil some requirements given to them, and collect their paycheck. They usuallt can't be bothered to pick up more interesting tools on the side.

Ontop of that there is fluctuation and risk-avoidance, so using anything that is not absolutely mainstream is seen risky, because replacements might be a bit harder to get. Combine that with the usual mediocre preexisting employee base, and its obvious why by default the dumbest/broadest thing is everywhere in use, even though most people involved in the decisions aren't idiots.

There are roughly 2 types of places where you can encounter Elixir or other exotic tech:

1. The decision maker / CTO / tech lead actually has the autonomy and the personal interest in this tech so he is the driving force to level up and stand out. Only works in tandem with enough dev motivation in the team or it will backfire.

2. Startups/new tech insourcing departments, where a small circle of actually competent/motivated people got to choose the foundation and are by some miracle not blindsided already with "pick the cheapest and least risky" option but understand that tech can be the critical advantage needed.

Joker slot: be a solopreneur and use whatever you feel comfortable with. Thats the general escape hatch that is becoming increasingly popular it seems.

[+] jes5199|2 years ago|reply
I used Ruby professionally in the early 2010s and that sucked all the joy out of it. Gigantic Rails monoliths in that era were just unmaintainable brambles. I probably would rather write Ruby again for side-projects but the ecosystem just isn’t there
[+] briantakita|2 years ago|reply
> But instead I hate my job working in Typescript all day solving problems that I wouldn't have to if I could just use Elixir.

Before I focused on iso js, I worked with EventMachine & even a little bit of Erlang. Would love to hear more about an alternate timeline if I stuck with Ruby & went down the Elixir route.

---

I used to work with Ruby & switched to js before TS to build isomorphic libraries & apps. TS has been beneficial imo though figuring out type inference for library code is a steep & time consuming learning curve & takes experience to figure out the edge cases. In the end though, having type inference work in library code is worthwhile for quickly developing apps. Re: expressiveness, the js/ts ecosystem suffers from mostly using camelCase, which has variable casing depending on the position of the name segment...which makes project wide searches for composed abstractions less reliable. I distilled the "tag vector" name convention to address this issue. Granted, Ruby having `?` & `!` available is as a terse & explicit expression of intent is nice.

> almost no one is building on Rails anymore compared to how many people build on React, and NextJS.

I got burnt out on Rails after the 3rd consecutive upgrade project for large codebases. I think the dominance of React has been detrimental to the js ecosystem as its bloated with the api being complex & unintuitive. It also took the JS framework guys a decade to figure out the MPAs are the way to go. I hoped people would have figured that out sooner. I got tired of the complexity & size of the reactive state management & ui libraries & recently wrote my own (rmemo & relementjs). I working on a vite alternative called rebuildjs with an Elysia/bun based app library called relysjs.

I loved how many Ruby community (other than Rails) had a commitment to create simple libraries. It seems like js framework communities have this drive to lock developers into their complex manifestations.

Sorry about the long comment. I have to get back to a major version update to ctx-core (general purpose contexts & utility functions) addressing type inference...which will make developing apps with these libraries more reliable & effective.

https://www.briantakita.me/posts/tag-vector-1-tag-vector-con...

https://github.com/ctx-core/rmemo

https://github.com/relementjs/relementjs

https://github.com/rebuildjs/rebuildjs

https://github.com/relysjs/relysjs

https://github.com/ctx-core/ctx-core

[+] akprasad|2 years ago|reply
I'm glad that the author enjoys Ruby! As someone with limited Ruby exposure, these quotes stood out to me:

> The language is meant be joyful to use. [...] Everything else that Ruby is stems from this value.

This is important and underrated. I think many programmers have a bias that working on a difficult problem entails using a "real" programming language with sharp edges. I had some version of this bias for a long time until I started exploring the most recent generation of systems languages.

> Well written ruby code can often read like natural language.

I see where the author is coming from, but I find a healthy dollop of symbols to be very helpful for reading and understanding code at a glance.

> Feeling recognition in the language you’re programming is so powerful.

This is the feeling I had the first time I used Python, and later Rust. It's a wonderful feeling!

> [As] Kent Beck said at RailsConf in 2020, “Software design is an exercise in human relationships.”

Especially true given all of the components involved in supporting a language: compiler, docs, standard library, third-party libraries, package managers, frameworks, formatters, profilers, ...

[+] rapsey|2 years ago|reply
> This is important and underrated. I think many programmers have a bias that working on a difficult problem entails using a "real" programming language with sharp edges. I had some version of this bias for a long time until I started exploring the most recent generation of systems languages.

All languages have some mantra that everyone repeats and that is the Ruby mantra. Personally I find Rust to be joyful because the type system, project and package management is so good and the end result is efficient without any extra effort. What I find joyful is getting things done well.

[+] cryptos|2 years ago|reply
I agree with the author that "developer experience" is underrated in many programming languages or frameworks. But at least for me Ruby is by far not the number one in this area. While the syntax looks nice at a first sight, lack of type information and meta-programming can make working with this language tough. And there are other factors to pick a programming language, runtime performance for example. I guess that this and the absence of static typing are the reasons why Ruby fell out of fashion.

For me Kotlin is the sweet spot in programming language. You get a concise, readable language with world class tool support, static typing and the excellent performance of JVM + everything available in the Java ecosystem.

[+] jstummbillig|2 years ago|reply
The hours I have sunk into making vscode a rails ide are substantial.
[+] cutler|2 years ago|reply
The only problem with Kotlin is the idiomatic use of the abomination that is Gradle.
[+] vinc|2 years ago|reply
I started with PHP many years ago for my side projects while at the university, then I switched to Python, but when I graduated there were only PHP jobs available so I took one because I had to. I was not happy with PHP, it was a pain to use it. I never want to hear again about WordPress or Drupal.

I discovered the Ruby community at its peak around that time and fell in love with it! I started a new project at work with Rails and all my next jobs were Ruby jobs.

I experimented with Node when it came out but I think I'm burn out with everything related to JavaScript at this point. And the Ruby community, while still great, seems to be dying out locally. Meanwhile I've been doing some Rust side projects for almost a decade, and it looks like this will be my next language. Time will tell.

I still love Ruby though, I wish it was more popular, it's such a nice language.

[+] verelo|2 years ago|reply
Very similar experience here. I started in .net but ended up Working in php, although only recently did i switch to ruby for a personal project. I’m loving ruby, and paired with nextjs / react for a front end this has to be the best working environment I’ve ever had the opportunity to use. I wish I’d been doing this for work prior but I’m glad to be finally doing it at the ripe old age of 37.
[+] mberning|2 years ago|reply
It’s a shame that Ruby doesn’t have the cachet it once had. People are missing out. It’s still a fantastic language and Rails is still the goat web framework. Perhaps we’ll see a renaissance in the future. I still prefer to do all my tinkering and playing in Ruby first.
[+] woodruffw|2 years ago|reply
The blog post (and Ruby's) emphasis on programmer happiness really resonates with me: other than Rust (which induces programmer happiness for fairly different reasons), I've seldom run into a programming language and ecosystem that tries so hard to make programming mirthful.

(Does that make Ruby a good programming language? That's unclear to me; what's clear is that I have fun writing it.)

[+] hschne|2 years ago|reply
Interesting that the discussion here focuses so much on the actual language.

I think the language is fine, but the thing that really makes me stick with Ruby is the ecosystem and the culture it fosters. The article also makes that point.

I have yet to see a programming community (around a language) that is as encouraging and nice as the one around Ruby.

[+] marcrosoft|2 years ago|reply
Take ruby vs go. Ruby can write expressions that resemble a sentence so you can skip commenting and it looks nice. Go is verbose and less English like. Which is easier to understand what the code actually does? Go may take a little extra time to digest but it is infinitely more clear what is going on. If you don’t need to debug the ruby code or optimize it ruby wins because it is easier to digest and reads like English. It is a trade off like many things in software.
[+] PH95VuimJjqBqy|2 years ago|reply
This is actually one of the reasons I dislike cucumber so much. They try so hard to make it read like English for non-tech people but to really understand it you need to understand the underlying regex being used.
[+] djur|2 years ago|reply
I spent several years working on production Go code and I never found it particularly clear or intuitive to read or debug compared to Ruby. This seems like a "your mileage may vary" situation.
[+] nickysielicki|2 years ago|reply
I had to write some ruby at work recently and wasted a few hours on a bug caused by the following footgun:

    irb(main):028:0> value = false or true
    => true
    irb(main):029:0> value
    => false
That really makes me want to write it off entirely. It’s hard to think of a situation where this is the right behavior.
[+] matthewowen|2 years ago|reply
In python empty string is false. In ruby 0 is true. And yes, ruby has both or and || but they mean different things.

I’m not saying that it isnt valid to criticize these things: first time use of a language matters, people work in multiple languages, it is good to be intuitive.

But in practice, these things aren’t problems for people who work regularly in these languages, so I personally find them to be quite low salience.

I recognize that this is sort of similar to the claims the hypothetical user of php makes in “php is a fractal of bad design”, but personally I find think the issues are of a different nature.

[+] mattgreenrocks|2 years ago|reply
Ruby’s a great language, but the cult of personality is really strong there, especially in Rails. And that ultimately led me away from the ecosystem.

I’m not looking for heroes to worship, just good tech.

[+] andrei_says_|2 years ago|reply
What are some symptoms of a cult of personality? I use Ruby and Rails and I know that DHH and Aaron Patterson are somewhat famous but don’t know much about them and certainly don’t make any decisions based on their existence or fame.
[+] shaftway|2 years ago|reply
I don't know Ruby at all, and maybe some familiarity with the language would help, but the biggest example code makes absolutely zero sense to me:

    RSpec.describe Ticket do
      context 'when the ticket is closed' do
        it 'emails the requestor with a confirmation' do
          ...
        end
      end
    end
I have no idea what's going on here.

I get that there are some blocks of code, though it was the indentation that told me that; "do" and "end" feel super verbose and bleed into the important parts of the code for me.

Why is Ticket capitalized? Is this a variable? An object that we're about to work on that's coming into scope?

`context `when the ticket is closed'` feels like it's setting me up. Is this an if block? Or is it some fancy way to set a listener on a property? Is this setting up a callback that'll persist across runs of the program? Or is this just a method named with spaces that could do anything?

`it 'emails the requestor with a confirmation'` has got to just be a method name. But what is "it"? What was "context" in the previous one? And why does "emails the requestor with a confirmation" need to be a block? What happens in there? Is this just setting up some kind of call stack like thing that provides context all the way down?

None of this is intuitive. And the impression that I get is that the author is calling methods with spaces in their names and unclear block semantics "expressiveness".

[+] chihuahua|2 years ago|reply
It is mind-boggling to me to see all the low-value features that Ruby has, but no enums. So every time an enum is needed, there's some ugly code that tries to emulate an enum.

The guiding theme for Ruby appears to be "let's give people a huge number of ways to write unreadable code" and it reminds me of JWZ's classic rant about PHP, "a fractal of bad design."

[+] jes5199|2 years ago|reply
I think the ruby answer is “just use symbols”
[+] pvg|2 years ago|reply
That wasn't written by jwz.