156 comments

[ 3.8 ms ] story [ 249 ms ] thread
ruby is a still a pleasurable language to use. it's simpler than python. rails for crud stuff is gold standard alongside django. at least in the ruby world, there isn't much momentum compared to most languages of adding static typing though things like sorbet exist. in the js world the typescript folks came in, the dynamism of js is disappearing
> the dynamism of js is disappearing

As an outsider, really curious to hear more about this. Is it from an ecosystem point of view, where the "dynamism is disappearing" or more from a day to day, the fact that writing TS is significantly different than writing JS? Or even something else?

There are a few patterns that TS simply cannot or is too painful to handle. I still have no idea how to define a class the old way with prototypes in Typescript, which I really only discovered when I ran into some edge cases around how static members and methods in the new class syntax were typed.

You also lose the "type out code really quickly without thinking too hard about it" and the thrill of wondering if it'll work when you load the page.

"Thrill" is an interesting way to put it.
It didn't always, but it sure felt good when it did on the first try!

Needless to say, my scripting nowadays is almost exclusively Typescript.

with dynamic language and yeah a multi-paradigm language like js, means you can come up with patterns a compiler can never expect. because javascript is so flexible, your code ends up like a mini dsl yet still remains readable javascript. with typescript, you won't have much flexibility. you lose a lot of productivity fighting the tool i.e typescript compiler
The dynamism of creating functions that happily take an object, or an array or a string (never detailed thouroughly in the documentation, of course) and then does different things based on which one you got, was always teleogically a dead end.
Not sure how you conclude it's simpler than python. Different precedence of !/not has burned me in the past. Symbol/String keys have burned me. Module/Class (Python has this to some extent, but you don't declare modules so it doesn't come up), block/proc, fail/raise, extend/include, case/when can be used for bool expressions or instanceof checks

I enjoy ruby, & it's nice once you get that every property access is a method call ("it's all message passing") which has nice dynamism (see Sequel)

Maybe you can argue Ruby does a better job not leaking its abstractions (no __slots__ etc)

Ruby is not "simpler than Python".
A counterpoint is nothing without argument. Care to elaborate?
Ruby occupies a similar space to Golang in my mind, where it is "just" a solid business oriented language that gets out of your way. It will never wow you like Rust or Haskell and that is fine, because that is not what it is aiming for. Rails is one of best DSLs for writing simple SAAS apps, too.

That said, different usecases require different languages. I would never use Ruby for a compiler project.

Go has Google support behind it though. Its journey is far from over (that is, until Google abandons it for another language), whereas Ruby's/Rail's growth phase is more than a decade behind us, and it's hard to know what its future holds. I hope it's a good one since I've been doing Rails my whole career.
FWIW, I had a call with a recruiter a couple days ago who claimed that the most expensive candidates to find at the moment are Rails people.

And I'm not a Rails person, so it wasn't flattery.

I've noticed that as well, that senior Ruby/Rails people will become very valuable in the coming years, which is good to hear. However, 10+ years into the future is the real scary part. Will jobs dry up so much so (especially due to the accelerating pace of tech turnover) that Ruby/Rails will essentially become the FORTRAN of the times? Who knows.
Do companies care about about tech turnover?

I have friends everywhere from FAANGMULA to Deloitte to 100 person tech startups (and I am at one myself)to banks. We have a group chat of classmates.

No attempts to stem the wave of resignations anywhere as far as we can tell.

Unlikely. To this day Rails is still being chosen for new projects. I see it for example in HackerNews job postings. You can see the company's tech and year of founding so you know it is new startups. Sure, its not close to how popular it used to be, but definitely not dying. And then what about all the existing code? There is a lot. I think Rails has its place and is still good at what it does, a segment of the population will continue loving working with it.
Not so long ago, before the rise of Node.js and when it seemed like Rails was The Way of the Future (tm) and everyone was really down on PHP, I used to joke that there was a silver lining to PHP becoming the next COBOL: there weren't many COBOL jobs around, but there also weren't many COBOL programmers around, and if you needed a COBOL programmer the chances were that you really needed a COBOL programmer.

