Can you explain in your own words for elixir where the balance between "joy" (productivity, flow, whatever you want to call it) and what you call "rethinking the way you write code". As another example of a functional oriented language that prides itself in the same thing look at Haskell. I wouldn't say most people think that Haskell is an easy or productive language (that is until after you have years of experience under your belt), but it definitely forces you to rethink how you code. Scala is another example, but draws the line at a different place. How is where elixir draws the line preferable in your opinion?
So as someone who worked in Erlang (and is familiar with Elixir), I can answer that a little bit.
They hit a sweet spot. Enough rigor, enough limitation, at the language level, to force you to do things "the right way" for a broad swath of problems (there are certain problems they're poorly suited for), but enough simplicity and freedom to keep a minimal learning curve, and minimal runtime complexity to figure out issues.
The focus on fault tolerance also means once you learn to use the app structure, with supervisors, you mostly have just one concern for reliability ("how do I start this into a known, good, consistent state?"), rather than hundreds ("what happens if -this- fails? Or that? Or that other thing?").
Haskell and Scala both have a huge surface area to learn before you're productive, let alone anything approaching fault tolerant, and even after years of use, there's still a lot of hidden gotchas with them. I've seen teams take Erlang, and their very first project just...worked. None of their lessons learned caused production issues, and no weirdness; the three issues that made it to prod I can even think of were, variously, one that wasn't user facing (just a log entry indicating something wasn't handled right; supervisor took care of it), one where performance started to slow (and it was due to having written an O(N^2) algorithm accidentally, and not testing at higher loads than production), and one where a low level C driver made an unnecessary reverse DNS lookup that, when the caches flushed, caused things to hang, which became an issue when load increased, and which should have been circuit broken (but which instead caused a failover to another node).
I've never had that experience with another language. The ramp up time to productivity was longer, the production issues caused by us missing something about the language were more frequent, the production issues caused by us failing to expect or handle a failure condition were more frequent, etc.
That said, Elixir and Phoenix do raise the bar a little. Elixir has a larger surface than Erlang (only a few concepts, but a lot of ramifications when it comes to macros if you haven't used them in other languages), and Phoenix is reliant on a fair bit of magic so you need to read the docs and it may take a little bit of work to feel happy with things. But even when I knew nothing about it, picking it was easy because of the experience I had with Erlang.
> with supervisors, you mostly have just one concern for reliability ("how do I start this into a known, good, consistent state?"), rather than hundreds ("what happens if -this- fails? Or that? Or that other thing?")
Thank you for this comment. I have used Elixir for a couple of years and is a concept I have always understood but have never been able to explain coherently and succinctly.
Ok, I've heard of Haskell and I've been to many Haskell meetups too. This was before I found Elixir. For me, the biggest problem with Haskell is that it will turn cryptic if you don't touch the codebase for say, 6 months. Because, you need to essentially re-learn the special syntax of the language if you're touching Haskell code after 6 months.
In contrast, Elixir is super simple. I can describe the language in a single HN comment. Everything is just a function and they're inside modules. That's pretty much it. When I was picking up Elixir, I started off writing an E-Commerce platform from scratch with Elixir. When I was about to finish it, I was thrown into a 8 month long PHP project. When I was finally done with it and returned back to work on my E-Commerce project, I was able to just open up the code in a text editor and immediately understand what was happening - without having to re-learn the language. That is a the "Joy" part for me.
One more "Joy" of writing in Elixir is you don't need to worry about memory usage or performance that much. It's pretty efficient unlike Ruby or PHP even. So, I can just throw this entire application in a $5 Digital Ocean droplet and watch it handle insane amounts of traffic. And this is without optimizing anything. You will probably able to squeeze more with caching, optimizations, etc.
As for re-thinking the way you write code, it's mostly to do with pipe operations. Piping was a new concept for me jumping from Ruby. It's absolutely powerful, concise and productive. In Elixir, if you don't write good code, the compiler will warn you AND show you examples of how (and sometimes why) it should be re-written. Eg. If you write a nested case statement which many people subconsciously may do coming from OOP backgrounds, the compiler will ask you to re-think your code. And stuff like this really challenges you, but actually doesn't do anything destructive to your code - your code will still compile and function, but you will feel that tingling inside - "Hmm, maybe I should consider re-writing that?"
THAT is the balance. Before Elixir, I also used Scala. Took me 3 months to fully learn the language from the 700+ pages book on Scala. I absolutely love Scala and the JVM. It's powerful, but there's just too many ways to do the same thing in Scala to keep track of. So, it goes back to my first point on looking at the language after 6 months without the need to re-learn it. I would still try Scala at some point because JVM is very powerful. But, will it replace Elixir? Absolutely not.