I've always wonder how the Erlang ecosystem would be different today if a digital giant like a Twitter/FB/Google had used Erlang as part of their core business.
Note: yes, I realize WhatsApp owned by FB is run on Erlang.
Hard to say, as you pointed out, Whatapp runs on Erlang, and despite their upstream patches, no BEAM based framework is competitive on the techempower benchmarks.
But let's not forget, AWS SimpleDB was written in Erlang, as well as the first iteration of Facebook Messenger.
I invested a decent amount of time in learning Elixir and Erlang and understanding BEAM. My personal takeaway, which seems to be mirrored by every big company, is that the ecosystem just isn't worth the investment.
> as well as the first iteration of Facebook Messenger
I was told, from someone familiar with the project at the time, that the first iteration was done with ejabberd, which is written in Erlang, with the main purpose of bootstrapping it. Erlang was not really in consideration in the long term at the time. Not sure if it changes your take personally but hopefully adding some context helps. I am always glad to be corrected if wrong. :)
I wrote about Techempower in the past. In a nutshell, the Erlang runtime does plenty of assumptions that you would absolutely use in production but which become overhead in benchmarks like these. Previous comment here: https://news.ycombinator.com/item?id=22894191
> My personal takeaway, which seems to be mirrored by every big company, is that the ecosystem just isn't worth the investment.
Your experience was guided by a decent amount of time and I actually appreciate you invested in learning it before deciding it wasn't worth it. However, I doubt every big company had the same takeaway for two reasons:
1. I doubt every big company went through the same experience (i.e. have they learned about the ecosystem?) to mirror the takeaway
2. The every quantifier is provably false, since there is Facebook/Whatsapp, PepsiCo, Klarna, Ericsson, Nokia, Mozilla, Cisco, and others using the ecosystem in production and/or investing on it (plus at least another company from FAANG using it at multiple projects)
I feel like developer experience of Discord is the only argument you need when talking about whether Elixir can scale economically. If a company can do it on venture capital, it's well within the grasp of FANMAG.
Edit: That said, squeezing every last drop of performance out of a server by writing everything in Rust is something that a FANMAG can well afford and may make more sense at the 100mil+ concurrent users scale, but it wouldn't be economical to start a project this way without certainty the capacity would be used.
It's worth calling out that the TechEmpower benchmarks have been flawed as long as they've had Erlang/Elixir on them. People keep submitting changes and they keep refusing to implement them.
Early days of Twitter were a lot of scaling issues due to the choice and implementation of RoR and they considered a lot of things, which got a lot of public attention. 13 years ago...
Twitter probably couldn't scale because of bad engineering, not because of RoR. For example, Shopify embraces the Ruby ecosystem and it scales up very well.
I imagine shopify is more profitable for the amount of traffic it gets, so they can afford to throw more machines at the problem as well.
Shopify does probably have better engineering though. They have an amazing process of 2 code reviewers per PR, and one code reviewer is from another team. They write tests for everything and deploy continuously to production.
Twitter were the first to get the future/promise abstraction right and publish it widely (in Finagle). That inspired not just Scala's now-standard Futures but also the CompletableFuture in newer versions of Java and even e.g. Rust's Future, although none of them have the wonderful for/yield syntax (similar to Haskell do notation) that make it such a joy to work with in Scala.
Sadly most of the tooling funding came from the other big Scala user, who favoured an invisible-yield-point style (which I'm pretty sure inspired the model that Kotlin now uses with suspend functions).
One of the many tragedies of Scala (still the best general-purpose language on the whole, IMO) is that the community formed these somewhat siloed ecosystems that were each doing things their own way and had their own stack of libraries that didn't really play nice with each other. The language actually makes it very easy to write your own adapters (which may be why industrial users didn't create a lot of pressure to stop all the nonsense), but political fallings-out usually meant that it took years before there were "blessed"/official ways to use X with Y.
In the 3 years I spent writing Scala, the only major Twitter contribution I remember running into was Finagle (http://twitter.github.io/finagle/). It might have been a big influence at the time, but these days it's relegated to the scrapheap of older frameworks.
There was no major users of Scala prior to Twitter that I can recall. Twitter put Scala on-the-map.
Plus, there is far less of an "ecosystem improvement" to be made with Scala since it's riding on the Java Runtime (which already had massive adoption and development prior to Twitter selecting it).
Yes, this. They buy companies all the time.
Also counting Erlang and Elixir together seems a bit odd, are they the same thing? Is a Clojure company actually a Java company?
If someone makes the Java GC 3x faster, that will most likely positively impact all Java and Clojure programmers. Similarly, if someone wants to invest on Clojure performance, they most likely need to do so by investing on the JVM and core libraries, which will benefit the overall ecosystem. Plus one main reasons people use to pick JVM languages is the access to the whole Java ecosystem and related packages.
Therefore, if you are considering the performance of the platform, improvements to the runtime and virtual machine, package ecosystem, etc, lumping them together makes total sense. On the other hand, Clojure and Java are quite different languages, with complete different paradigms, so there is probably a ticker layer specifically dedicated to Clojure.
Erlang and Elixir are much closer to each other than Clojure and Java or even Scala and Java. The data structures are the same, the language constructs are mostly the same (different syntax but the same semantics), etc. You can call each other with no performance cost whatsoever. All of the companies investing on Erlang will directly impact Elixir and, if you want to make the Elixir compiler or runtime faster, odds are that this efforts goes to Erlang - it is one of the reasons I have ~100 PRs merged upstream, mostly focused on the compiler and/or performance.
So, once again, if your goal is to assess the healthy of the ecosystem or how many companies are investing on the platform, then they must be considered together. The contributions done by Ericsson, Whatsapp, Klarna, Erlang Solutions, etc. benefit all languages running on the Erlang VM. In fact, if someone asks me how they can financially contribute to Elixir, I will 100% direct them to the Erlang Ecosystem Foundation (https://erlef.org/), which focuses on domain areas around the ecosystem, rather than languages.
Since you seem to use Ruby as a reference, I don't expect the dynamics to be much different. Most companies and contributors are likely working directly on the Ruby VM and the runtime, rather than the language itself. However, because Ruby is the only (main?) language running on it, we don't tend to separate them. But in practice the language is only a small surface into the complexity that is its underlying platform and working on said platforms requires a completely different set of skills and technologies.
EDIT: this applies to the ecosystem too. For example, every Phoenix application is running a web server written in... Erlang. :) All Ecto database adapters are using the tcp modules provided by Erlang. The package manager that powers all languages running on the Erlang VM is written in Elixir. And so on. You don't need to know Erlang in order to write Elixir but, if for some reason you need to pick up, it is straightforward because of all of the above.
Ruby runs on C, I guess if C gains in performance then Ruby (and Python, and JS(?) and PHP) all become faster as well. I know it's not a perfect analogy to Erlang/Elixir but there is a strong connection between C performance/memory management and Ruby. For instance the whole malloc/jemalloc memory issue which affects Ruby/Python/Node(?) apps. It could be that these dynamic languages misuse C or something and it's really not C's "fault", I'm not sure, it's above my pay grade :)
I am sorry but that's a very inaccurate analogy on this topic. The Ruby VM, in particular MRI, is implemented in C. The Erlang VM is also implemented in C. A better C compiler can likely benefit them.
But what runs your Ruby code is the Ruby VM (or even the JVM). What runs Java and Clojure code is the JVM. And what runs Elixir code is the Erlang VM.
The relationship between Elixir and Erlang is much closer to, say, Rails and Ruby (i.e. Rails is built on Ruby's abstractions and semantics) than Ruby and C. It is not a good example but it makes much more sense than the analogy above.
OK, gotcha thanks for explaining. Just for my general knowledge is Erlang/Elixir apps also affected with memory bloat (I mean memory that grows and grows and never properly garbage collection) which seems to be improved for certain apps with jemalloc 3? I mean if it's built with C I would imagine the same problem may occur for Erlang/Elixir.
I am not familiar with the issues affecting the referenced languages to make an efficient comparison, sorry. But I can add some context if you are interested in looking further.
First of all, let's talk about the memory model. The Erlang VM manages memory per process (where a process is a lightweight thread of execution inside the VM that runs concurrently and you can literally have millions of them). So for example, when you have a web request, you spawn a separate process for this web request and once the process terminates, all the memory allocated to it is reclaimed by the VM. This means you can serve a web request without triggering a garbage collector even once. And if you need to garbage collect, it is local per process, so no system wide pauses.
However, what happens if you want to share a large blob of memory between processes? If you copied it between each process it would be expensive, so in this case the VM employs reference counting.
One curious point is that the Erlang VM did not give allocated memory back to the OS until Erlang/OTP 22 (roughly two years ago). This was not much of a problem in the Erlang VM because you typically run only one instance of the VM per node, regardless if you have 4 or 32 cores. Given the issues you mentioned in Python/Ruby/Node, could it partially be because you would rather start 4 or 32 instances per node, so if one of them accumulates too much memory and doesn't give back, it starves the other ones? Or perhaps you would have background workers fighting each other? If you have links to said issues, please share them!
Come now, macros are just functions over syntax. ;-P
But yes, the only headaches I’ve had have been with hard-to-follow macros.
That said, the Phoenix Framework has some well-chosen macros that are a delight to work with. Furthermore, all these macros are defined in your source when you create a new Phoenix project—I feel that over all there is remarkably little magic in Phoenix, and what magic there is is easily inspectable.
I wouldn't say "remarkably little". There's "relatively little", esp. compared to Rails. I'd even say there's little magic compared to Django.
But try to peek under the hood of Phoenix.Helpers someday...
And also, don't ask too many questions about how Ecto drivers work... I tried writing an ecto driver once and gave up. Props to the people who made the Sqlite3 driver.
Macros are extremely powerful, and like all really powerful things, they’re very easy to shoot yourself in the foot with… we’re lucky that the Phoenix team are some very capable wizards!
I'm still not entirely sure if I'll be an Elixir programmer, but I do appreciate the culture of the Elixir community. José definitely seems to be trying to Be the Change with respect to inclusivity.
The Elixir/Phoenix forums are a genuinely delightful place. Can’t recommend them enough. Great mix of beginner questions and best-practice discussions, and commenters tend to be quite knowledgeable and very friendly.
And doing it in a genuine way as well. Just living out the values, instead of beating it over everyone's head, and shouting "We're inclusive! Look at us! We're inclusive! Hey everyone check us out! Inclusivity!"
Metaprogramming in elixir (i.e. macros) will definitely feel like magic to most. It allows for really powerful abstractions, but doubtful the new guy would have been able to be productive in a month in a large codebase full of them. Your standard phoenix app, yes it is fairly straightforward.
But what does a large codebase full of macros would look like? It's an anti-pattern to have too much macros. They should be used as a last-resort option.
I wouldn't say it's an anti-pattern to have too much macros. Macros are a a tool to solve problems. If the problems require macros or at least benefit greatly then macros it is.
HN meta question:
When I see all these double-returns at the end of each sentence, should I assume it's because someone is using Slack (or another chat program where mashing return after every statement makes sense) and a bot/script to make the post? That strikes me as a very unnatural way to punctuate in a textarea form.
I did this twice this year at my current job. Each time I made a case for introducing something new and interesting (Typescript, and Elixir). It took some convincing, and finding the right projects to introduce these technologies, but it happened. The result is that I've shipped four projects with Typescript, and am in the middle of delivering a greenfield Phoenix (with LiveView) app.
What? There’s so much magic in Elixir and it’s ecosystem. Controllers in Phoenix, various handle_info overloads and requires implementations, misspelled atoms, pattern matching and mismatches with names structs, the implicit return… there’s so many footguns to fire at yourself.
these days returning from the middle of a function seems like magic to me. What is this return keyword and what sort of control flow is it abstracting over??
1. What's funny about the photo at the top of this blog post is that it scales with the width of the window you're using to view it. That normally would seem like a bug but it actually works with this photo, to the point that I can't tell what the original width of the photo is!
2. This quote is kinda funny to me:
> Many of the engineers whom I work with, actively seek out Elixir specific opportunities because they enjoy the language and the run-time that much (I’ll be diving into specifically why a bit later in the post ). This is also supported by a recent StackOverflow developer survey where 68.2% of people working with Elixir, wanted to continue working with Elixir. For some comparisons, Go received a 67.9% rating and Javascript received a 66.8% rating.
It seems like OP is trying to make the point that Elixir is so special that engineers will actively seek out Elixir jobs ... and then cites stats that show that's true only 1% more than Go and Javascript.
Maybe I'm reading it wrong and OP is just trying to show that Elixir is only as loved as Go/JS, not better, but in any case the stat cited does not show Elixir is any more special than either of those other super popular languages.
(I'm currently an Elixir dev, btw. I like it well enough but I personally don't think it's enough better than Go or JS to justify switching when the community is still so small.)
I think the case was more intended to point out it's no different than choosing Go or Javascript, in terms of developer affinity (the size of community is part of what the article is intending to address).
Personally, I find Stackoverflow's surveys pretty useless. Python has 73% "loved", which tells me...what? That 73% of Python developers like Python. But what else do they have experience with? Is this just objectively "I like Python", or "I like Python more than X"? What is X? For those who don't "love" their language (which really just translates to "they have not expressed interest in continuing to develop with it", based on what SO gives us), is it because of another language capturing their imagination more? What languages are those, have they actually used it in the past in production, etc.
>For those who don't "love" their language (which really just translates to "they have not expressed interest in continuing to develop with it", based on what SO gives us), is it because of another language capturing their imagination more?
As a C++ dev, definitely Rust. It got almost everything right that is horrible with C++, while still maintaining similar power.
Author here. Glad you like the banner image and the zooming effect :).
Perhaps I miscommunicated what I took away from the StackOverflow survey. The point that I was trying to make was that in relation to other programming languages in the survey, Elixir ranked high with regards to how loved it is. The StackOverflow survey is just one data point in addition to the others that I bring up and like many surveys has it's own issues (like WebAssembly being a compilation target as opposed to a programming language the people program in).
Not sure if this against the guidelines (it says no job ads as submissions), but on the note of hiring Elixir developers, if anyone is interested in being involved in an early stage Elixir (Phoenix) startup, we at Jinso are hiring a senior engineer with Elixir experience and would love to hear from you: https://www.jinso.com/
Don't want to derail the conversation, but shoot us an email at admin [at] jinso.com. We are happy to tell you about us and get to know who you are!
What is not mentioned here, the lack of static typing in elixir. I think for some people it could be no go. That is one major downside for me as well. On the other side, totally agree with the developer experience, really love it. I work profecionally with nodejs/typescript and on my free time looking on other languages, especially functional ones. I tried clojure before, but found the ecosystem in Elixir way better, especially dev tooling. It feels like it all really stick to each other. Another part, because all structured around modules, it is easy to check documentation and find the function you are looking for.
I dont' care about static vs dynamic typing but if I could at least typehint function arguments my IDE intellisense and
I would be so happy :) Maybe it could even be compiled to guard clauses or something?
Writing specs is tedious and apparently not even encouraged for private functions.
I personally don't miss statically typed languages having worked professionally with Java, C++, and Typescript in the past. But if static typing is your cup of tea and you want to run on the BEAM, be sure to check out the Gleam programming language https://gleam.run/
We use the dialyzer and also heavy usage of the @spec function signature annotation on public module functions to work around this. It’s an nice compromise between some defensive safety while still enjoying the readability of the dynamic typing.
Agreed. In my experience, typespecs and dialyzer has caught a bunch of bugs living on rare code paths. If I had neglected to test those code-paths, they might have found their way in production.
And what's liberating is that there can be multiple types (including patterns) for each argument and the return value, and the spec can capture all those details. This combination of specificity and flexibility is unthinkable in most languages.
I'm curious about the experience of having taught a senior dev GenServers so early on. I guess it depends on what they are working on, but I think for most people (senior devs included) GenServers are YAGNI -- I have not once written a genserver for my current job, the senior might be tempted to be clever and use GenServers as code organization or as a circumvention to write stateful code, a la "objects" because GenServers are rather close to Alan Kay's original objects.
As a seasoned Erlang developer, it's really foreign to me that people can go so far as to never need a GenServer since they are everywhere in Erlang. Have you had any experience with ramping up an Erlang engineer to use Elixir? After interviewing an Elixir dev for an Erlang position, it was interesting that so much of what they used in their day-to-day abstracted away the components of OTP and the Beam. Didn't really have a firm grasp of supervision trees, process linking vs monitoring, etc.
Elixir gives you Task for one-offs, which is a superior abstraction over proc_lib, and has seamless integration with OTP things like supervision trees, which you will have to roll by hand and probably mess up if you use proc_lib.
For just stateful data, ets is much better performance-wise than a GenServer (with the tradeoff being complexity in understanding matchspecs and the like), and Agent is much simpler for dumb state and leads to better code (though I basically never use Agent).
Honestly, I think the GenServer behaviour is awful (not GenServers, themselves, they are great), because it does not engender writing well-organized code. Dave Thomas' empex talk about it is really eye-opening and you will understand the internalized pain. (I don't like his specific recommendations, and I think the ship has sailed on Elixir reimagining how GenServers are organized).
So yeah. My philosophy is don't write GenServers, unless you are really sure you need them (like maybe collaborative state for games; to wrap a stateful communication protocol, like http tcp, or an application layer over udp; or to to model something IRL or remote, e.g. browser state as in liveview, or as I have in a previous gig, qemu VM state). And even for some of these you're probably better of with a gen_statem or the like.
> supervision trees, process linking vs monitoring
you still need to understand these to use Task correctly, or gen_statem, but those are really advanced topics. It's crazy, but you can get really really far without those (even if it's not, strictly speaking best practice), and it's not like once you learn about them it's hard to change your code to start using those correctly.
In my day to day work I don't write many GenServers either and I think that's a good thing. Like any tool, they can be overused and abused. It is best to stick to modules and pure functions until you really need to pull the stateful lever.
To that point, GenServers as an abstraction are super powerful and when applicable, are an amazing tool. For example, being able to control the initialization of a supervision trees using :ignore in the init callback can be handy to run DB migrations as part of the application startup. Or when used in combination with a registry it can be useful to hold on to user data in a GenServer and access it atomically across your cluster.
The temptation is there, but AFAIK most learning materials are good to call out that processes are for concurrency needs, and a genserver is an abstraction on top of that to help with certain things, like synchronization.
Yep, FP is really nice. A lot of what people think is going to be different is actually not that different from OO. Elixir especially ends up looking a lot like OO with its pipe operator ("string" |> String.split() vs "string".split(), for eg). Some of the major wins are immutability (which is actually very easy to grasp and a lot of people write in an immutable style in OO) and the fact you can every functions dependencies right there. The latter is actually huge for me as I always hated jumping around files, trying to see where things are coming from. FP minimizes this. There are lots of other niceties (some language-specific) but those are some of my faves.
Sometimes things take a little longer to write as you have to be slightly more verbose, but it's so much quicker to understand when coming back to it.
What's better (and more flexible) than Object Oriented is Polymorphism.
The pipe operator |> that you mention is great example because it does something in OO that is typically done using a 'fluent interface'[0] often used in 'Builder' classes (i.e., the class methods return the object so that it can be chained together). The great thing about the pipe operator is that it's much more simple and flexible, it simply passes the result of the prior function as the first argument to the second. This means, unlike with a fluent API, you can pipe together functions from completely different modules:
Elixir also has protocols[1], which allow a function to be used across a variety of types (similar to obj-c/Swift). Which again is more flexible, as the functionality can extend a 'class' that you don't control.
Elixir also has behaviors[2], which just guarantee that a module contains a number of functions, something akin to interfaces Java.
Dialyzer can take advantage of behaviors and protocols to enforce typing constraints.
Yes! Another thing I love about FP is the simplicity of terms. So like how you mention a return value can flow through different modules, if you wanted to do something like that in OO, you’d have to come up with a concept for what the new object is (ie, Service or what have you) which in turn has to take an object, breaking the whole “data and behaviour combined” idea. In FP, you just have modules. You don’t have think much past that a module is a group of functions that work on a certain data structure and other modules might also work on that data structure and that is fine (though of course you’ll want to hide those behind another module and delegate if you are dealing with a complex model, but that is a whole other problem that also exists in OO).
Yes - far more than the opposite IME, it's pretty rare for someone who's good at FP to switch permanently to OO, whereas even successful, experienced OO people often switch permanently to FP.
My OO definitely has a much more functional feel to it. Pretty much use OO to connect the parts so that the functions are connected from inputs through to outputs in a pipeline-y way. Monadic data, aspects, and error handling is also commonplace. I recently figured out that I can chain (value, error) in Go with different value types and not deal with input x output explosion of flatmappers--trick is to bind with closures to make zero-arg functions so only the output type varies.
I assume you mean the Go part. I meant to write a mini-blog post but can summarize here. Lets say we want to use an Either<ok, error> and chain computations. In Go naively without generics this needs the product no-of-input-types x no-of-output-types forms of result mappers/chainers. Instead we make functions that bind all it's inputs so only has an output-type. Now we only need linearly as many mappers/chainers (and_then's). e.g.
where makeComputeAThingFn(...) returns a function with the body `return computeAThing(...)`. `err` will end up with the first non-nil error and the following and_then.X's will be no-ops.
I started using OOP with Turbo Pascal and C++ a long time ago, and Elixir 5 years ago roughly.
Yes, I do enjoy FP on the long run, not only to write it but more importantly to maintain it (much easier in my opinion, including refactoring & tech debt reduction).
I still use OO too (e.g. with Ruby), but my Ruby style has gotten more FP-oriented as a result (e.g. ETL components which looks a lot like Elixir modules).
I think many people haven't realized that different paradigms fit different people's brains in different ways; there are better paradigms for a specific person and task but it's impossible to generalize.
Ehn, the more pro-Elixir search results out there the better.
I feel the same way as the author and really want to find a job where I can work with it full time, but my current work situation is too good to give up.
https://news.ycombinator.com/item?id=2825689
I've always wonder how the Erlang ecosystem would be different today if a digital giant like a Twitter/FB/Google had used Erlang as part of their core business.
Note: yes, I realize WhatsApp owned by FB is run on Erlang.