Is it the most maintainable code? No. Is it the easiest to understand? It depends tbh. Rails provides so much out-of-the-box stuff that lots of rails apps end up looking sufficiently similar, especially if they're small-to-medium-sized. But yes you can end up writing some dreadful spaghetti without a bit of discipline, but imo that's true of python and (node) js as well.
But damn is it SO fast to get up and going. And given product-market fit is why most projects and products fail, it's hard to argue against using Rails for me, since if I'm even still here to complain about it later, that's already a win.
I know this feeling!
If one using Rails accepts this and tries not to fight it, then the metaprogramming of Rails provides a lot of goodies.
I prefer convention over configuration because once learned it just works. For me in Rails when I look at an URL, I kinda know what is the file that handles that (the controller). And that is what I appreciate.
Of course, different needs require different solutions. I also worked with Sinatra which does not have this. But I choose it exactly because it is light and it allows me to group my logic in a different way.
On the other hand, that deep magic metaprogramming can be really hard to follow if you need to understand how it works. Tracing back through (or even debugging) a metaprogramming-heavy codebase is a nightmare.
I'd argue that deep magic metaprogramming is great for when you have abstractions you almost never need to dig into. Rails is great because it's relatively rare that I need to go spelunking in the rails codebase itself (and thus understand the deep magic). Instead, I can rely on a huge pile of documentation, stack overflow answers, conference talks, etc to figure out how to use rails' abstractions (like `has_one :posts`) without needing to understand their implementation.
On the other hand, the average production codebase should minimize their use of metaprogramming. When I don't understand how Joe's `Whatsit` interface works, I'm much more likely to need to dig into Joe's code to understand how to use that abstraction. If I have to understand Joe's deep magic every time I do that, it's a net loss.
Agree with everything you said
(disclaimer: I do rails all day)
I have never looked back.
Jard is a tool that is simply done/complete/ready.
JavaScript as a developer culture seems to have convinced a lot of folks that if a package isn't updated at least a few times a year, it's "dead".
RubyJard looks cool, but the repo is marked as "Archived" and the last commit predates Ruby 3. And, in fact, it looks like there are issues with Ruby 3.2 and RubyJard.
Most software cannot really ever be "done", if only because no software operates in a vacuum. Nearly all software relies on a language, a standard library, an OS, direct dependencies, indirect dependencies, etc. The only way your software can be "done" is if it relies on absolutely nothing, and very little useful software does that.
Well, that sucks. Still, I urge people to clone a copy, update the pry dependency and give it a try because I've never run into any issues and it's at the center of my debug game. I'd be devastated to lose it.
This lack of easy debugging capabilities has cultivated a whole group of developers whose primary way of debugging is 'let me out in a print statement'.
One thing I've noticed, and this is something that seems to bother non-Ruby engineers, is the people that flourish in a complex Ruby application prefer to read code over documentation.
You hit the nail on the head.
Metaprogramming is just one of the things that make Ruby a joy to use. It's not really a reason unto itself.
Which is still plenty fast for CRUD web applications even at large scales, don’t get me wrong, I’m just pointing out that JS for example often has a 10x multiplier between it and Ruby/Python.
Python is the de facto glue language.
You going "fast" now means that others (including the future you) will go "slow" later.
I've also worked on Java, Go, Elixir, and Haskell codebases.
I find that anytime we went "Slow" was because of decisions that were made around the data model, which can happen in any framework or language.
The thing that I love about working in Ruby is Rubyists tend to write fantastic tests (which double as documentation of what ever business logic), and the culture around "convention over configuration."
So even when we decided to port one of those Rails apps to Elixir/Phoenix, it wasn't an absolutely awful rewrite.
It's fine for those 2-3 cases, and should be banned everywhere else. In rails is highly abused. What rails achieved and it's good at can be achieved with less metaprogramming, but of course nobody is going to build another rails, since rails is already there.
I don't like it in python, I don't like it in Java.
But e.g. in Rails, sure I bump my head sometimes, but overall I like how magical Rails feels because it lets me go so fast.
Maybe it's because Ruby alone is willing to sacrifice so much speed (though not THAT much vs python tbh) and is willing to go all-in on it, that they enable magic to be so deeply magical that it can deliver adequate value to compensate for being more inscrutable?
Whereas other languages' metaprogramming systems keep you a little more leashed.