5 ms·
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?
- georgia_peach 5y agoWe inherited an Elixir project. After a year of irritations, we re-wrote it in Go and never looked back. The 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.
- hardwaresofton 5y ago> We inherited an Elixir project. After a year of irritations, we re-wrote it in Go and never looked back. 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.
- georgia_peach 5y agoFully agree on the typechecking. That's probably part of why LISP is so under-represented in commercial software projects. 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.
- hardwaresofton 5y ago> Fully agree on the typechecking. That's probably part of why LISP is so under-represented in commercial software projects. 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?
- georgia_peach 5y agoyep
- kazinator 5y agoSo, then, any idea why Haskell is under-represented in commercial software projects?
- hardwaresofton 5y agoWell you just don't need Haskell most of the time. 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).
- sph 5y ago> two different string types, two different throws (catch vs rescue), two different versions of each function (exception throwing vs error returning) 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.
- mstipetic 5y agoSounds like they were using elixir like Java or go. I’ve never even used exceptions
- georgia_peach 5y agoJava and Go never did this to me on a point release: warning: System.cwd/0 is deprecated. Use File.cwd/0 instead warning: String.strip/1 is deprecated. Use String.trim/1 instead warning: Integer.to_char_list/2 is deprecated. Use Integer.to_charlist/2 instead I'm sure that underscore was just killing them.
- mstipetic 5y agoIt didn’t break, it gives a timely deprecation warning, you can probably fix it in an hour or two with basic grep, where is the problem?
- georgia_peach 5y agoProblem being that this happened on every point release. It would be a non-issue if it only happened before a major release. 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...
- 5y ago
- sethammons 5y agoI recently switched from a Go shop to an Elixir one. Exceptions as control flow, arrgh! Compile times, gnashing of teeth. Unmatched patterns with zero context bubbling up. 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.
- georgia_peach 5y agoThe compile times were particularly galling: rust-like compile times to get javascript-tier runtime errors.
- bluehatbrit 5y agoLate to the game but wanted to add a reply to this. I chose Elixir for a side-project about 2 years ago now, and switched to Elixir full time 6 months ago. Absolutely no regrets. It definetely took a while to learn how to write decent Elixir code, but I think that's true of any language. My side project was my first Elixir project and it's gone through some serious iterations as I've learned various early things I did aren't ideal. Now I'm using it professionally and I'm so glad I am, it's wonderful to work with when you've got some experience in it and feel comfortable with it. 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.