Ask HN: Who Regrets Choosing Elixir?
If you ended up choosing Elixir for your projects, did you have to deal with pain points if any? Compared to proven platforms like Rails, did you feel things became difficult, especially in a team scenario? What made you switch to a different stack and what did you switch to?
23 comments
[ 2.8 ms ] story [ 72.9 ms ] threadThe combinatorics of having to deal with two different string types, two different throws (catch vs rescue), two different versions of each function (exception throwing vs error returning) in most of the base libs, weak typing, weak documentation, and the constant churn of dependencies because the language developers like to change things "just because" (i.e. regular re-naming of built-in functions for "consistency"--several builds broken because they just had to add/remove an underscore in one identifier or another).
And when things go wrong, we'd often have to dig-down into Erlang errors and libs the same way we would with Java errors in Clojure, so now we have two languages we've got to get everyone up-to-speed on.
When it got to the point where we were avoiding point upgrades in fear of how much of our code it would break, it was clearly time to move on.
This is a bit unrelated but I think a lot of non-compile-time typechecked PL communities are going to do this in the next 3-7 years.
In my mind, Go will be the next Java, because it actually does what people want -- builds fast, runs fast/lean and forces you to write code that isn't clever (so that the next dev who has to work on the "legacy" software) can get up to speed quickly.
That said, I don't think it makes sense to regret choosing Elixir long term. It's still good at what it's good at, and the fundamentals benefits underpinning erlang/OTP are unique.
Keeping the combinatorics to a minimum is critical, so if I wanted the benefits of erlang/OTP, I'd use it directly. Wrestling with these VM-in-a-VM languages is for the birds!
Only thing I miss about Elixir is its function composition operator.
Yeah after a friend re-introduced me to lisps, and I watched the original SICP classes along with some other things I got really into lisp and started building things in Clojure/SBCL (more so clojure).
After trying lisps my next foray was Haskell and now I can't imagine.
It's like a bad after school special -- Haskell, don't even try it once if you want to go back and live happily in untypechecked land. Now I have to have at least Typescript.
> Keeping the combinatorics to a minimum is critical, so if I wanted the benefits of erlang/OTP, I'd use it directly. Wrestling with these VM-in-a-VM languages is for the birds!
Yup, I feel that.
> Only thing I miss about Elixir is its function composition operator.
|> this thing right?
Startups need code that works, not good code, and certainly not code that is correct.
Large companies need code that meets the business need as fast and as cheaply as possible, makes developers more fungible, and is easy to hire for. Most companies just aren't doing the kind of work that you either need the correctness or the brains that Haskell attracts (not that Haskellers are smarter, but they skew towards theoretical knowledge, when sometimes you really just need someone to fix the rails controller that works properly with the new Stripe gem).
Correctness, performance, and error avoidance just aren't enough of a business need in just about all sectors. Good enough is good enough, and smart companies are good enough until it's not good enough.
BTW, even for myself, when I want to be productive/fast, I choose Typescript. When I want to be well structured and correct, I use Haskell. When I want to be blazing fast and mostly correct I use Rust.
IMO 99% of companies will never need anything more than Typescript (or it's equivalent) if the right solution wasn't wordpress+woocommerce or whatever to start with. Even Typescript is already overkill, since lots of people prefer vanilla JS and there are rubyists running around everywhere who haven't touched Sorbet but are extremely productive nonetheless (I am a bit biased against ruby, forgive me).
Haskell is what people think Java was supposed to be like/going to be -- the type system is expressive, the runtime system is amazing, it's got a bunch of mature libraries in the ecosystem, the performance is within spitting distance of Java if not better, consumes less memory, etc.
Even amongst research/ML languages Haskell isn't far behind. It's been a while since I've looked but Idris is basically Haskell + dependent types.
Haskell is the Mercedes of PL (especially if you're referring to the subset of practially-used PL).
I want to be clear that once I tried Haskell it became impossible for me to consider not having a similar type system again. It even soured me off of Go -- a simple nonfeature like having nullable types just ruins entire languages for me now.
Like it's why Python, Javascript, PHP and Ruby are underepresented, and why Visual Basic was so hugely unpopular in the 1990's, having had virtually no developer mind share or installed base.
It wasn't a dig at lisp BTW. Just pointing out that the combo of no typechecking + such a homogeneous syntax is going to make it harder for the new guy to find his bearings in the codebase.
In your examples objects are idiomatic, and give the new devs some idea of what they're dealing with outside of runtime. I know lisp supports objects, but I wouldn't call them idiomatic from the lisp I've seen.
And as for typechecking, the writing has been on the wall for PHP (first Hack, now native type declarations) & Javascript (Typescript anyone?) for some time now.
I have never used charlists at work. You have to know about them if interfacing with erlang, but it's never been a problem.
Same with exceptions: they are so niche in Elixir you practically never encounter them. Errors as values are idiomatic, not exceptions.
I don't want to assume, but it sounds like your project was handled by a team that didn't know idiomatic Elixir very much.
Spending "an hour or two" to update source and dependencies every time the runtime is upgraded is an expense I have only encountered in elixir.
It didn't help that, circa 2018, many of the dependencies had been abandoned by their original developers, so even more work for us...
.NET is no better.
Ecto is helpful for what we do, but I asked the team about handling (monitoring, logging what failed for what customer, metrics) db connection errors, and they are fine with exceptions. A connection error is not exceptional - they are expected with an app our size.
The modules seem written to deal with a lot of happy path. I want to know more about failure routes and ensuring we have the information to fix issues.
I'm assuming my frustrations are because there is more for me to learn and understand of the ecosystem.
Some of the things that tripped me over early were: * Deep case statements when pattern matching functions would have been clearer. * Not using type specs. * String vs Atom keyed maps, I thought I needed to have a consistent approach but later realised they're both useful in different circumstances. * Over-use of exceptions (throw/raise). In the end I realised you generally don't want to use these except in really specific cirumstances. One such example is when you want to totally fail and exit a deep stack which would otherwise require loads of case statements to bubble up an error. But usually staying away from these is the right call. * Multiple forms of functions (ones which raise and ones which don't). While having both is useful in libraries, the rule of thumb really is to stick to the one which doesn't raise and handle the potential issues (ie: nil being returned). Only use the one which raises when you need to kill whatever you're doing. In general I don't write both forms of functions for my own code though.
Once I got past those and other teething issues it's been wonderful. Even language version upgrades have been pretty easy and that's often a pain in other languages. Now that the languages is "mostly complete" we don't see much in the way of breaking changes which is great, the rare deprecation perhaps but usually you can just upgrade without much of a thought and reap the performance benefits.
For context, I was using C#/.Net professionally before and TS/JS (node) for side projects before picking up Elixir.