Making software in Rails feels creative, and the act of writing code in itself is very satisfactory.
A good opportunity to re-read the Rails Doctrine: https://rubyonrails.org/doctrine
Now, I know that this is very subjective and I can see how others might prefer other languages or frameworks, so I'm not adding this here to start a discussion. Just to share my feelings :-)
The small/large project distinction makes sense to me. I think there’s a clear point in project size where the joy of writing code has to be deprioritized behind maintainability and simplicity, even if it becomes less fun to write code that way.
Even then - there's no real path to a mature and maintainable language/framework. In my area (Atlanta) we're seeing a glut of RoR devs available because a lot of the large employers have given up and shut down the RoRs projects in favor of anything more suitable to teams in the 15 to 500 engineer range. Usually this has been typescript/java/.net.
Even within the RoR guys I know - a LOT of them are trying to get out and work with something else (several folks I know are moving to elixir)
Dumb move, Elixir has around 1000 job openings in the U.S while Ruby has 35000. In fact I find it pretty hard to believe they can't get a Ruby job in the U.S, and they choose Elixir from all stacks as a solution to their problem. Sounds to me like they just wanna try Elixir and can't really build a good argument in their head on why they're doing it. Jobs-wise things are definitely not gonna be easier for them with Elixir.
Hopefully that is what Github and Shopify brings to the table. Instead of just using Rails they are now actively shaping its future direction.
>because a lot of the large employers have given up and shut down the RoRs projects
My impression is that the vast majority of Rails communities don't care much about its ecosystem growth. They are just happily using it.
My opinion, typed/tooled is useful when the desired solution/behavior/concept is complex.
It's still got most of what made Ruby a joy to work with and several unique advantages, too!
I completely disagree. Joy of writing code must always be a top priority, also in large codebases. There are enough examples of where Ruby (on Rails) is used in large codebases with GitHub, Shopify, etc.
I guess it's a matter of personal match, too. Some people match better with TypeScript, others better with Rails. Nothing wrong about that.
I'm aware that they use a heavily modified version of Rails, but it still is Rails in the fundament.
Without those imports, how will people reading the code find the definitions? How will they track down the source code for all the methods being called?
If the answer is "with an IDE / tools", then can't those same tools be used to solve the "mess of importing modules"? If you're using a good IDE, imports and go-to-definition are both solved problems, no matter what language you're using.
If you're not using an IDE, that's a more interesting situation, and without an IDE I much prefer having the explicit imports so that I at least know where to start digging.
[0]: A big disadvantage of the above is it's not statically resolvable, so you couldn't really build an IDE go-to-definition with it.
Solargraph is an amazing project but ctags is still just so fast and low overhead that it's what I mostly use.
ctag support is available for most editors and is built into Vim. You need to first generate a tag file (or have an editor plugin do it for you[3]) and then press Ctrl-] to go to definition.
With ruby 3.1 I think we’re getting a new default debug.rb gem.
It will be interesting to see if pry or the beat ideas from pry can be integrated with that.
THIS. 100%!
I also think Python seems to do this better with the namespace pattern of `import x.y.z`. Never seen the `import *` pattern before, didn't know Python can do that (never done Python really though either, only browsed some code here or there).
But one addition to your statement I'd like to add: not just idioms, but documentation can spread this antipattern too.
Noobs come to a language, read the documentation for some tool, library, etc., and understandably come away thinking "Oh ok, this is how it's done" when in reality, while they're not doing anything wrong per se, they're being taught a bad habit right off the bat. And that makes the inevitable hard slap across the face that reality (or a co-worker) eventually hits you with all the more shocking, possibly even leading to resentment of others when this happens.
I myself had this problem many years ago; "why the hell do you need all these subclasses and so many layers of abstraction?!" I once asked. "Because those class/method names already exist within other classes loaded at runtime, or will likely be added in future external dependencies, and we don't want to accidentally overwrite those."
Well, I thought that was a stupid idea. In my (very limited at the time) experience, when I had that problem, I just insisted on finding a damn good descriptive name that wasn't going to be used for anything else, even if it was wicked long or a pain to type. Too long? Don't be lazy. Typos more probable with length? Learn to copy/paste. That was the approach I learned at some point from some documentation somewhere on the internet, and it always worked for me, so it was the "one true path" and all others were inferior, making proponents or users/adherents of any other way "wrong" and inferior to me and my superior, non-lazy intellect. You're telling me that you do it differently? You must be stupid or lazy, and I'm neither therefore I'm better than you; thus forcing me to adopt your inferior standard?! Preposterous! Insulting! Offensive! That's how I saw it.
God, was I dumbass.
I developed this attitude by learning my skills in a near total vacuum, other than documentation written by people on the internet back in the 90's. Not official company-published technical docs, mind you, but forum and BBS posts, mailing list discussions, and way too much IRC to be considered "healthy" by any stretch of the imagination.
Those who taught me did so in a way that was efficient and they did no wrong at all of course - this failure was entirely of my own making, from my own arrogance. But it's also true that had I been taught at the same time that "there are other ways in other languages that are totally valid; this is just for simplicity's sake" and then been shown, or better yet required to use other patterns in school/projects/etc., I might have been able to see the short-sightedness of my own arrogance sooner. Instead, it resulted in an antipattern that allowed me to become overconfident, arrogant, and more difficult to work with than I should've been.
----------
In case you're wondering, I can't remember what I read or where that came from so long ago. Sorry. Might have been C, C++, Java, DOS BASIC (non-GUI/non-Windows), Visual Basic (before .NET) or maybe even PHP 3.something, no idea - that was 20+ years ago. I was inexperienced, arrogant, and a fool; none of that was the author's fault whatsoever. We're all young and stupid at some point in life. I'm no longer young, but at least now I know I'm stupid! :-)
Short of that, assuming all your dependencies are unpacked under your project's directory (likely .gitignore'd but there nonetheless, instead of in somewhere like /opt/ or /usr/local/lib or something) you could also `grep -ir 'def method_name' | less` or something to try to figure that out, though it's nowhere near as smooth as RubyMine.
Other editors have Ruby and/or Rails plugins that may help ease this pain point as well, though personally I haven't done anything with that on the editor front in a very, very long time. Generally I'm outright militant about keeping my dependencies to an absolute minimum in a project, and doing everything the most "vanilla" (standard, accepted, most widely adopted patterns, naming conventions, etc.) way possible, and therefore I usually know what gem/lib is providing what particular method, so I don't really need that kind of utility most of the time because I can google up some API docs...when there are API docs anyway.
But in cases where you're having a legacy project/monolith dropped in your lap and nobody knows anything because "the business guy" fired the one developer who actually knew how everything worked and now that guy won't answer his calls because working for free is dumb? Yeah, in those cases, RubyMine or a real good editor plugin can be a lifesaver for this.
People trying to write Java-like OO in Ruby end up confused and frustrated.
object.method(:name).source
object.method(:name).source_location
but frankly this is still thinking in a rigid mindset that suits other languages better. Ruby isn't just "dynamic dispatch"; a typical metaprogramming technique handles all incoming calls without named methods, or by dynamically writing the code.To put it bluntly, assuming there's a method on the other side of your message, is practically the antithesis of Ruby.
It's similar to the category error that leads folks to conflating type with class, and writing type checkers that look for class signatures.
Or if you mean, dynamically instantiated methods, those are found throughout Ruby and its ecosystem, and the reason it isn’t horrifying is that the language has terrific support at the REPL for developers needing reflection.
Well, since I have been privileged to work with several really great Ruby teams over the last couple of decades, whose large and well-structured code uses metaprogramming techniques yet remains easy to follow & comprehend (and debug and extend), and who remain splendidly productive to boot, I can say, if this bunch of guesses at the intended meaning of that "soap bubble" metaphor hold water, then yeah, I disagree.
Conversely, shitty code can be (and is) written in explicit import and early-bound languages. The enterprise world, for example, is riddled with massive hairballs of brittle, unmaintainable, boilerplate-heavy Java.
All of which only goes to show that people, not the programming language, are the problem.
Though having suffered in a Rails codebase written by Java engineers, I definitely agree that a light touch is needed with OO -- though composition has its own difficulties and together this forms one of my bigger criticisms of Rails.
RubyMine, and the "jump to definition" feature in particular, is the primary thing that enabled me to really "get" Ruby and finally understand how everything worked together.
If someone asks for directions you give them directions or a current map.
I understand using to find out why it's there, but not what it is.
Indeed, and the problem is that IDEs have encouraged developers to write convoluted code and to forget how to navigate a filesystem. Reading code and commit history is a much faster path to understanding a system than an IDE's autocomplete. I learned this from Ruby, and it serves me well in C, Kotlin, Scala, PL/SQL, Typescript, etc.
I would argue the exact opposite. Developers who force tools designed 30 years ago to dictate programming language best practices today are holding back the entire industry. There is no reason for my tooling to depend on my filesystem; imagine if my IDE integrated directly with vcs, and a language server provided both of those tools semantic information about my code, available on any device. Let's not kid ourselves either, utf-8 isn't human readable on disk, it's still a binary-like format.
Input and output parameters on a program with hundreds of thousands of lines becomes .. rough, to say the least. DryStruct has helped a lot; but several teams working on a single codebase with their own opinions of method calling patterns evolved over several generations all in a single codebase, and it’s … rough.
I think for people that come to love Ruby it feels more natural to think about a program that way as opposed to thinking about a purely lexical context of a piece of code.
That's also why I don't think it's a great idea to add types etc. to programming languages like python or ruby. They are not made for this and they should focus on what they do well. Use the right tool for the job, don't try to make every tool being able to be used for the same task.
In fact, the philosophy of convention over configuration et all makes Rails MORE scalable and easier to onboard new people than anything else out there that I’ve seen.
I recently worked on a Rails project for someone who didn't like to create scaffolds, models or controllers for small things, thinking that it would add to the bloat. But conceptually it makes everything 10x times easier and faster to find and understand
There are soooo many blogs about migrating away from Ruby, adopting Go, Scala, whatever statically typed thing.
There's a reason even Ruby is getting a proper static type system.
Its productivity is simply hard to beat.
Most of these companies are unicorns or public. https://spreecommerce.org/ruby-on-rails-most-popular-among-t...
I doubt they can be listed as a Rails success story.
Stripe doesn't use Rails either. That was a pretty bad article. And it is somehow from Spree.
Almost all the major former startups that I could find are from 2010 or earlier.
I've found that people that gravitate towards Ruby enjoy meta-programming. The running joke is that you're not a Ruby programmer until you've decided that you should write a DSL. Like everything, clever programming has its tradeoffs.
These days no one reads the source code of every method they call until something is not working the way they expected it to.
Personally, I find the JS ecosystem that absolute worst for this because of the amount of imported code to layer basic functionality on top of the standard library.
If you've worked with rails long enough - well at that point things like Devise are probably in your mental model of how they work.
Personally I still find the large unbridgeable chasm between Python 2 and 3 to be a large friction point in the ecosystem. But if I worked in Python a smuch as I worked in Ruby, I may find Ruby more troublesome.
The simple fact is all languages are getting better. The best tool is not always the one that would be best for the job, sometimes it's just the one you know best. And the tradeoffs we make for ease of programming and abstraction can then turn around and mean we are pushing megabytes of JS over the wire when we don't need to, and now we are trying to solve that with more explicit inclusion and automatic tree-shaking in build pipelines etc.
It's all good. Every tool has two edges. I'm much happier to see people continue to engage with this edges are figure out how to make them more effective than to always argue about which edge is sharper.
Memorization is not consistent between teams/team-members.
Memorization is also the fastest skillset folks lose if they step away from the language/toolset for a while (it degrades rapidly)
Worst of all - The RoR ecosystem (6 versions in) requires memorization about which set of things you need to have memorized for this specific version of the framework.
I'll take some boilerplate code EVERY FUCKING TIME. The magic becomes a curse.
I think in dynamic languages like Ruby and Python, there are two very different cases that we need to distinguish when thinking about this.
The first one is global references to modules/classes/functions. For example, in Python you may write:
import my_module
foo = my_module.Foo(some_arg)
So, if you wanted to find the definition of that my_module.Foo() reference, it's easy: go to the definition of my_module and search for the Foo class/function definition.In Ruby, you may see instead something like:
require 'my_module'
foo = MyModule::Foo.new(some_arg)
Which looks very similar to Python, with the difference that the `require` method doesn't assign any local binding, but just executes the file my_module, which in turn will modify the global namespace directly and make `MyModule` available at runtime. The `require 'my_module'` might not even be present on the file that's then using `MyModule`: it might be indirectly required by another module that this file uses. Or, in the case of using Rails or any framework with auto-imports, the file might not have any `require` calls at all!So, how is this resolved?
By convention, basically. If you see a reference like `MyModule::Foo` and want to see the definition of that, the convention is that that definition will live under my_module/foo.rb, so you can go to that file with some confidence that you'll find the the code for that class there.
So, if the convention is strong, and people follow it, this is basically a non-issue, and the go-to-definition can be done as easily as in Python, with or without an intelligent IDE.
---
The second case is when you have a dynamic reference to an object/function/whatever, like:
def do_something(arg):
arg.foobar()
In this case, neither Ruby nor Python (or any dynamic language in general) will help you much in trying to find the definition of the `foobar` method, as the type of the argument will only be known at runtime at the moment that this function will be called, and can even vary between calls.There are different ways to make this go-to-definition somewhat more ergonomic than a global search for `def foobar`. But on the language level, i think both Python and Ruby are basically the same in this case: not very helpful. We then compensate by using good naming conventions, type annotations/comments, or using powerful IDEs that analyze the code to make good guesses about who is calling what.
I totally see the value and understand why someone would like it but I just never could get to that point with it.
I much prefer the explicit imports, loops, etc I suppose
For example, I really don’t like that rails implicitly imports stuff into the namespace.
I like being able to follow the imports explicitly at the top of the file. I feel like there is way less of “where does this come from or what IS this?” when working with Django.
What function did I import, exactly? Which of the 37 “update” calls did I call when I called it on this?
You might like some of the recent Rails 7 previews. I believe they’re removing Webpack out of the box and trying to simplify things on that end[0].
[0] https://weblog.rubyonrails.org/2021/9/15/Rails-7-0-alpha-1-r...
The Achilles Heel of Hotwire apps has previously been the low number of supported websocket connections and high memory usage when using ActionCable and Puma but I have high hopes that Falcon[1] will take care of that.
That along with Github's View Components[2] and Tailwind make me really please with the way Rails is heading right now.
i'm personally not a fan of tailwind (or bootstrap) for being overly/cryptically verbose, but i understand why it's popular when coupled with view components, which do seem useful.
The nodejs API is rather big really. If you're using Ruby as your standard of normal sized almost everything would look small in comparison, but "anemic" is a stretch. You'd really hate Lua.
If you're taking suggestions, you might enjoy Janet[1]. It has a pretty large user API, lots of bells and whistles included in the standard libs like you'd find in Ruby, and lots of different ways to achieve the same result like Ruby. It's been a while since I checked out the ecosystem, but I was _very_ happy with the Joy Framework[2]. It definitely doesn't come close to the scope of Rails, but I think it _does_ near Rails in it's easy of use for the developer with it's scaffolding, controller generation etc.
Just curious about why you'd suggest going from a popular stack to Janet? I'd rather suggest Common Lisp as it's a way more stable, mature and standardized technology.
But now that Rails has incorporated Stimulus as a sane approach to the client-side of things, I'm coming back and it will be difficult to take me away again.
Not sure what you mean here specifically (do you not understand Enumerable.inject in the Ruby stdlib? That's about the hardest thing to understand and once you're there, functional langs are pretty trivial) I was already coding in a functional style in Ruby (PORO, intentionally not mutating vars, etc.), so that wasn't an issue for me at least, when I hopped to Elixir.
The kicker was when I spent an entire month debugging a problem that would have been impossible to occur in Elixir/Phoenix- I was working on a million-line Rails codebase and there was a session issue where sessions would seemingly randomly get dropped... it was nondeterministic and absolutely maddening, a number of other devs had attempted to fix it and failed, and I finally did- and it ended up being a key-overwrite issue with a regular Hash being merged with a HashWithIndifferentAccess in the ENV variable passed between rack layers (and god, was that hard to find! I had to write custom debugging tools that walked through every Rack layer and deep-diffed the ENV hash, etc.). That was the last straw.
So far, Elixir/Phoenix has been fantastic for me at NOT producing "flagging tests", nondeterministic-seeming bugs, etc. Massive productivity boost.
Also, please keep tedious programming language flamewar like this and https://news.ycombinator.com/item?id=29288298 off HN. We're trying for something more interesting here.
https://news.ycombinator.com/newsguidelines.html
Edit: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&qu... is totally unacceptable, and we ban accounts that carry on like that. I don't want to ban you, so please don't post like this again. In fact, please just stop posting about this topic and stick to things that genuinely gratify your intellectual curiosity. Conducting a putdown campaign against what other people like is an abuse of this site.
that's basically what you just did. "Electric cars will pollute someday! Just you wait!" >..<
Keep in mind that I've worked on small Ruby projects as well, and still prefer Elixir.
I'm not gonna suggest that there wouldn't be challenges in that scenario, but it just seems to me so far that they'd be much more manageable given the thoughtful design of Elixir.
The biggest problem in my app currently is actually JS/Node dependency hell, not Elixir code... and the JS only makes up a small portion of my app! (I should have never used AdminLTE as a design template...) At least my JS is tested (which was another huge PITA to figure out... simulating a DOM...)
It's been years of this nonsense. Let it go.
Have you tried Phoenix? It's really close. It's better in some ways. The data layer is quite different however. As much as I like Ruby, Elixir made a lot of things I liked about Ruby better
It's such a better platform than Ruby and Rails that I won't bother writing about it here - there are already hundreds of blog posts about it. Productivity is at least on par with Ruby (I believe better) and performance on another plane of existence.
It's not just jobs, by any metric you can think of Elixir is an obscure tech, if you want I will add sources to this claim but hopefully we can agree.
- https://appunite.com/blog/top-10-elixir-companies-to-follow
If all that's true, it's a natural consequence that better tools will have fewer job postings: you need fewer people to get the job done, and the ones you've got have really good retention. However, so will tools on the other side of the bell curve: nobody in their right mind wants to go there, either on the supply or demand side. So all popularity really tells you is where the enterprise hype machine was, five, ten, fifteen years ago such that "nobody got fired for choosing X" and "learn X! It's got a lot of job postings!" still align.
But the enterprise hype machine is optimised for tools that have a very specific set of surface criteria: enormous libraries so you're not inventing anything, rock-solid vendor support so there are people being paid to evangelise it into orgs (or, like JS, are ubiquitous anyway, but I think that particular lightning only strikes once), and "easy to learn" ergonomics such that developers asymptote towards replaceable cogs in both quality and quantity.
"Well respected but obscure" describes a certain sort of success, by that reasoning. It just needs enough of a community to stay alive, and that's a bit more of a toss-up. Ruby haemorrhaged people in the Rails 4-5-6 cycle as people jumped ship to node, but Rails 7 and Ruby 3 are looking extremely tasty despite that, and I wouldn't be surprised if we saw a bit of a resurgence in popularity over the next couple of years outside big enterprises.
Most of the people I interview have got into tech after Rails 3 was released, and generally aren't aware of why the Rails/Phoenix/Django concept was such a breath of fresh air. I think what you'll see is that the reason Phoenix and Elixir have a "next big thing" isn't technical factors at all. It'll be a rediscovery by the new generation when someone unexpected goes unicorn and the story is "it was all down to Phoenix", even when the real factors were elsewhere.
> there's little jobs that's all
wasn't an issue for me. I applied for five elixir jobs in a limited sector (fintech) and got an offer.
You probably haven't heard of klarna, or discord, either.
About Discord see my other comment - I don't think Elixir is their main language.
> From day one, Discord has used Elixir as the backbone of its chat infrastructure.
https://builtin.com/software-engineering-perspectives/what-i...
> Another is a re-architecture of our guilds service, which as our biggest communities have grown, started struggling to handle 100,000 connected sessions per Elixir process. We horizontally scaled the Elixir processes so that we can scale as the number of connected sessions increases... Many of our stateful services that maintain connections to clients, and process and distribute messages in real-time, are written in Elixir, which is well suited to the real-time message passing workload. But in recent years we have run up against some scaling limitations. Discord has written and open-sourced several libraries that ease some pains we’ve encountered with managing a large, distributed Elixir system with hundreds of servers
maybe come out from under that ruby rock and smell the dev air now and then
Also, I was on Ruby since the time when it was "trying to be the next Java" (this was prior to 1.0!). All good things start out small.
Anyway, after the initial learning curve, much happier working in Elixir/Phoenix than I ever was in Ruby/Rails... especially from a code-writing AND code-maintenance standpoint. Immutable-everything is the way forward (which also massively aids concurrency). It also being 10x faster and far better/easier at working in a concurrent context are also perks.
2. The amount of users Discord has has nothing much to do with anything. Facebook has 2 billion users and its programming language is Hack. So Hack isn't obscure? How many people know and use Hack besides a few thousand Facebook employees? If Facebook gets 2 more billion users in the next decade will Hack become 2x as popular?
> The amount of users Discord has has nothing much to do with anything
The argument I was arguing against was that Elixir is niche, not argumentum ad populum. It's no longer really niche, just elite. ;)
It's funny, the fact that Ruby doesn't have a facility to import modules is one of my biggest gripes with it. Instead of importing into a specific scope, the global namespace becomes a dumping ground for anything that has ever been loaded, and you need something like Zeitwerk to do auto-loading for you. Which I guess can be seen as a convenience initially, but it makes things harder to manage as your app grows in complexity.
It would have been nice to be able to do something like: `MyActiveRecordImport = require('activerecord')` to take control of the constant name, but honestly it's not something I hugely miss.
While Elixir has more than enough uses and I love it dearly, nothing comes close to the productivity and expressiveness of Ruby (+ Rails).
I have very high hopes for JS/TS. Using a single isomorphic language for web development must have some benefits, but I'm afraid it's not there yet.
This is a question about standard-library. The standard-library of kotlin is equally amazing (but Kotlin more or less requires the IntelliJ eco-system of course).
It is 2021, web frameworks are ... one of the solved problems. Polyglot is the future, and people are already adapting
Yes, right. I like how you can read into the future. Let's see what happens 10-20 years from now, things tend to change. But even if we look at how things are now, plenty of places still commit to 1-2 languages (in fact if you're a small shop it's pretty crazy to try anything else).
That might be true, but it didn't mean they will commit to ONE language for forever. Even governmental agency's code gets rewritten in newer languages eventually:
https://aws.amazon.com/blogs/apn/automated-refactoring-of-a-...
Since I’ve run Linux servers at every job I’ve had, I’m trying to get my toe into devops at my current employer. Getting all of our application into Docker has been fun. (Why does everyone run shit as root in a container!? Dropping permissions isn’t difficult!!!)
I’ve bounced around over the years and I’m doing a lot of Python now. It’s funny You said that about “loops” because I do feel like I’m always looping something in Python ha
It's not as nice as rails, but we love kotlin so it's hard to give up.
Totally agree, 100%. Ruby isn't "perfect", but it's a pleasure to use. As in, I actually want to use it, not just am "ok" or ambivalent about it. I have my nitpicks about Ruby, about Rails and other things just like anyone, but I second your comment that nothing else has been able to match that sweet spot of great productivity that is a direct result of a fantastic developer experience created through a programming language that just "flows" linguistically so much easier than...well, everything else I've personally ever seen (with Python being an arguable tie there).
My biggest gripes about Ruby and its ecosystem have been the pain in the posterior it is to deploy apps (all those gems, which eventually wind up abandonware and now you've got dependency hell, especially with apps not maintained in 5 years or something) and its relative sluggishness when compared against some other deployable artifacts.
Personally, I think Crystal (https://crystal-lang.org/) fixes pretty much all of this, as long as you're willing to cede a few things due to the nature of the beast (compiled vs. interpreted).
And that's not considering the speed improvements Ruby's gained in the last few years (3x3); it's undoubtedly far better now than when I last released an app with Ruby or Rails (circa ~2016, maybe ~2017ish). I'm just so disappointed that everything's "JavaScript this" or "Go(lang) that". Not that I have a problem with Go (I do have many problems with JavaScript, which I strongly dislike, but that's a separate topic), it's just that this industry acts like lemmings in a lot of cases. "New shiny!" attracts the horde, and that critical mass creates a new tyranny of being the "snowflake" technology/stack/developer, which has a lot of risks for both the organization paying for what you build in tech stack $X (rare language, can I replace this hire later, can I find somebody that knows $X, lower risk if we use $Y b/c we can find plentiful/cheap talent in $Y or $Y salaries are lower than $X), and by that token therefore it's a risk to the developer's career to get hard core on anything perceived as "snowflake" or otherwise not "flavor of the $(month || year || interval)".
Which is just so sad, and I feel like it's a contributing factor in Ruby's decline (in terms of hiring demand for full time positions). It's not at all the technology's fault, and it's not a performance "issue" whatsoever anymore (really wasn't in the first place unless you were nickel and diming literally everything or did stuff just plain stupid).
Go, Rust and friends all have their own benefits and drawbacks too, and they're fine languages with their own killer features and/or quirks. They can produce pre-compiled code for a variety of platforms from a single machine, resulting in (if desired) a single file binary deployable artifact that can be installed and simply run, no dependencies to install, no OS configuration necessary. Ruby, without lots of hacks potentially questionable hacks and potential future abandonware, doesn't do that at all AFAIK, but Crystal can also produce fat binaries just like Go can (and I assume Rust can too), making it the best of both worlds in my opinion.
Crystal: compile Ruby-like code to a "fat" binary for single file, zero-config/dependency deployment that runs true multithreaded apps as native code. And most of those tradeoffs you'd have to give up because "compiled" - most of those you can work around pretty easily and I've heard you can even have it embed source code in the binary to be run in interpreted mode at runtime, so you can have your app compiled for the vast majority of use cases, then have it run its own code inside itself interpreted/JIT'd when run, giving you access to many (all?) of the features you'd otherwise think you'd have to sacrifice.
So yeah, I love Ruby, and I think Crystal is definitely the next evolutionary step for that language and ecosystem. No hate on Ruby there whatsoever, I just see it as a more mature option for a lot of use cases, but definitely not all. I don't know if you can do that metaprogramming magic Ruby is so amazing at any faster in Crystal since you'd have to run the code as interpreted at runtime, not pre-compiled (AFAIK), so it's not an outright replacement. Still, I think it's damn near one, and you can probably "color outside the lines" just a tiny bit as needed when you absolutely MUST have that feature anyway.
Okay, end stream-of-consciousness. I haven't been able to sleep for 3 days, so rambling is a sort of unavoidable side effect...sorry about that. But yeah, try Crystal if you haven't already, you'll likely be very happily shocked at how amazing it is!
I think the actual reason why it's not more popular is something I personally call "The Tyranny of the Masses". In short, what's popular/flavor-of-the-month is automatically "right", and everything else is automatically "wrong" or "high risk" in our industry. These are of course not real demonstrable facts, but people's perceptions that influence choice of technology stack.
Take JavaScript/Node.js for server-side apps for example. MASSIVE ecosystem. Near total ubiquitous skill availability in the developer market (with one major caveat I'll explain below). Not perceived as a rare or difficult skill to pick up, so salaries can be on the lower side than, say, a C developer with Linux kernel experience, for example. To employers and managers, this is a much more attractive mix than something where all of the above are in any way seen as "less true".
Compare that to Elixir. Not around nearly as long as JS, far fewer learning resources, relies on perceived turbo-nerd/esoteric "Erlang" runtime, so support availability may be harder to find and more expensive (so what's that mean for the employer's support and availability contracts, uptime agreements, and/or regulatory environment should something go sideways?). Not nearly as many available published libraries as on NPM (yes I'm sure Elixir's are far higher quality, but remember: it's perception, not fact, at play here). Skilled hires in market not nearly as common or ubiquitous as JavaScript devs are. Nobody has 20 years of Elixir experience. 20+ JavaScript experience does exist though (again, perception matters, not the fact that JS 20 years ago was laughably bad and would almost never even run today!).
Then there's the "safety" factor for production apps. JavaScript? Billions of apps all over the place. Nearly ever prod scenario imaginable has happened and 90% of them have at least been blogged about. Async/await in single threaded runtime using multiple processes for concurrency? Yep, somebody's done it. True multi-threaded single-process concurrency? Yep. Big, perceived as financially stable tech company behind it? Yep. Large market/ecosystem of firms that provide high quality support at reasonable prices to compete for business? Yep. Elixir? Arguably none of that, and definitely not to the quantity - again, not quality, quick-glance perception, optics here is all people look at - that JavaScript has behind it.
Is Elixir a better language, runtime, and ecosystem than JavaScript/Node.js? Almost certainly, and you can probably prove that pretty objectively with only some very obscure/esoteric exceptions having merit. I mean, dude, it's JavaScript, that's a low fucking bar! (Yes I'm a JS hater, go ahead, flame away! "YOUR BOOS MEAN NOTHING TO ME, I'VE SEEN WHAT MAKES YOU CHEER!" - Rick Sanchez)
But is it popular? Not compared to JS! JS is like that air-headed valley girl high school cheerleader that every guy wants to sleep with, and Elixir is that nerdy girl with a good heart, a great head on her shoulders, who can respect people and while she covers nearly every inch of her skin with clothing, leaving everything to the imagination, even a blurred photo would tell you that underneath all that, hot damn! She's the total package. But you want the cheerleader because of the popularity contest. You'll be the big man on campus if you get with her! Well, maybe not "the", more like "a", one in an ever-growing series.
Fast forward to 5-10 years post HS graduation. Cheerleader? Trailer trash with 6 kids on food stamps and zero drive in life whatsoever. Nerd girl? CEO of her own startup, and somehow even hotter now than she was back then!
Oh how foolish we are for falling into the trap of popularity. And while some may feel justified in their subservience to that popularity because reasons, some of them even good, we'll all feel curse the lack of choice, the absence of competition, the void of creativity and innovation - that we inevitably acquiesce to the clamors of the mob. Our future's bright hope will be made dim indeed when we succumb to the Tyranny of the Masses.
EDIT: The caveat on JS skills I mentioned above? Almost everybody who says they "know" JS is really at best an intermediate-level developer with it. It has a lot of special use cases, variations in how things work depending on engine, execution context (server app? browser engine?), and even today in 2021 we still see even self-described "experts" telling you to use alert() to get debug data instead of at the very least console.log/warn/error, etc. The language has made some frankly just plain weird (IMO flat out bad) design choices, like allowing more arguments to a method than its signature declares, and used to be so vastly snowflaked (nearly zero consistency between browsers) that you absolutely had to write an ENTIRE new JS app for each browser you wanted to target. Granted, that was the Netscape Navigator days, when Internet Explorer (Exploder?) was version 5, the rightly-maligned version 6 didn't exist yet, Firefox was a twinkle in somebody's eye, and Microsoft even shipped IE for the Mac (like OS X 10.1 or 10.2! Remember Aqua, the striped textures? Ahh, the good 'ol days...) It's come a long way since, but it still fundamentally suffers from having more bad documentation than good, and while most consider it a "lowest common denominator", that's unfair to people who really are true experts in the language, who will tell you that when you get real deep with Node or V8, you can see some gnarly shit. It's a god-awful security nightmare; why the hell would I let whatever website in the world run whatever code they want directly on my machine all willy-nilly, automatically accepting every API call by default, denying almost nothing, with unrestricted access to some pretty advanced/low-level APIs that can do some serious damage if abused? And people say Flash was bad (well, they did only after Steve Jobs made a big deal about it; he wasn't wrong, but virtually NO ONE hating on Flash back then had any idea how it even worked before Steve bitch slapped it into oblivion and rightly so). Its syntax is arguably archaic (we don't need semicolons to end statements/lines these days, language parsers are much more capable now; look at Python, Ruby!), it's littered with inconsistencies in the language itself, and since everybody's a hammer (JS "expert"), everything looks like a nail (a suitable use for Node/JS/DOM/Script), even when it's damn well obvious, painfully so, that it's absolutely NOT. All this, and yet everybody's somehow an "expert" with JavaScript. Really? Really?
I approach programming creatively. I think in large systems and architecture. Ruby allows me to skip worrying about the details. Code blocks abstract away thinking about loops and just focus on data. Just about every array operation I could want is there, waiting for a code block. In other languages, things don’t flow like that.
I’ve tried purely function languages and I just can’t wrap my head around them because they abstract too much.
I’ve tried python, but I end up having to deal with the mess of importing modules and having to set up loops when all I want to do is map data.
Node.js comes so close but anemic standard library and absolute mess of explicit async everywhere just gets in the way. I want to love JavaScript. :(
Then there is Rails. Nothing even comes close. The attempts to replicate it in other languages ends up missing part of what makes it so great. I’m sad about the move to mounds of JavaScript. Nothing can match the productivity of simple_form and bootstrap.
My entire career has been in Ruby on Rails. I hope improvements to Ruby can keep it relevant. If not, I suppose JavaScript will do.