As things have played out, PHP has done pretty well at modernizing (I know some would debate that, but that's a different thread), and Rails has faded a bit into the background -- although now I joke that because Rails is well out of its fad phase, it can get down to the real work.

I do wonder whether Rails has been kind of a mixed blessing for Ruby all in all, though. I think Ruby is, in itself, a great alternative to Python or Perl, and it's the language I reach for first when I'm writing short utility scripts -- but since Rails exploded in popularity before Ruby itself did, a lot of Ruby programmers really only know Ruby to the degree they know Rails.

> a lot of Ruby programmers really only know Ruby to the degree they know Rails

This so bad that frequently I see “Ruby on Rails” in lists of programming languages aside “PHP”, or “Elixir”, or “JavaScript”.

(When I was most in to Ruby – but not so much Rails, even then – there was actually a palpable divide in the community between the Rails-only community and the broader Ruby community, some of which was Rails-inclusive.)

Granted, I have never used it a lot except for hacky projects, but I have never used any Ruby except in the context of Rails. Is it really used for anything else?
Yeah Rails is definitely a blessing and a curse. I only know of Chef and Puppet being kinda big, but both of those are waning in popularity.
> FWIW, I had a call with a recruiter a couple days ago who claimed that the most expensive candidates to find at the moment are Rails people.

Maybe in USA. In Europe, Rails has been far less popular. Now I imagine expensive candidates means the ability to work on decade old Rails codebases from previous versions, which means with a lot of Rails experience.

Specifically asked about this. Mixture of old codebases and new.

Half the companies using it are 1-2 years old according to him. Lots of 10 person startup teams just fresh off a raise.

Stripe, Shopify, and others are contributing. They are large enough to provide some large corporate assurance, if that is what you are looking for.
Don't forget Square, GitHub, Airbnb, Bloomberg, Zendesk...
> until Google abandons it

Given Google's track record I'm not sure that's the most reassuring argument...

While not widely advertised, matz works at heroku, which was acquired by salesforce for more than 10 years now. In essence, Ruby is supported by Salesforce.
Google abandons as much as they support.

The Ruby and Rails ecosystem has Stripe, Shopify, GitHub actively pushing new things all the time, DHH and co working on version 7 right now, etc...

I still get a real kick out of Ruby's elegant and powerful metaprogramming, which is something other languages don't often compare to.

    class String

      def colorize(color_code)
        "\e[#{color_code}m#{self}\e[0m"
      end
    end
The general advice is to avoid confusing others though, so changing base classes like this is not really a business-safe idea.
Is there a good way to verify that all of the code is business-safe?
Delete it? Otherwise no.

But this is true of any language. The truth is in the middle ground.

It's not entirely true of any language.

In Java, for example, one can do static analysis and identify when a class is doing reflection... and flag as an error if the class is doing reflection on a class that is an instance of java.something.

How do you define "business safe"? Java won't prevent you from sending a message to the wrong customer or something like that.
I can look at the code and see if anyone is doing:

        Class cache = Integer.class.getDeclaredClasses()[0];
        Field c = cache.getDeclaredField("cache");
        c.setAccessible(true);
I can examine to see that java.lang.{something} class is getting reflected on. I can check to see if anything is calling getDeclaredField and flag that. I can see the setAccessible and really flag that.

This isn't about coding errors. This is about being able to analyze the code and see if the code is using prohibited methods.

Through static analysis, I can verify if anyone is trying to do something tricky with the String class.

Can I verify if a method is being modified added to an instance of a String in Ruby through static analysis?

I don't know of anyone actually doing that, but all the code is right there. You could probably wrangle the linter into checking those things if you really want to. That said, many Ruby frameworks rely on being able to dynamically add methods to classes at runtime so I don't think such a thing would be all that beneficial.
And besides general craziness and DSLs as pointed above, you can also easily experiment with relatively complex language-level constructs, like derived attributes or cacheable functions [talked a bit about it here https://news.ycombinator.com/item?id=22338923].

Trying to make such experiments safe in Ruby would be unwise, but starting them in Ruby is happiness.

I do love this. The ability to change base classes so easily is such a "With great power comes great responsibility" lol.
That's pretty smalltalkish, also with the trend of extension functions you get that more often these days. I remember doing such things in kotlin. Maybe not perfect for large projects but a real pleasure for developpers.
What's nice about extension functions in Kotlin is that they are statically imported. So you're not really modifying the class, and there is no danger of collisions (like it was when people monkey-patched javascript built-ins back in the day).
Ruby's refinements sound somewhat similar; they let you scope your monkey-patches.
Ruby is Smalltalk becoming successful. Ruby meta programming is very nice. Ruby is OO both internally and externally. Unlike Python which doesn’t feel very OO.
Ruby is Smalltalk jettisoning everything that makes Smalltalk awesome.
A major difference between Smalltalk and Ruby is that in Smalltalk, the live system knows its own source code, and you program through the live running system. Ruby doesn't really do this, it's more of a scripting language with Smalltalk semantics. Ruby source reads like Monticello changesets, a suboptimal format for exploring and modifying a dynamic object system.
Supposing you need to do this kind of stuff a lot, one fairly nice workaround is to subclass the base class and then use that subclass when you need added mutative and/or chain able functionality.

The drawback in this case is it's not as concise as just typing in a String literal :)

What is the wow with Rust? Seriously asking.
A few things come to mind. Rust has the potential to be fast... VERY fast. It also can be very safe. Pretty much everything in Rust utilizes the Result type (an Either Monad that causes Errors/Exceptions to become first-class citizens). It compiles to a single binary. Many of the packages in the ecosystem are very high-quality (Serde for example).

Even still, this doesn't mean anyone should drop what they're doing and migrate all their code to Rust! If you're a Ruby dev (especially if you do Rails) and you're making a living churning out apps with your good old friends like Devise, RSpec, etc. Rust is probably not the thing that'll really wow you. It _can_ do web, and do it REALLY well. But the experience is very different. (Actix/Rocket)

(comment deleted)
So Rust wants to be the new C? Like if someone was writing a new OS or code for an autonomous vehicle today is Rust a likely candidate?
Rust wants to be the new C without C warts, using the compiler to ensure memory safety (up to a point), promoting immutability and having generics baked in.

I'm not a C programmer, but I think Rust can fit almost everywhere C can fit.

> Rust has the potential to be fast... VERY fast

I think this should be phrased differently. There is a minor bloom of zero-allocation web frameworks in go and java, and probably a few others, which blow their peers out of the water and are horribly not at all idiomatic usages of the languages.

They can be very fast, but the performance cliff for using idiomatic code is very significant.

Does idiomatic rust perform VERY fast? Can it be both very safe AND very performant? I think the answer to both of those is yes, but I honestly haven't used it enough to know.

Yeah, I was wondering about that as well. Maybe the parent comment meant the practical implications, such as C-like speed with memory safety? As a language, Haskell has much more wow in it.
Does it have C like speed though? Have no idea. I guess I just don't care enough about performance for Rust to be a thing for me.
I don't really use Rust so YMMV, but what's genuinely special about it is that it's a new take on a system-level language with very modern features (Error monad, borrow checker, pattern matching, functional-like semantics) that were previously exclusive domain of garbage collected languages.

Honestly I kind of cringe at the "do everything in rust" crowd, if you need to, say, write an API, you can just do that in Python or Ruby or Go, 99% of the times the performance penalty won't matter and Rust is just a very complicated tool for that job.

But it single-handedly reopened the discussion on high performance, safe(r) languages, and I believe that's a very good thing even though I don't use Rust day-to-day. Projects like Zig are in a sense following in the footsteps of Rust.

The ability to use mutable data structure with worry-free mentality of immutable data structure (FP langs) is really new and special.
So its a functional language with good performance? Or a systems functional language?
Rather than designing around shared mutable state like a functional language, it gives you the tools to do it with greater confidence.
Systems programming language that's safer than C++, just as performant and has lots of functional goodies.
Go is not a business oriented language. To be a business language, you need a decimal data type built in (or in the standard library), that doesn't make you go through hoops like this:

    total = new Decimal(principal);
    total.mul(1.0 + interest);
In other words decimals support the same operations as the rest of the language's numeric tower. Go doesn't have this.

Go is a networking language. It's good for writing microservices and network protocol clients and servers. That's about it.

I've felted wowed in theory by Rust but every time I come to it, I'm constantly getting stuck by how much the compiler gets in my way. On one hand, the idea that the compiler is your friend that stops you from making dumb memory decisions unlike in c++. But with Rust, I can't get even simple tasks done which really frustrates me. Perhaps Go might be a language to checkout if it "gets out of your way" as you say.
Ruby is for handful hacking lang for me like old days Perl. It seems that thoughts who learned Ruby for production Rails app vs learned Ruby for hack is very different.

Python is also great but I still wish Ruby is installed everywhere for writing one-liner since Python isn't good for that.

I also think Ruby should be the natural successor to peel on all *Nix systems.

Ruby is ridiculously useful. Python edges it out for scientific/engineering applications because of Scipy and now Machine Learning ecosystem.

I love Ruby's syntax (even if the parser is a nightmare of special cases) and overall feel. But, I have no reason to use it because I really don't like using Rails. Rails remains one of the few libraries/frameworks that I just don't get along with.
Is Sinatra too bare bones?
An old joke: any sufficiently advanced Sinatra app is indistinguishable from Rails.

  Many systems using other “preferred languages” also
  implement some form of GIL (e.g., Javascript’s V8 machine,
  CPython); we don’t hear complaints about it, because these
  languages have a rapport for heavy lifting and parallel tasks.
As a python developer i almost fell off my chair when i read this section. We don't hear complaints about the GIL in python? I love the article's tone in general but that's some heavy Gell-Mann Amnesia or filtered news sources :)
(comment deleted)
There's scarcely a Python thread on here that doesn't mention the GIL. Or version 2. Or whitespace. It's like generics for Go and framework churn for JS.
Hey guys, I'm the author of this article and I have been rueing the day I ever said this. I have since received complaints and/or restraining orders from a number of Python developers. I truly apologize, that one is on me, I made a classic mistake of writing about what I hear about instead of what's actually out there, for which I repent. We live and we learn! This is my first article so I gotta start somewhere. I've edited the article to avoid further contact with rage-filled Python devs:

"Note: Many systems using other “preferred languages” also implement some form of GIL (e.g., Javascript’s V8 machine, CPython). Python has a reputation for heavy machine learning lifting and parallel tasks. However, when it comes down to actually looking at the benchmarks, the constraints, and the underlying implementations, its quite hard to pull out any statistically significant metric or distinction between how Python and Ruby handle these tasks — what Python has in advantage over Ruby is its popularity, vast library, and very active data-science community, moreso than any benchmark. Ruby is a little faster in some things, Python is a little faster in others.

Edited: I previously had a line in here saying that we “don’t hear about” Python’s GIL, to which I received a number of messages from Python developers who assure me that it is all they talk about. Sorry Python!"

I'd be curious to have a good example of when to use a Fiber vs a Ractor in Ruby. I'm assuming it's much much faster to spawn a Fiber? Or am I missing something?
Fibres are best for concurrency. Ractors are best for parallelism.
In actual practice... ractors are kind of still new experimental technology, that are hard to use if you are using any existing gem code.

And fibers are not new, but also can be hard to use and aren't super popular in general use.

So the practical answer is you probably won't use either. :)

But one way to explain the difference is that fibers are basically for cooperative/evented concurrency, while ractors are a new invention that are more like (OS native) threads but without shared memory.

This is a really fluffy article devoid of real technical content. It does not sound like the author fully grasps all the concepts discussed, especially in the section on parallelism and concurrency.

> Many systems using other “preferred languages” also implement some form of GIL (e.g., Javascript’s V8 machine, CPython); we don’t hear complaints about it, because these languages have a rapport for heavy lifting and parallel tasks.

GIL is the biggest performance obstacle for python and is constantly discussed. JavaScript is notorious for being exclusively single threaded (unless you consider the very late arrival of workers to be true multithreading).

JavaScript is single-threaded, but in the most popular runtimes, almost all I/O is event-based. This is a great difference from Ruby where library functions are blocking (or at least were when I last used the language many years ago).

A single thread of execution for scripts isn't so bad when those scripts are all relatively small callbacks.

Yeah, it's fine for "reactive" processing but not for anything where you'd actually spin up a separate thread (or use a threadpool thread) in a lower-level language - i.e. to perform cpu-intensive calculations/computations in parallel. In practice, JS being single-threaded isn't an obstacle for the uses the developers using JS are after. It doesn't sound like Ruby 3 affords the same with its GIL (but all I'm going off of is TFA).
Hey! I'm the writer of the article. I'm not a fantastic writer but am trying to improve and felt I needed to start somewhere, so I started with something I'm passionate about. Truth be told I do not know as much about Python as I do about Ruby, I think I was probably responding to its comparative popularity and not in fact if it is discussed about or not, so that's on me.

I'd like to know more about what you would have liked to see in an article like this, it is a bit of a fluff piece; the goal wasn't to provide a super technical explanation. The goal was to get people talking about Ruby 3 and I am happy to see so much discourse here! But yeah, I was asked by the maintainer of the blog to try to provide "layman's explanations" when I could, which I think may have kneecapped me a bit in retrospect - but obviously layman's explanations usually are best when they are succinct and accurate. Is there anything else, particularly in the layman's examples for parallelism and concurrency, that felt inaccurate or misleading? I want to make sure I am communicating the concepts and implications correctly.

From my perspective, the goal of the article is provide an explanation of concurrency/parallelism, so that when I begin to describe the features in Ruby 3.0 we have appropriate context to understand why fibers/ractors matter, so if I didn't do that I really bungled it!

I saw you edited your post, which is great. Happy to chime in from the Python side: people complain a lot about the GIL but in practice a lot of the truly parallel logic happens in C extensions, which are lately quite easy to write. This is where all the heavy lifting for machine learning happens; the I/O parallelism that one might see in e.g. a scraper is a different kind of thing (e.g. fibers). I don't know much about ractors but it's neat to see a GIL being lifted!

Small nits: the image with fibonacci performance numbers needs a maximum number of significant digits. I think "implement" usually applies to an algorithm or idea; you might mean "use" Sidekiq? The thing I'm most curious about is how easy it is to write an extension in C/C++/Rust for Ruby (in comparison to cffi, pybind11, etc.).

Best of luck! It's not easy to write a technical article and face criticism, but I appreciated reading it.

I think it's important when writing an article like this to stick to what you know about. If you aren't sure what is going on with the GIL in Python or v8 and whether it's discussed or how it's relevant, either research to learn more, or don't mention it. Instead of assuming things or implying assumed things, to make the article flow.

Articles I trust are where I trust the author knows what they're talking about and doesn't assume things they don't know.

Totally, I understand. I've since changed the language to not assume anything, simply stating that they exist, which is all I know. I was concerned that I was painting a picture of GIL being a Ruby concept, which isn't the case and is why I included it originally, but you're absolutely right. Thank you for the feedback, really appreciate it!
Hey, so I would've taken a few more seconds to be less blunt if I thought the author was reading this - sorry about that. Also, you say you're "not a fantastic writer" but I think you're being way too hard on yourself: the writing was just fine and I had no problems with it; it was the teasing of technical content without followup that led to my comment.

That said, for me the issue was that the introduction read like "this is going to explain the technical reasons why Ruby 3 rocks" and each section/bit thereafter was ostensibly "technical reason x/y/z why this is better" but then no section really followed up to the promise of actually providing any hard technical details (this is aside from the inaccuracies about other languages).

So, for me at least, it was about expectations not matching the content. I'm not a Ruby dev, but I am a programming language internals fanboy and I was excited to get a technical peek into what a hard-core Ruby user was saying had changed but found myself really stymied/disappointed that it seemed like the same bullet points were being repeated but with no technical content getting delivered.

TBH, it's really hard to write for nerds like us. I'm sure if I'd organically discovered your post, perhaps while Googling something you wrote about or if shared from a Ruby devs' group, I think I'd have come away with a different conclusion from the article. But seeing it featured here on HN played a role in making me think it would have juicy technical content which kept being referenced but then kept just out of arm's reach.

Thanks for trying, though! Sorry for being grumpy.

One of the questions we had for python developer interviews in my previous startup was regarding implementing parallel/concurrent tasks in Python and we expected the candidates to tell the limitations with GIL to do justice to the parallel/concurrent tasks.

Honestly anything to improve performance with large python applications seemed like a hack - gevent, Gunicorn, uvloop, switching libraries to cython etc. It delayed our product rollout and increased costs(incl. cloud infrastructure). Hence I switched to Go for anything where performance matters.

Good to know that Ruby3.0 has made some improvements regarding concurrency/parallelism.

> JavaScript is notorious for being exclusively single threaded

Sure, but this concurrency discussion is talking about green threads / event loops as much as true parallelism.

I still enjoy writing Ruby, and while I consider myself a rather rudimentary programmer, I do regular exercises to maintain my skill in Ruby so that I can use it to get things done. For many years, Perl was my go-to language for getting things done, and Ruby has fully supplanted that. For some of the things I used to reach for Ruby to do, I now use Go, but for the most part it's now all Ruby.

One of the things I love about Ruby is that you can do very powerful things with minimal code, while still having it be understandable. The way metaprogramming works in particular is fantastic. I also like that Ruby provides an escape hatch to do horrible but necessary things (backticks), which lets me utilize existing hacky scripts and build upon them, without needing to rewrite everything to include it.

> while I consider myself a rather rudimentary programmer

You missed an opportunity for a amazing pun :-)

The company I work for re-implemented out entire platform with Ruby on Rails. Even though it's not super new, everyone has really fallen in love with ruby. The gem ecosystem and the community are great. Ruby is an absolute joy to program in.
Rubygems is one of the best packaging systems I've used.
We use Devise. The fact that it's free and open source blows my mind. It's some incredible software.
> Ruby is an absolute joy to program in.

Really? At my company it seems like 90% of the tests are catching things that would be caught automatically if we had used a proper language with strong types/compiler.

IMO Ruby is slow, not particularly beautiful (yes, this is subjective), and seems optimized for shoving crappy REST endpoints out the door as quickly as possible.

Have you tried Crystal to get static typing?
Crystal seems very interesting, but how is the ecosystem like? How hard/easy is it to find libraries?

Also, it seems like a very small team behind the language. Is longevity an issue?

I have been infatuated with Crystal since I first saw the 1.0 release posted here in the spring.

Your questions point out the obvious shortcomings of Crystal currently. While it is easy to find libraries, they are few and their support is questionable. Not to do anything with the language itself or the ability of community, just the nature of a new and small ecosystem.

The team is small but I take solace in the fact that they have been at this for a very long time now (2011).

Once nicety that helps the ecosystem is the easy of interoperability with C-libraries. Many shards are simple wrappers around an already established C library.

I just started learning Elixir, Crystal is another language that I want to try at some point. From the first looks of it, it is not going to be that hard to learn (like Haskell or Rust). Lucky framework also seems interesting. I don't think I'd need some niche library for my personal projects at least, but it would be nice to know what one is getting into.

I haven't looked at other languages seriously - at the moment Elixir and Crystal seem to be the most interesting to me

Do you really need those tests? We are testing validations, CRUD operations, states, border conditions. Sometimes an integration test is enough to validate at least the happy path and catch any mismatch between passed and expected arguments: if we are passing a string instead of an array of strings somewhere, the test will fail.
If the tests are catching bugs, obviously they need them.

And if those bugs would be prohibited by static typing, then it sounds like Ruby is creating work.

> if we are passing a string instead of an array of strings somewhere, the test will fail

Is this an example of a real bug? It's mind boggling that anyone would use a language that allows them to type that bug into existence without an immediate error.

I know we used to be forced to use JS, but not we even have TS so that we don't have to catch extremely machine-catchable errors in tests or, worse, production.

You're going to write the tests anyway. Static typing doesn't free you from that responsibility. The question is whether any type errors would make it past a unit test suite focused on other kinds of correctness. In practice they usually don't.
> like 90% of the tests are catching things that would be caught automatically if we had used a proper language with strong types/compiler

It sounds like the tests are testing the wrong thing

> seems optimized for shoving crappy REST endpoints out the door as quickly as possible

Ruby is a general purpose language. Perhaps it is Rails that you have gripes with?

I'd also like to hear what you are doing that leads you to the conclusion that 'ruby is slow'. For most domains I would say ruby is fast enough to solve the problem in a way that customers are perfectly happy with.

> shoving crappy REST endpoints out the door as quickly as possible.

I would argue 90% of the software businesses I've seen are simply CRUD REST endpoints. If that means you can get those out the door as quickly as possible, why on earth would you want to use anything else?

It's almost like you're actually advocating for it...

You have to use the right tool for the job. If you have a very big project, with a requirement for strong types then you should probably use C# or Java.

If I'm in a situation where I need to throw up a rest server as soon as possible, I'm probably using NodeJS. It's dirty but it works ( except when you have the wrong Babel compiler installed and lose 3 days of your life trying to fix it)

Agreed. I've done a lot of Rails over the years, and concluded that, except in the hands of a stable and incredibly disciplined, talented, and knowledgable-about-Rails team, it borders on being write-only.

Ruby's fun to write but I hope never to onboard to a Rails codebase again. I think the vast majority of the ones in the wild are... not great, to put it mildly.

This is probably closer to the real reason that we have had so much fun. I am not particularly senior, and I was wholly new to ruby, but the senior engineers that joined are the "incredibly disciplined, talented, and knowledgable-about-Rails team."

It's not just the framework, but the fact that have proper tests, architecture, and CI/CD.

I am curious what codebases you have encountered in the wild (with similar age and turnover to those ruby ones) that are great and easy to work with! Have you found this correlates to other platforms better?

I feel like in my career, across many different languages and platforms, "legacy" codebases (ie, any codebase that pre-dates me and is a non-trivial amount of code) are uniformly "not great to put it mildly".

Of course most codebases are shit, but it matters a lot more when a Rails codebase is shit than in many other languages/frameworks. The reasons are mainly:

1) The amount of "magic" available and how much it's used—in low-magic scripting languages or frameworks, you can at least grep to find definitions, even if better code navigation tools aren't available. The more often the answer the "wtf is this?" can't be known for-sure until runtime, the harder it is to find your way around, and the more memorization you have to do. Rails and its ecosystem are very high-magic, even more so than something like the roughly-comparable Django. It can be annoying to even figure out which gem defines a given symbol, in a given context.

2) The level of reliance on tests to keep things from falling completely apart. Tests are generally good things, of course, regardless of language, but a poorly-maintained test suite in a Rails codebase is a far more grave problem than it would be in, say, a Go or Typescript codebase (yes, it's mainly the static typing that makes the difference). That is, keeping the codebase viable requires more active attention and work.

This is exacerbated by Rails being a common choice for bootstrapping startups (the library ecosystem, especially Devise, which might be single-handedly the main reason Rails wins as many "what should we use?" discussions as it still does, is a pretty damn strong argument in its favor) and bootstrapping startups having a tendency to go through multiple teams in short order (contractors and external dev teams being common, both in the early days and in the somewhat-later, very common, "oh god the cut-rate shop we got to build this fucked it up, please save us" phase) means that a whole lot of live Rails codebases have been treated very poorly, and that, for the above reasons, a Rails codebase that's been treated very poorly is a special kind of hell.

I am genuinely curious, in your experience of working with "legacy" projects, what platforms/languages, with codebases of approximately the same age/turnover/type-of-project as the Rails ones, were significantly "less shit"? You didn't answer that part! Or, I guess, you implied Django?
I did cover that—it's irrelevant, because Rails in particular is much worse, at similar levels of neglect or incompetence, than lots of other frameworks+languages. It's a joy to build with from scratch, and it's fine as long as your team is steady, disciplined, quite good, and mainly focused on your Rails codebase (that is, it doesn't go for long stretches without eyeballs on it and effort going into keeping it up). Deviate from that ideal state and it starts to turn awful in a hurry—and of course other languages and frameworks do, too, but the curve for Rails codebases that fall of that ideal plateau of quality is much harsher than most.
So you have worked with legacy codebases at similar levels of age and project type that haven't been as bad as the Rails ones? I am just curious to know what they are! I don't understand why you don't want to tell me, but ok, the end!
All proprietary ones, but yes, of course. I don't know what you think I'm trying to avoid telling you—I've worked on a lot of codebases in a lot of languages for a lot of different platforms over ~20 years, and repeated exposure to Rails codebases (maybe half a dozen of them?) has yielded the observations already posted: that they are like closed-ecosystem terrariums, which are beautiful until something goes slightly wrong, and then everything good about them withers and dies in short order.
The gem ecosystem is a direct result of the language decisions. Ruby is IMO, the best language for working with 3rd party libraries.
I like Ruby. Rails, not so much.
Is it just me or are Ruby and Python cousins.

