Generally I'd say any senior rails dev, given the right task, can write decent elixir code on their first day. There are a lot fewer foot guns in elixir and Phoenix, and so other than language ergonomics (a simple rule that doesn't stretch far but works at the beginning is use pipe instead of dot), there's minimal barriers
I've watched Elixir with much interest from afar, I even recently cracked open the book on it, but I feel like my biggest pain points with Ruby are performance and lack of gradual typing (and consequent lack of static analysis, painful refactoring, etc), and it doesn't really seem like Elixir has much to offer on those. What does Elixir solve, that Ruby struggles on?
Elixir is gaining set theoretic type system, so you are showing up at the right time. https://hexdocs.pm/elixir/main/gradual-set-theoretic-types.h...
The performance of my crummy web apps. My understanding is that even something like ASP.NET or Spring is significantly more performant than either Rails or Phoenix, but I'd be very happy to be corrected if this isn't the case.
I appreciate the BEAM and its actor model are well adapted to be resilient under load, which is awesome. But if that load is substantially greater than it would be with an alternative stack, that seems like it mitigates the concurrency advantage. I genuinely don't know, though, which is why I'm asking.
> Elixir is gaining set theoretic type system, so you are showing up at the right time. https://hexdocs.pm/elixir/main/gradual-set-theoretic-types.h...
Neat! Seems clever. Looks like it's very early days, though.
The community and it's values, because you enjoy it, because the technology fits your use case. Most web apps fit. 1 and 2 are personal and I'd take a 25% pay cut to not spend my days in ASP or Spring, no offense to those who enjoy it.
Phoenix has significantly faster templates than Rails by compiling templates and leveraging Erlang's IO Lists. So you will basically never think about caching a template in Phoenix.
Most of the Phoenix “magic” is just code/configuration in your app and gets resolved at compile time, unlike Rails with layers and layers of objects to resolve at every call.
Generally Phoenix requires way less RAM than Rails and can serve like orders of magnitude more users on the same hardware compared to rails.
The core Elixir and Phoenix libraries are polished and quite good, but the ecosystem overall is pretty far behind Rails in terms of maturity. It’s manageable but you’ll end up doing more things yourself. For things like API wrappers that can actually be an advantage but others it’s just annoying.
ASP.NET and Springboot seem to only have theoretical performance, I’m not sure I’ve ever seen it in practice. Rust and Go are better contenders IMO.
My general experience is Phoenix is way faster than Rails and most similar backends and has good to great developer experience. (But not quite excellent yet)
Go might be another option worth considering if you’re open to Java and C#
I've written APIs in Rust, they were performant but the dev experience is needlessly painful, even after years of experience using the language. I'm now using Rails for a major user-facing project, and while the dev experience is all sunshine and flowers, I can't shake the feeling that every line I write is instant tech debt. Refactoring the simplest Rails-favoured Ruby code is a thousand times more painful than refactoring even the most sophisticated system in Rust. I yearn for some kind of sensible mid-point.
Elixir seems extremely neat, but I've been blocked from seriously exploring it by (a) a sense that it may not be more any more performant than Ruby, so why give up the convenience of the latter, and (b) not having seen any obvious improvement on Ruby's hostility to gradual typing / overuse of runtime metaprogramming, which is by far my biggest pain point. I'm chuffed to hear that the performance is indeed better, that the magic in Phoenix happens at compile time, and that gradual types are being taken seriously by the language leadership.
I guess I'll have to take Phoenix for a spin.
Typing is coming, some is already here, and if you're impatient you can use dialyzer to get half way there. But in my experience you need it less than you'd think. Elixir primitives are rather expressive, and due to the functional nature there really isn't any "new" data structure that isn't easy to dive into. And with each function head being easy to pattern match in, you can dictate the shape of data flow through your application much as you'd do in a typed language.
The ide story isn't great, but it's getting better. There are a few LSPs out there, and an official one coming soon. And I'd say all of them beat solargraph handily
But most of all I'd say that, since it's a bit more strict, elixir saves you and your coworkers from yourselves and each other. There are still several ways to do something, like Ruby, but going out of your way to write very cutesy code that the next programmer will loathe is more difficult. Not impossible, but harder. And with the rock stable concurrency systems in place, a lot of the impetus to come up with clever solutions isn't there
Re types, I think what I really want is just comprehensive static analysis. Coming from Rust, where I can immediately pull up every single call site for a given function (or use of a struct, etc.), I find refactoring Ruby/Rails code to be comparatively very painful. It is several orders of magnitude more laborious and time-consuming than it should be, and I just don't find the justification for that cost convincing - I'd trade every last bit of Rails' constant runtime metaprogramming cleverness for more static analysis.
What I like about Rails is its batteries-included nature, but I honestly could do without those batteries materialising via auto-magic includes and intercepted method calls. I appreciate that that's just the culture of Ruby though, so I don't expect Rails to ever change.
The lack of cutesiness in Elixir sounds lovely. I don't know if functional approaches could make up for a lack of typing for me; I think I'd need to try it. I've used and enjoyed Haskell, but of course that's very strongly typed.
As for magic, elixir can have what looks like magic, but upon closer look it's nothing more than macros, which are generally pretty easy to decipher and follow. It has minimal automatic code generation, what it has is mostly the form of generators you'd run once to add things like migrations
I'm looking forward to the upcoming gradual type system - it can only be an improvement - but I would still encourage people to try Elixir now, and let go of their preconceptions about static typing.
Wrote about it more here: https://arrowsmithlabs.com/blog/you-might-not-need-gradual-t...
I cracked open an Elixir book last night, and with the benefit of a few chapters, I can see how Elixir's pattern matching can obviate some of the issues I have with purely dynamic, Rails style programming.
I also note that there appears to already be more static typing going on than I realised. In your add_comment/2 code, for instance, you focus on the {published: true} pattern matching. That is very neat, but what stands out more to me is that all clauses of that function require BlogPost, a struct type.
Am I right in thinking that every instance of BlogPost type must be constructed explicitly in your code? I.e. that every possible instance of BlogPost in the code base is knowable at compile time, along with its entire life cycle?
Or does Elixir partake of the horror that is duck typing, where any conforming untyped map of indeterminate provenance will pass the guard check for a BlogPost?
> Would you like another undefined method exception on that NilClass?
*thousand yard stare*
Almost. You can create a struct dynamically at runtime like this:
struct(BlogPost, %{title: "The Title"})
# => %BlogPost{title: "The Title"}
… but you rarely need to. In fact I'm not sure I've ever used `struct/2` in real life. 99.9% of all the structs you ever create will have their types known at compile-time.> any conforming untyped map of indeterminate provenance will pass the guard check for a BlogPost?
Nope. In the `add_comment/2` example, If I pass anything except a %BlogPost{} to that function, I'll get an error.
While I remain haunted by thoughts of someone e.g. deserialising a YAML file into a map, which then sneaks in some __struct__ key and squeaks past the guard clause, I also appreciate this seems fairly unlikely in practice. I think I'm just traumatised by Rails. It sounds like the culture around Elixir eschews excessive cutesiness, though. Promising!
I wrote a long Reddit post about that[0], but for the tl;dr you can ask José Valim himself: https://news.ycombinator.com/item?id=36604054
[0] https://old.reddit.com/r/elixir/comments/1ipyi81/why_should_...
In practice I find that I hardly ever need to think about things like this. A few times I've done macro expansion to peek under the hood and figure something out but that's partially Lisp damage, I could probably just as well have read some documentation.
Having seen... things... unless it's written by people with the right skillset (and with funding and the right environment), that it exists doesn't mean you should use it (and the phrase "it's a trap" comes to mind sadly). https://scicomp.stackexchange.com/a/10923/1437 applies (and note I still wouldn't call Julia mainstream yet), so while I'm not saying people shouldn't try, the phrase "don't roll your own crypto" applies just as much to the numeric and scientific computing fields.
Edit: Hah! aloha2436 beat me to the answer. Sorry for the repetition.
</shamelessselfplug>
I think the community tends to overestimate the ecosystem’s maturity which is one of the big things holding it back, both because it blinds the community to areas that need improvement and leads to bigger shocks when newcomers do unexpectedly run into the rough edges.
"Take this Ruby gem and write the equivalent functionality in Elixir" is something that LLMs are very good at.