I really really didn't like Ruby when I tried to learn it at work , but Python just clicked. I imagine many Ruby programers migrated to Python.

Then again, Nodejs started to take off when Ruby declined. I strongly suspect this is due to all the "full stack" positions. Hey Billy, you write all that nice js on the front end, now you can write it on the back end too.

> Is it just me or are Ruby and Python cousins.

Not at all, they used to be competitors in the web space but Python won the academia space. Python is taught at university in Europe, Ruby far less.

Node.js is a mess, not because of javascript but all these layers of complexity imposed by professional front-end development, and on the server because Node.js standard library is pretty poor. I shouldn't have to use a third party library just to parse a multipart http request or work with cookies...

Go in that domain is just examplary. The std lib even comes with a Go parser, which is just invaluable for implementing code analysis tools, and it's very easy to do so.

Personally I like Python much more than JavaScript but at work I almost exclusively use JS. Recently I’ve been doing stuff in node.js and it does make it much easier to flip back and forth. Still like Python more and I can’t help but put ;, (), and {} all over the place.
I imagine many Ruby programers migrated to Python.

Not my experience being involved with the community. Indeed, there seems to be rather less migration between the two communities than than other languages (e.g. Python + Go, or Ruby + Elixir) probably by virtue of their similar problem spaces and approaches.

I'm a Rubyist who also knows some Python and while I admire Python, I certainly prefer Ruby. Python is flexible and fantastic in many ways, but is a far less consistent language in terms of organization (e.g. you use methods for some things, functions for others) which didn't click with me. If you want to do something with an array/list in Ruby, say, 95% of the time it's "arr.method" whereas in Python it might be len(arr) or arr.method, a comprehension, etc.

Ruby and Python are close cousins in many ways, and if I'm being totally honest it's hard to justify why they both need to exist when they serve such similar "general purpose scripting language" use cases with similar performance profiles. But when you get beneath the surface they have fairly different aesthetics and ergonomics, and that's the biggest thing that shifts developers toward or away from one or the other. As you described one just "clicked" for you, I think many developers feel that way about one of the two languages, but not both.

The coolest thing about Ruby is that the language paradigm is very internally consistent - everything, absolutely everything, is just objects and methods. The language has very few core constructs, but they can be composed together very fluidly to create all kinds of rich abstractions. People who dislike Ruby generally dislike this specific aspect -- it tempts programmers sitting atop mount stupid to go nuts with meta programming and try to make "magical" code when it isn't called for, and that's annoying to deal with on a team.

By comparison, in Python there are multiple paradigms and you need to learn where they apply. Why are things like `map` and `len` global functions, and why shouldn't we just call `__len__` on that object ourselves? Why do some functions for list processing take a list first and then a lambda, and some do it the other way? Why do you have to define self as the first argument for methods but you then just ignore that argument when calling the method? Why is it so hard to perform a relative import? Python is less consistent.

The other nice thing about Ruby is the elegance of it's closures and block passing - I miss that a lot when it's not present in other languages, and am always excited to see new(ish) languages like Kotlin embrace that paradigm. That, combined with the enumerable interface, make for great functional programming and list processing in Ruby. The alternatives in Python are certainly functional, but feel clunky to me.

On the other hand, Python has better semantics around named versus positional arguments, better type annotations, and decorators, each of which I would love to see in Ruby but for many reasons don't expect to. Python's import system allows more control over the global namespace, which is very nice. And lastly, Python has become the de-facto academic language which has led to it's fantastic ecosystem growth. Python is everywhere and there's a python driver or library for everything. Ruby has a good ecosystem, but not near as good as Python.

As for the bit about Node, the rise of Node and relative decline of Ruby are the same phenomenon, it was the full-stack web hipsters that had powered the rapid rise of Ruby moving onto Node that helped Node rise quickly as well. There were valid reasons, specifically 99% of Ruby developers also need to be proficient in Javascript, but the two languages are quite different, and many engineers felt (reasonably) that it would be nice to just pick one and have it work across the stack. Well, the browser doesn't run Ruby. Also, Node's evented model is a good fit for precisely the kind of IO-bound stuff that's a bit harder in Ruby.

But mostly, the hot-new-thing wave follows a pattern of enthusiastic adoption and evangelism, then over-adoption, followed by cynicism when the things that were built in hotlang don't scale up as well as their enthusiastic early adopters hoped, followed by the embrace of next hotlang and the trashing of *previous hotlang. So Ruby had to ride that out and calm back down into just being a normal programming language again. Meanwhile here comes Deno... ;)

>Why is it so hard to perform a relative import

I've lost many hours trying to get relative imports to work. It might be the one thing about Python I absolutely hate.

But Node doesn't do this well either, maybe it's just the nature of dynamically typed languages. The two programming languages I enjoy the most would probably be C# and Dart / Flutter. Having types, like real types is essential when projects scale. However I only get to enjoy these programming languages in my spare time.

Personally I think Dart is everything I could ever want in a language. Being able to use types when I need to, and the freedom to use Dynamics when I just don't feel like creating a new class. If you haven't tried Dart yet it's like Java's younger sibling who's easier to get along with.

Dart strikes a perfect balance between dynamic and strongly typed languages. Dart is better than JS, typescript and java combined. It has a great VM that makes development easy, an AOT compiler that generates native binaries like Go, and can also compile to Js just like typescript. The language is familiar, easy to learn and the type system is very powerful, sound and non-nullable. Dart SDK includes everything you might need: standard library, code formatter, linter, static analysis, JIT and AOT compiler, package manager, dev tools etc. Right now Dart found its niche in Flutter(which is great imo), but I wish there was a backend framework like Django or rails that would leverage this amazing language.
Flutter web is amazing. I have the opportunity to build a side project with it last year, and I just love it. Compared to trying to build web applications with React or Vue, Flutter doesn't have to deal with the baggage of the JavaScript ecosystem.

Here's a server side Dart framework

https://aqueduct.io/

Not sure how mature it is, but if I ever have a need to build another backend server I'll try it. I tend to prefer managed solutions now like Google's Firebase, which integrates so well with Flutter ( obviously because Google has a vested interest in you using their services)

Ruby used to be considered a more beautiful Perl. With Perl it shares powerful meta programming facilities, good package management and a high degree of flexibility when it comes to implement something. Ruby added a MOP and prettier syntax. Many early Ruby devs migrated from Perl. Pythonistas always were a community of its own and tended to frown upon any other language users.
In the grand space of programming languages, Ruby and Python are twins with slightly different birthmarks. I exaggerate maybe a little, but not much. A lot of their differences are cultural rather than technical.
You may not be completely familiar with them? The object model is fundamentally different. The syntax is vastly different. The runtime capabilities are different. Performance characteristics are different. (Ruby has less startup-time overhead.)

Subjectively, I’ve been using Python since version 1.5? on classic Mac OS — but I’ve never liked it much. Always feels like a struggle to do basic flow control. Ruby really clicked for me. The ‘_why the lucky stiff’ quote really resonates: it’s the language Buddha would have programmed in.

You're using the perspective where you sit them right down next to each other and compare them directly. In that case, every little small difference leaps out and they look very different.

I'm using the perspective of the whole programming language landscape. Take Python and Ruby and sit them next to Haskell, or SQL, or Prolog, or best yet, all of them at once. Even within just the "dynamically typed languages" they are the most similar to each other.

Syntax is one of their greater differences when sat next to each other, but much less impressively different when considered in the whole landscape. Syntax glosses on virtually identical semantics.

As I recall there is a loose connection between them due to history. When Perl added an object system in version 5 it was heavily influence from Python and Ruby's designer was inspired by Perl. You can see a lot of similarities between the three beyond their dynamic nature.
Ruby's influences are sometimes described as being both Perl and smalltalk, but I'd say Ruby's OO comes more from Smalltalk than Perl OO.

Things that came more from Perl to ruby include: Ruby's syntax; first-class regex support; some rarely used features like the Perl-ish global variables and command-line options; just the idea of being an interpreted unix-friendly language executed like `ruby file.rb`.

I do think Python and ruby are very similar languages, in the whole universe of languages. I think that's not really because either influenced each other, but instead because both were invented at approximately the same time, to meet similar needs -- both as interpreted-not-compiled, edit-with-a-text-editor, with C-like syntax, etc.

Them both being so similar, I wonder what's behind things like "ruby just didn't click for me but then I loved Python" -- but then, I'm the same just opposite. I don't know if I'd say it didn't "click", but I much prefer ruby to python, hugely (and sadly at this point, I feel like a betamax enthusiast), despite knowing that they are basically similar languages.

Ruby has some what hostile rules imo.

Such as end and lower casing variables.

Another factor to mention, Python has some specific use cases, like machine learning which I can only effectively learn by using Python. I actually managed to secure a 30k pay raise by learning Python in my spare time.

Anything I can do in Ruby, I can already do in NodeJS. If I ever run across an employer who would offer 30k or 40k more for me to learn Ruby, I would definitely jump at the opportunity.

Of course I understand why people use python if that's where the jobs or better pay are, I have no confusion there! Or for that matter, if that's where the libraries for doing certain kinds of work, like machine learning as you mention, are. None of that is a mystery, as reasons to use python.
I wish I could merge the parts of Ruby and Python I like while discarding the parts I don't. Mutable strings by default was a huge mistake in Ruby and so was allowing non-self calls to methods from another method of the same class. Within the class scope, it's great, but it just leads to bugs in the method scope. The things I love most about Ruby over Python is I don't have to memorize as many things. With Python I'm never sure if it is isinstance or is_instance or DefautlDict or default_dict. It's annoying having to constantly lookup things. Oh and how I miss one line if statements and conditional assignment when I'm in Python.

One thing I like about both languages is how nice it is to write tests. The patching and the assertions are great.

> I wish I could merge the parts of Ruby and Python I

Crystal lang does a bunch of great thing but the poor support on Windows (having to install some Linux subsystem to compile stuff) is a non starter for many companies.

I personnally never liked Python's syntax, or OOP, it feels tacked on. However Python's ecosystem is just too huge to be ignored.

I have the same feeling. Chaining is so much more intuitive in Ruby.
You can write one line if statements in Python. You can also do conditional assignment with the ternary operator.

i.e. if True: a = 1 if True else 0

> a = 1 if True else 0
Why should I need an else statement to use an if statement?
You said you missed two things in Python:

> Oh and how I miss one line if statements and conditional assignment when I'm in Python.

derac provided an example exercising both. To separate them:

One line if statements:

  if predicate: expression
Conditional assignment:

  a = 1 if predicate else 0
The else is to permit the conditional assignment, it's a ternary operation, it is not for the if statement.
Well, sorta. In practice people don't use one line statements and it's considered unpythonic. So much so I forgot it was even possible, so you're right, I was wrong. Black converts it to a multiline statement. Also, the Ruby syntax for them is better because it makes it clear it isn't a mistake.

     launch_nuclear_weapons if at_total_war
Just reads better because it doesn't look like a mistaken if statement.

By conditional assignment, I meant more something like this:

    some_var ||= 45
And I know I can do either:

    some_var = some_var or 45
    some_var = some_var if some_var else 45
But it just looks stupid and it is such a frequent need due to the way default args work for things like dicts, that it gets annoying.
What is your issue with mutable strings? I've been a heavy Ruby user for 16 years and have never really thought about strings being mutable... what negative effect does it have?
It allows for certain classes of exploit and is not worth the cost for the negligible performance gain in 99.99% of the situations. Before there was a comment to disable them I would see codebases littered with .dup or .freeze.
> Mutable strings by default was a huge mistake in Ruby

This was changed in 3.0. String literals are now frozen/immutable by default.

I don't believe this is correct.

There was a plan to do that at some point, but it was pulled back from for backwards compat reasons.

You can opt-in to string literals being frozen by default on a per-source-file basis with a magic pragma comment, and this has existed for several ruby 2.x versions and is unchanged in the released ruby 3.0.

Oh, huh. Yeah, you're right. Really showed my whole still-on-2.7 ass here haha
I do love Ruby, my first love, and honestly could be my last. I turned my back on her when I found Node and Go, but as of late I have come to appreciate her simplicity and ease of use. Performance aside, I would re-write our stack in Ruby specifically rails just for the organizational aspect and the fact that Ruby is just so damn pretty.
I still love writing Ruby. I suspect I probably always will, in fact, and I use it as my system scripting language over Python and the like. It has always made sense to me and I enjoy it being a part of my day-job too.

If I need to write something, like a small tool, or an API, or a Prometheus exporter (https://github.com/robotmay/prometheus-aanet-exporter/blob/m...), I write it in Ruby. The Prometheus exporter is a good example actually: nobody else seems to write them in Ruby, but I found it easier to make one from scratch than to figure out the pretty obtuse and non-standardised examples written in Go by everybody else. Obviously this won't be true for everyone else, we all have our own favourite languages, but for me it's very rare that I find something that can't be written effectively in Ruby, so I'm happy to keep writing code that way.

There's always a lot of arguments about Ruby/Rails performance, but it's actually not too tricky to make it run fast enough for most tasks. It is fairly easy to shoot yourself in the foot I guess, compared to other languages which are natively fast, but there's a downside to all languages.

I totally get what Matz said about threads, and it's also no mystery to me that there are so many GIL's around.

Adding threads complicates the interpreter, to the point where I'm beginning to doubt it's worth the effort.

For my own interpreters I've had success running separate interpreter instances in their own threads and communicating via channels. This allows multi-threading without making a mess.

https://github.com/codr7

To amplify your statement, it seems to be borderline impossible to 1. develop a world-class interpreter for over a decade and then 2. retrofit multithreading onto it.

I don't have an example of that I'd call successful, where here I'm defining "success" as "the entire community casually uses it whenever it is useful and there are no special warnings to be given about the threading support". There are some implementations, but last I knew they all tend to be sort of dangerous and things the community will warn you away from, and some languages just don't have them.

I would be intrigued to see someone try to create a modern dynamically-typed language or interpreter written from the beginning to be threadable, but it seems to me the energy in the dynamic typing community may not be there any more to sustain it. While it's not "dying", I suspect that as static typing is getting better the dynamic typing community is, shall we say, losing the updraft it has ridden these last 30 years. It's not like it's going to crash straight to the ground or anything, but I don't know that there's a whole lot of people chomping at the bit to write such a thing rather than write something static and useful. Especially when you deal with the fact that even the fastest dynamic languages are still ~10x slower than compiled languages on general tasks now, and it's hard to justify going crazy with threading when a single thread in a modern statically-typed language, which may only be modestly harder to write now than with a dynamic language (if that), starts out with such a performance advantage, one that only continues to multiple if the static language also starts spawning threads.

I would be intrigued to see someone try to create a modern dynamically-typed language or interpreter written from the beginning to be threadable

There is Clojure, is dynamic and allows for multithreaded programming, courtesy of the JVM.

The JVM being a very dynamic system is a good target for new dynamically typed languages. But as you said, they are a hard sell today not only because of performance but more because of static typing.

Ruby & Ruby on Rails was my first love, my side projects were always use Ruby, until the performance really hit the point where I can't tolerate it anymore. I moved to Elixir then Golang. But one day I would love to start new project using Ruby 3.0.
I'd love to hear more about the performance needs of your side projects that made you have to stop using Ruby. I also use ruby for my side projects and have been considering a switch but for other reasons.
When it comes time for the Ruby project, try out JumpStartRails.

It's just a great skeleton Rails app to begin with. You'll be able to start on the hard problems much sooner.

https://jumpstartrails.com/

Ruby is a great language if you don't go hog wild with extreme OO ideas and metaprogramming. Unfortunately, in my experience, it's way more common to go hog wild than to just do things in a straight forward way.

Before y'all throw tomatoes at me, allow me to make things more confusing...

The problem with elegance is that it is mostly about being clever, but cleverness is often a tradeoff for being cryptic and hard to follow for those who don't have context or understanding. Because it is an abstraction, elegance in the form of things like metaprogramming and inheritance hierarchies make the underlying ideas more difficult to understand, not less.

Many programmers, including myself at one time, confused the idea of making something abstract as making said thing simpler, but more often than not it is the underlying details that are most important to be able to read and understand as a sequence of instructions and you are abstracting at the wrong level. Languages like Ruby are already so abstract that even just a level of abstraction above what it already provides can make code murky, resulting in lots of "thinginess" but not "this does this, and then this, in order to result in this".

I'm not singling out Ruby, BTW, but the topic of the article just happens to be especially vulnerable to the issues that caused me to lose interest in it and OOP in general.

I won't go into inheritance other than that I've realized that it's a terrible idea most of the time and that a growing number of programmers agree. Over the years things like Rails have added concepts that lean more into composition, but every single Rails project I've ever worked on was a mess of countless levels of inheritance that makes it difficult to know where behavior is coming from (which is ironic in a way).

This isn't necessarily a failure of Ruby but rather its community since countless other languages implement inheritance. There's something about Ruby that encourages overuse of inheritance and so many projects suffer from the pitfalls of it whether the developers are willing to admit it or not.

Speaking of the community, I really don't understand the amount of effort they go through to avoid documenting anything. I'm not talking about the language, frameworks, or libraries, since they generally provide great API documentation, but if you are reading Ruby code you are far less likely to find inline documentation or meaningful readme files than in other languages. Strangely, after having used the Ruby language for 8+ years, colleagues still discourage me from adding comments here or there to provide context around why something works the way it does. In contrast, it's rare that I'm ever told not to add inline documentation to JavaScript code by other JavaScript devs. It does happen, but I've really only had that experience one time in my career.

Ruby developers buy this line that "Ruby is so expressive that you don't need to write documentation, and the tests will describe anything else." That sounds wonderful but, frankly, I'm not a computer. I don't live and breathe code, and I'm not interested in modeling MRI in my head so I can interpret Ruby code. Even if I did, I doubt it could actually communicate contextual ideas in a meaningful way because that's not what computer languages are designed for, because computers don't understand anything. When you throw in metaprogramming and other dangerous ideas, the "documentation" you are writing effectively turns into a Choose Your Own Adventure book where every page has a 6 line paragraph that rarely finishes a full thought and makes you jump to random pages in the book.

I used to not trust the notion that Ruby is slow, and I still think that perspective is overstated, but not in the way a lot of people think. The vast majority of Ruby projects I've worked wer...

> Ruby has an awesome syntax, thus I wish there was a radical shift in Ruby, perhaps a fork, where the great parts of the language that make it especially readable and expressive could be kept while metaprogramming be made highly limited and inheritance impossible.

Uh, the features you want to be kept and those you want to be limited are the same features (or, at least, the latter are a key component of the former), so that’s not going to happen.

Metaprogramming and inheritance are (key to, not all of) the features that make Ruby especially readable and expressive.

It's all a matter of opinion, but I argue that those are not what make Ruby expressive.

What makes Ruby expressive to me is that it relies more heavily on English language than other languages that make heavy use of symbols and overly concise naming conventions. The symbols it does use (and I don't mean the Symbol class) get out of the way when you don't need them, meaning you can often get away not using curlies or parens, which may result in code that is easier for the human eye to parse (w/ syntax highlighting) and makes it simple to write DSL-like code and APIs without going down the full metaprogramming rabbit hole. Languages that are more C-derived don't have such affordances. Conveniences for creating ranges, calculating time, having array/enumerable operators, etc., are all highly beneficial. Ruby stands out in those ways without things like metaprogramming. It's the parts that get out of the way that are great, whilst metaprogramming can easily end up interfering with anyone who didn't write it. There are certain exceptions, but they are usually well tested libraries that get a lot of time and attention. The metaprogrammed DSL one guy wrote, who left the company before you showed up, can have flaws that take hours to flesh out.

I wonder, is Ruby with Rails still the best choice if you're starting out and want to build web applications? A few years ago the "new" stack was something like MEAN or MERN but Express doesn't seem to have the productivity of Ruby. If you had to start today, what would you pick and why?