The article was published earlier this week and I have a quick addendum: regarding Erlang/Elixir, my goal has always been to bring new developers to the platform. After all, Erlang developers already have the most important part of Elixir, which is the Erlang runtime!
There are also key people in both communities working hard to make sure the tooling is consistent across all languages. A lot of this effort happens under the Erlang Ecosystem Foundation (https://erlef.org/) too.
All to say, regardless if you pick Erlang or Elixir (or Gleam, LFE, etc.), I hope you will fall in love with the platform as much as I did 10 years ago!
Thank you for your work on adding user registration and authorization to Phoenix!
I'm setting up a new Phoenix app for a side project this weekend and have just run Arron Renner's auth generator[1]. Having user registration out of the box will save a big chunk of time and energy!
Thanks for creating Elixir. Before using it and going through the website and docs I thought it would be good but once I started to use it, I discovered it is excellent.
I'm going to shamelessly take advantage of your being here with a question if that's ok. Do you have any recommendations for reading material that covers Phoenix as it's used today?
Back in the early 0.x days I read the Phoenix book, which was a great introduction to building an application and using Ecto, but trying to pick it up again recently I found that nothing really seems to cover using Contexts in the real world.
You probably have seen it already, but recent Phoenix docs have a section on contexts and what is their intended use case: https://hexdocs.pm/phoenix/contexts.html
The way I see it, context are just the public API to access your data model. Your Ecto schema is a piece of data, which in a functional language has no behaviour attached. The (business) logic to deal with this piece of data lives in the context. That's it.
It's nothing particular and specific about Ecto or Phoenix, it's just a good design practice that's applicable and recommended in any language.
What about access control? That's often directly tied into business logic, but it's so elegant and convenient to do it in the controllers or even the router using the pipelines. In fact a ton of the examples (I think even the Chris McCord Phoenix book) does exactly this, presumably for that reason.
However I did that with an app and haven't been very happy with it because while the bulk can easily be done in the router/controllers, there are things that are totally inappropriate to do there and so it ends up in the context. Then your logic is distributed and messy, which is awful. But putting all access control in the context also bloats and complicates a ton of otherwise very clean, elegant API functions. I try to keep the Repo query building code clean and separate but that often leads to inefficiencies (such as filtering fields in the caller instead of in the generated SQL, which is vastly preferred for obvious reasons).
Personally, here is what I do: if access control is part of the business model, then I put it in the context and, almost always, I raise. Otherwise, continue doing it in plugs. That's it!
For web apps, you should almost never be triggering these invalid access control state, because it means the UI is allowing users to do something they are not really supposed to do. If the user cannot delete a resource, then the button most likely shouldn't show up (or it should be disabled with a comment) etc.
Raising actually helps us find these bad UI paths too because I get an error I can act on.
Now let's say you do want to handle some of these errors. You have three options:
1. Continue raising and rescue in the controller (meh)
2. Continue raising and implement Plug.Exception for said exception so you control how they are shown to the user (great if they are still general exceptions)
3. Return {:ok, _} | {:error, ...} and handle it in the controller (or in the FallbackController for APIs)
Thanks :) I started reading the original DDD several years ago, but bailed out due to quite how dense it is, hopefully this summary will be a little more approachable.
Just to add to your comment: I've been running through the free LiveView course and it's been really great. I'm excited to finish it and continue with the pro one!
I have that book too and it's great. Will have to check out that specific section. I mostly used it to see examples and explanations of how to do things in the Ecto DSL (which it is great for).
Contexts are loosely (maybe a little more than loosely) based on the Bounded Context concept in Domain Driven Design. As a good introduction, I would recommend reading Domain-Driven Design Distilled by Vaughn Vernon. It's sort of like the Cole's Notes version of the full Domain Driven Design which is a monster of a book.
Thanks for Elixir and to the team as well for the work you put. I'm new to Elixir, had to learn it at work and it's been an interesting way to solve problems. I'm looking forward to deploying a few prototypes this year using Elixir. Thanks.
Thank you Jose for your relentless dedication to the language and community. The last year of full-time Elixir/Phoenix has been my favorite of my career, and I'm really looking forward to future of the ecosystem.
Thanks from me as well. It’s been more than 5 years since switching from Ruby and I have never regretted it. You did and continue to do great work(and whole team as well). Can’t wait for the big thing at Lambda Days!
Happy Elixir user here. At work we have a use case that isn't covered by José's high-level overview of the domains Elixir's used in: we run a massive multiplayer game server on it.
This is actually a really good fit. (It kind of rhymes with the original use of Erlang, being telecoms infrastructure.) We get outstanding concurrency support, high reliability, and really efficient development times. I can't imagine shipping this feature with a server written in C++ (the language I'm most comfortable in), and I can't imagine scaling it the way we need to if we'd gone for a traditional web language like Node, PHP, etc.
If you're interested, you can see the RakNet (game networking protocol) implementation we use on the server here:
The README gives a good overview of the full MMO server's architecture, too: each client connection is a stateful Elixir process (not to be confused with a heavy-weight OS process!), acting asynchronously on a client state struct; clients then asynchronously schedule themselves to send updates back to the user.
It's not as ambitious as an MMO, but I like to use MUDs to learn new languages. I've been (slowly) working on one to learn Elixir and I'm actually finding the concurrency model somewhat difficult to use for the MUD - especially the single world that every player connects to.
But altogether my design feels fairly un-Elixir-like. It seems like the language would shine more in a problem space with more process isolation. When it comes to the game world, pretty much any process could potentially depend upon any other process. Especially once you get into scripting NPCs.
I took a look at ExVenture when I first started working on this. A lot seems to have changed since then, but from what I could tell at the time there were some potential races. For example, movement processing seemed like it allowed for the possibility of players to seemingly move through doors that were closed (at least, from the players' point of view). I could easily have been wrong though since I'm new to Elixir.
That said, a requirement for scripting I have is the ability to chain together arbitrary actions in an atomic fashion without any races or deadlocks. Content creators can create really complex scripts that involve arbitrary locations and actions. I wasn't sure how I would achieve this goal with ExVenture.
If concurrency doesn't help, you can always just not use it. You don't need to run logically separate modules in different processes.
What if you put the entire state in a single GenServer? You can still delegate modifying different parts of the state to different modules, just call functions in those modules from a single server process.
It does help. Any given action will modify a fairly small part of the overall state (at most around .01% of it). But what part of the state it can modify is fairly arbitrary based upon the action. Your dependency could be dataA, dataB, then dataC. Or dataC, dataV, then dataA. Which, if you isolate into processes could create races and/or deadlocks. They would be very unlikely, but they could still happen.
This is why I went with software transactional memory. In the generally unlikely event that there's some overlap, the changes will just be rolled back and re-done.
Yep! I was actually the sole dev working on it, both server- and client-side. I'm working on a post for our public dev blog talking about why I chose Elixir and what my experience has been. It'll eventually be available here:
Meanwhile te company I work for is moving away from it. We cannot find enough people with enough knowledge to be already productive in it. Not many want to learn it because it is considered pretty niche, and the ones willing to learn will need many months or years to be productive and build with some level of quality, and once they learn they move away to bigger companies which pay more. We end up paying to people to learn to then "graduate" and we end up with a platform built by people that were learning.
Some people here say the tooling is great. Compared to what? The editor plugins are terrible, slow, and blow away your CPU doing god knows what kind of indexing. Compilation is slow and takes a lot of time (in CI for example). Libraries for things you give for granted in other platforms (java, javascript, python, ruby) are non existent, implemented in erlang, unmantained, poorly documented, not popular enough, or a combination of these.
People are using it for creating traditional CRUD apps, and it is totally overkill. Something you would do in a day with django or ruby on rails takes a lot of time. Ok, you have tons of concurrency and scaling and.....but... unless you are facebook or google or amazon you won't need this anyway.
Probably all of these things will be solved in the future, but at this moment, using Elixir for real production code in product focused companies is just a terrible mistake in my opinion. Certainly the ideas, the technology, and the BEAM are awesome...and it is technically superior to everything I've seen out there. But from a business perspective, it makes no sense to use it unless you're building the next whatsapp or similar.
Anecdotally, having managed elixir teams and talked to other managers of elixir teams:
- The learning curve is real. but 2-6 months for us, not years. It's not particularly hard, just longer than a small language like go.
- Having Ruby and/or functional programming experience shortens that learning curve.
- Developer experience/satisfaction is very high. This helps retention
- Some devs will just never "get/grok" Elixir. They may have 20 years of java experience or a new dev better suited to a FE role. This doesn't mean they are bad, just not a great fit.
- The devs that do get it? They are quite productive. Feature velocity is high.
I disagree that Elixir/Phoenix isn't a fit for CRUD apps. I'm seeing high feature velocity across small and large scale products.
In particular, feature velocity per engineer is quite high. A smaller team in Elixir/Phoenix/LiveView can outpace a similar full stack team.
It sounds like you're recruiting from a pool of junior developers and convincing them to use Elixir instead of attracting folks who are already interested in the language. Not only is that community sizable, but it's experienced- surveys of attendees at my conference (https://empex.co) consistently show that 50% have >5 years and 30% have >10 years in the industry.
Elixirists really are senior developers and Elixir is usually their fourth or fifth language. If it's taking your hires years to get up to speed, then I would look at your hiring practices before blaming the community.
As for libraries, I challenge anyone to name an unmet dependency in Elixir that is 1) trivial to implement and 2) not for some niche application.
My company has built a scalable platform with 3 engineers. I don't even think about maintenance, I just think about delivering new features. So business wins are higher velocity + lower hosting costs + less downtime + senior team. You don't need to be WhatsApp to appreciate those benefits.
I'm pretty sure I can find more than one package I'll miss.
> My company has built a scalable platform with 3 engineers. I don't even think about maintenance, I just think about delivering new features. So business wins are higher velocity + lower hosting costs + less downtime + senior team. You don't need to be WhatsApp to appreciate those benefits.
Hosting costs are a lot cheaper for us than developer's time. Downtime has never been an issue given "cloud" (docker based) infrastructure. The productivity part is something we're not seeing to be any better than with more traditional technology, and the reason we're moving away.
I wonder if what your team of 3 people is building couldn't have been built with just one engineer and ruby on rails at the expense of paying for two more servers.
Ironically, Europe has a higher concentration of Elixirists given Erlang was invented there. My hiring attitude is that paying for senior developers is cheaper in the long run given their ability to make better decisions.
> I wonder if what your team of 3 people is building couldn't have been built with just one engineer and ruby on rails at the expense of paying for two more servers.
Emphatically no. Having more servers costs more than just hosting, there's maintenance, orchestration, and communications complexity.
While other package ecosystems certainly have _more_ packages, the question is: how many of those will you actually use?
> While other package ecosystems certainly have _more_ packages, the question is: how many of those will you actually use?
Exactly. Saying NPM has millions of packages is completely misleading. There will be 20, 30, 40 packages that all do the same thing.
Elixir is also a very stable language with no current plans for a 2.0 release. This means that while a lot of Hex packages may not have been updated in a while, they are still rock solid. I agree that this is a very hard thing to get used to since the first thing I always do is looked at the last commit date and then the number of stars. While this is still useful, it doesn't hold the same weight it does in other ecosystems. Personally, I think this is how it should be.
I won't say that the Elixir ecosystem is perfect, though. There has been trouble with maintainers leaving projects, but to knowledge someone always steps up.
> Exactly. Saying NPM has millions of packages is completely misleading. There will be 20, 30, 40 packages that all do the same thing.
And the one with the obvious name hasn't been updated in 18 months. Maybe it's complete. Maybe the developer has moved on. Then there are a couple half hearted forks. All of these dependencies bring in 1 to 100 dependencies each and you have to spend a days on the treadmill every month or two to keep things updated.
I loved Node development despite the packaging mess but I really appreciate how the Elixir community tends to coalesce around key libraries/frameworks/methodologies and focus on making them the best possible.
Is that a Node specific problem though? I have elixir packages up on Hex that I haven't maintained or looked at in years. In fact, I'm pretty sure they are buggy but since no one is using them I'm not worried about it.
There are packages on Hex that haven't been updated in a long time but still work perfectly (Canada, for example: https://github.com/jarednorman/canada). Elixir itself doesn't change much... in fact there's no plans for a 2.0 on the horizon, so the fact that packages don't change often isn't a big deal if they still do what they say they do and aren't hurting for more features.
Ooo, I'd also mention that there often isn't a need for a lib. For example, as outlined in The Little Ecto Cookbook, it's trivial to build a small fixtures framework—the API is two one-liner functions! Sure, it's missing a few things, but I've been using it on my own project and have not missed anything provided by dedicated fixtures lib.
> As for libraries, I challenge anyone to name an unmet dependency in Elixir that is 1) trivial to implement and 2) not for some niche application.
For quite some time the ex_aws[0] package was no longer maintained because the only person who maintained it stopped using AWS. There were many months in between before a new maintainer was found. Unlike Python, Ruby, PHP, Node, Go, etc. there's no official AWS SDK for Elixir.
The ecto pagination[1] package has a "low maintenance" warning, basically the author is no longer maintaining it except for fixing issues even though there's a number of interesting features that could be added that other web frameworks have available.
The arc file upload[2] package was no longer maintained or touched for a really long time until someone took it over but now that new package is also racking up open issues and looks like it kind of stagnated in development. This isn't based on looking at last commit times too. I mean there's issues open to address important topics that haven't gotten reviewed for a long time.
There's also no official Stripe SDK for Elixir and all of the community created ones feel kind of abandoned or no where near feature parity with Python, Ruby, Node, PHP, Golang or any of the other official packages offered by Stripe. This is the last thing I want to have to implement myself since it's so critically important. The same can be said for PayPal and Braintree integration. There's official SDKs for Python, Node, etc. but not Elixir. I've asked Stripe a couple of times about an Elixir client and they all say the demand is not near enough to consider creating one officially.
These are only a few examples of tools I've found in questionable state when working with Elixir compared to Python and Ruby. All of which are very important in a ton of applications.
Then there's also less generic but still really useful things like notification abstractions to send emails, texts or broadcast notifications to connected clients. Rails, Laravel and Django all have excellent solutions to this where you can get up and running in no time but with Phoenix you'll have to write all of this on your own. It's a huge undertaking.
Long story short, I started with Phoenix and Elixir almost 2 years ago and today 2 years later I feel like if you plan to write any type of business'y app with Phoenix you're going to have to end up writing a ton of libraries yourself instead of focusing on your business problem. That might not be a problem if you have a huge team and your business idea is already proven and 5+ years old but for anyone who wants to build something and see if it works, it's hard to say you'll be able to build something faster than Rails, Laravel, Django or Flask if you already know one of those frameworks.
Now you might say some of those packages are trivial to write but they're really not. That seems to be a common pattern I've seen with the Elixir community where someone will say just do it yourself because it's easy and then you're left hanging. Sure maybe it's easy if you're Jose or someone with 5+ years of prior Elixir experience and have written 100k+ lines of Elixir code but a regular developer who just wants to build web apps (not libraries) is going run into tons of roadblocks. I know I did.
I don't say this to dismiss your experience, but just to share a counterexample:
I found Elixir extremely easy to learn (despite having no Ruby experience, nor any significant experience in any functional languages). I went through the (excellent) official tutorial in a couple days, skimmed parts of Saša Juric's book, and felt reasonably confident diving in to actually writing code. Within a couple weeks I felt like I "got" OTP and idiomatic Elixir.
I do agree that, at least for somebody who uses Intellij IDEs exclusively, the lack of good first-party support sucks. I do most of my debugging via unit tests and "printf" because the Intellij Elixir plugin's interpreted mode is just too slow for the debugger to be useful to me.
I have found Elixir as a whole to be amazing, but the debugging process to be painful. Maybe its because I'm used to using Chrome's developer tools (since I mostly debug JavaScript), but I really wish that debugging on Elixir could be simpler. Using printf's is just too painful and feels backwards.
I would recommend you learn the dbg module that comes with Erlang. Its a great tracing debugger able to trace existing code in runtime without having to modify the source. There are also several wrappers on top of the Erlang tracing tools, like Recon for example.
> and the ones willing to learn will need many months or years to be productive
That’s interesting. I’ve been doing Elixir for a while and found it almost overwhelmingly simple. As in, I’d do something in a very simple way which would usually take me a lot longer and have to think whether it was actually right because I’m not used to that.
I recently learned Go and I think it was only slightly more difficult to learn than elixir. I could see having trouble if you have never done functional before, but that’s kind of a separate issue. The language itself is tiny.
OTP is one thing that can take a bit of getting used to. But again, I think that’s only for people who are only used to traditional threading methods of concurrency, which is again a separate issue. OTP and the actor model themselves are dead simple in terms of how to use them.
> The editor plugins are terrible, slow, and blow away your CPU doing god knows what kind of indexing
Without even looking I already know what this is. You are using ElixirLS and you are hitting the Dialyzer PLT generation which is needed for type assistance. Elixir LS gives you a pop-up (at least in VSCode) telling you that it's building the PLT and it might take a while. You can disable this if you really want. Most importantly it ONLY RUNS ONE TIME. So, if you've already generated the PLT for a project, it will NEVER run again until you upgrade Elixir or something major. Other than that, I rarely ever see Elixir LS taking up any noticeable CPU.
> Compilation is slow and takes a lot of time
Yes it does. However, you can just cache the _build/ directory in CI. Then it will act like it does locally, only recompiling what has changed and doing it very quickly. Usually, dependencies will not need to be recompiled if they haven't changed.
Also, testing in Elixir is crazy fast and everything runs nicely async by default, even database tests with Ecto.
Could you provide a little bit more context around where it's coming from so I know how to interpret it?
Are you someone who recently joined this company and is now having to learn Elixir? If so, are you finding it difficult? Has it been taking you months or years to learn it and still feel like you don't know it well enough? How long have you spent trying to learn?
Or are you someone who knows Elixir very well and has worked at the company for a long time doing Elixir work and you're observing the struggle to find new junior hires that are willing to learn it and finding it hard to teach it to them? It be nice if you could tell us the number of years of experience you have with Beam and Elixir as well.
Thanks for sharing your experience. I love Elixir, but I have yet to find a way to be truly productive with it. Funnily enough I had a very similar experience with Go.
* It was very hard for our startup to find any Go developers.
* The Go language server would very often cause massive CPU spikes.
* At the time I was using it, the community support in Go was really, really bad.
I'm sure things have changed a bit, but there are always growing pains when choosing a niche technology.
Probably true for you and your team. Definitely not true if you fully grok all the advantages of the BEAM. Elixir is much faster to prototype modern web apps than alternatives and then also naturally seques into scaling if the need happens to arise.
Just curious, what is your company moving to, and are you far enough into the transition to verify that productivity and retention are better with the new language?
Salaries are actually pretty good. Not facebook salaries, but good enough and certainly above average. The company can already get very proefficient, experienced developers in Ruby and JavaScript.
> moving to a better company?
I certainly could. But how does this solve the business problem I'm talking about?
The reason I'm not moving to another place and instead helping transition back to normality is because I actually like the company, and my coworkers, and I like to focus on building our product and solve the real problems the company was created for.
Elixir can be a great tech (the best) for certain kind of problems. In our case (and any other "CRUD" like web application like 80% of the internet) is an expensive, distracting toy.
So, totally disinterested question, can you name those companies paying well for Elixir in Europe? :)
Otherwise I agree with a good part of your post. For CRUD work I feel way more productive with PHP/Symfony than with Elixir/Phoenix, especially for outputting HTML. Part of it is the DX with the templating and type hinting but also the unbeatable amount of libraries and manpower behind the language and framework.
Otherwise the plugin for Jetbrain's IDEs works OK for me (but again it can't beat the Symfony plugin with PHPStorm features).
I'm building my first non-toy app in LiveView. I'm blown away by how quickly I can move with it and love how Phoenix encourages DDD practices.
I'm a bit saddened that Elixir isn't bigger than it is. It's such a great entry into the world of BEAM and functional programming yet I've read more than once that people aren't interested because "it looks like Ruby and I don't like Ruby". There are some more legit reasons as well like it's dynamic, but I wish people would stop getting so hung up on syntax and actually focus on what the technology can do.
What turned me off about elixir was not the syntax, it was the flexibility in designing new syntax. It felt like each library had its own idioms and syntax rules, which just adds a huge amount of variety and difficulty in a codebase. It was hard to have consistent architectural patterns across a team. I've seen an elixir/phoenix backend rewritten completely in python/django and it was a big improvement in developer productivity. I think elixir may work better for small teams. The learning curve and the "consistency enforcement" of languages really does make a difference on big teams.
Can you give an example of what you mean by “idioms and syntax rules”?
I’ve been using Elixir for a long time and I don’t know what this could refer to. Even with macros, all code still has to follow the same Elixir syntax. You can’t actually change that syntax nor can you extend it for the most part unless you are using libraries that are somehow writing their own control structures they are forcing you to use or something? I’ve never heard of that.
Also, if you are just talking about enforcing consistency style wise, there's https://github.com/rrrene/credo which is very popular, and the build tool Mix comes with a formatter by default which can standardize your codebase.
> It felt like each library had its own idioms and syntax rules
This sounds like the way software should be. No? Domain-driven design? Or are you saying that they don't follow industry nomenclature?
> It was hard to have consistent architectural patterns across a team
Is this a symptom of everyone being new the language on the team or the language itself? Elixir is a very simple language compared to Python and Ruby in my experience. There are certainly way more people that have done the latter two. What's comfortable isn't always better.
I'm wondering how aware of the trade-offs you are in using an imperative language as compared to one that's functional. If the nitpick/gripe you're having is around readability and syntax, I'm sure there are enough counters in other languages that you've worked with where the code was just spaghetti and hardly testable
Have you considered that productivity comes more with time? I get the sense that you've worked in a team with very few experienced developers that have either worked with Elixir/Erlang or functional languages. My experience has been that those with extensive experience in OO or imperative languages w/o ever treading into FP have had a much harder time adopting Elixir and it has resulted in slower development early on, but those willing to learn, march much faster after ramp-up.
But if you value correctness, less bugs, and easily testable code, it's hard to beat functional languages in this area, and I'm not even talking about just Elixir
> I've seen an elixir/phoenix backend rewritten completely in python/django and it was a big improvement in developer productivity.
Is this really a better idea? If you're mentioning "consistency enforcement", why not use Golang? Elixir also has a formatter built into its toolchain.
Take my responses with a grain of salt -- because if you're just doing a CRUD app and not buying into what the BEAM gives you from an operational perspective, it's probably not that worthwhile?
As in the whole project was rewritten in Django or some kind of transpiration going on there?
I haven't gotten to the point where I'm adding a lot of libs yet and certainly can't speak to using it in a big team.
In terms of syntax flexibility, Ruby has a similar issue where a lot of popular libs implement their own DSLs. I've never fully bought that that is a problem—a library is going to have an API that will require reading documentation. Maybe the one example that goes off the wire is RSpec (I'm really used to it now but I'm really enjoying going back to good ol' `assert` in `ExUnit`). In terms of keeping it idiomatic with the business logic, library can (and in my opinion always should) be wrapped. I may be missing the point or being reductive here, though, and I would be interested to hear more about your particular pain if you're willing to share!
...and of course if you are talking about using meta-programming to write business logic, that's not a thing anyone should ever do for any reason ever, period (IMO).
For me the raw speed of writing a highly interactive app in LiveView is unlike anything I've ever experienced. My primary experience is with Rails and React.
> In terms of syntax flexibility, Ruby has a similar issue where a lot of popular libs implement their own DSLs.
Of course in ruby, nobody is actually adding new syntax, although that's a common misconception. Ruby DSL's are still just ordinary syntax for method calls and block parameters, there's no new syntax at all. Sometimes it can look like it, maybe because ruby method calls don't require parentheses? But no library truly adds syntax to ruby, they just define methods that can be called.
I am not familiar with elixir, I am curious if what we're talking about is an ability in elixir to truly add new syntax, or something more like Ruby so-called "DSLs".
Correct. You can't add new syntax to Elixir either.
FWIW, the meta-programming models are very distinct. Elixir's is based on AST and it works at compile-time (like Lisp but without reader macros). For example, imagine you want to do your html markup in Elixir, you could do this (but don't!):
html do
title "hello world"
body do
...
end
end
In the above, `html` would be a macro that looks at the structure of the code and transforms it into something at compilation time. The macro must exist before being invoked and it has to literally surround the code it changes. Once the code compiles, you can't change it.
Ruby's meta-programming is runtime-based. So the same example above would likely be implemented by calling methods on an object, either pre-defined ones or using method_missing, as you execute the code. In Ruby you can also define (or redefine) methods at any time and it affects the whole runtime.
Both languages also have a similar ability to meta-program a class (in Ruby) or a module (in Elixir). Think Rails' resource macro in a router. But Elixir modules are closed, in contrast to Ruby classes. Many times this is what people refer to as DSLs, even though the term DSL in itself is more general. Python has similar abilities too.
PS: you are certainly aware of the Ruby bits but I went for completeness to be a reference for others. :)
> Of course in ruby, nobody is actually adding new syntax, although that's a common misconception.
This is the argument I usually use for anyone who has a problem with it yet if they've already decided they don't like it, it doesn't do much to pursued them. On the other hand, being able to rewrite operators in Ruby does take it a bit in that direction—While not strictly new syntax, changing the meaning of an operator can really throw people off. As an example in the standard library, there is `Dir[]`. `Dir[]` is a shortcut to `Dir.glob`. Sure, it's technically doing some kind of access, but everyone knows it as hash access and certainly aren't accustom to passing a pattern to it. Elixir libs do stuff like this.
And I'm sorry, I don't know if can actually add new syntax in Elixir, but you can certainly change the meaning of existing syntax (as in Ruby).
Yes there is a formatter built into Mix, the Elixir build tool. There is also https://github.com/rrrene/credo which is not as extensive but does the same thing as ESLint.
That's the exact reason why I won't be doing anymore Ruby development and haven't for almost 2 years. It's an awesome language, but everything's got to be a DSL and metaprogrammed with those people. Eventually I realized all that added complexity isn't worth it, though I suppose if it makes your company depend on you if you're the only person who understands the Eldrich abomination you've written.
Great post, Elixir has come a long way but more importantly had a great foundation to build on out of the gate. One of the best maintainer communities I've seen for a language + framework in a while. Such a strong + clear open source vision set on building a flexible and robust platform/language. Ty Jose + Chris!!!
Very proud to have been using Phoenix + Elixir for our startup, https://www.distru.com, since day 1 and it was one of our best stack decisions. The language is so pleasent to code in, brings functional programming concepts, can do powerful things with GenServer, has great default performance, and enables us to tackle concurrency problems in a way rails just wasn't built for.
Can't wait to continue meeting great Elixir devs as we grow :). If any devs are interested in working on a cannabis startup built on Elixir since day one, I'd love to talk. blaine@distru.com
Learning Elixir and starting to use is in projects is at the top of my TODO list for 2021. I tried to get into a while back, but being unfamiliar with functional programming concepts at the time really got me. Learning a new language and trying to grep FP at the same time was too much for me :)
Now, I'm more well versed in FP in general, and I'm excited to give it another go! Everyone I've talked to who uses Elixir on a regular basis or professionally absolutely gushes with excitement and joy when they talk about it!
Elixir's tooling is so good. The documentation is readable by a human, you can jump in and get information at any time. They focus on the developer experience, and it's one of the most compelling reasons why I love the language/ecosystem so much.
Last year, I deployed a system consisting of 4 Elixir applications, and recently added a new one built with LiveView, which took 2 days to write (1 of which was more of a learning day). I also built some helper services that are used in other projects. Phoenix nicely fits the microservice as well as the full-stack use-case.
LiveView is a bit of a game-breaker for me. Most of my job is writing CRUD apps and you just can't beat LiveView on that turf. Unless you have some super complex interactivity in your app or are a unicorn planning to scale to infinity, I don't see a reason to use another stack. If the web weren't so terrible and just plain old, we could have even better solutions, but this is the best for now.
I've picked up Elixir in 2016 and have started freelance work around 2017 doing Elixir and Phoenix exclusively. For me it is the best platform for web development and I'm very grateful to everyone involved (erlang/otp, elixir, ecto, phoenix teams and everyone else).
Congrats to José and the team! Elixir was a wonderful discovery for me a year or two ago — it's the closest I've found to my "ideal" language. You can tell, from the documentation and by using the language, how much thought went into each design choice.
Nice little retrospective. I’ve been using Elixir and Phoenix both for personal projects and in production at Househappy since 2015. It’s been nothing short of wonderful and to this day it remains my favorite programming language and ecosystem to work in. Congratulations to José and the rest of the core Elixir team for this milestone!
Congratulations to José and the entire elixir team, I find elixir to be a language which makes me incredibly happy as a developer, and I look forward to using it for another 10 years.
it looks really awesome! Can someone point out the negative sides (or drawbacks of any kind) ? What about finding elixir experts/freelancers? What about integration with .Net and the xamarin forms ecosystem?
1. no static typing. With typescript having taken off, and now even python and ruby becoming more and more feasible to use in production with static typing, switching to a new dynamic language is a hard sell for me.
2. limited ability to take full advantage of some of its unique features in many cases. The runtime and the included OTP library/paradigm has some really cool features with its approach to processes and concurrency with the actor model, and features like hot code reload. But IMO the industry and popular best practices have evolved in a different direction that make these things less compelling. Code deploys are a solved problem in any of the major vm/container runtimes, with blue/green deploys, canary builds, feature flags, etc. all quite easy to use, so hot code reloading isn't that compelling as a language feature anymore. There are tons of ways to orchestrate multiple instances of a services from Heroku to Kubernetes, and APIs built on Protobuf and GRPC, GraphQL, or json REST APIs, are now pretty standard for communicating between different services, or using message queues, kafka, cloud pub/sub, etc. Also the paradigm most developers are familiar with is stateless app servers that store any state in database or cache layers, which has a lot of benefits.
Erlang and OTP seem to kind of mix all of these paradigms together, and if you use all of its built-in ways of doing things you are really striking out on your own from the common "best practices" that more developers these days will be familiar with. A lot of common tooling and cloud hosting providers don't support Erlang OTP style programming natively. It can certainly be used successfully, I believe Whatsapp as one famous example was originally all written in Erlang, but I personally don't see a whole lot of justification for most apps to do this. Of course you don't have to use any of these features, but then why use a language if you're not going to lean into its unique strengths?
> limited ability to take full advantage of some of its unique features in many cases
Honestly, this shouldn't count as a downside. :) The way I frame it is "in the worst case scenario, you can deploy Erlang/Elixir as you would any other language".
You don't need to use distribution, you can still build stateless apps, etc. And yes, almost nobody uses hot code swapping!
However, whenever you need a specialized solution, such as quick messaging between servers, proper concurrency so a slow upstream server doesn't kill your app, etc... you have that at your fingertips!
Even if you are not using any of that in production, you are still leveraging concurrency when compiling code, running tests, etc. It really makes a large difference! And if for some reason you cannot leverage any of that either, the languages are still great on their own. Pattern matching and immutability are a joy, developers feel productive within the existing frameworks, and so on.
My car can go 260km/h but I never went past 140km/h (speed limit where I live) and I still love it (the best car I ever had).
static typing is what drew me to go, Elixir isn't a static-typed language, but there are plenty of guardrails in the language that make up for it. Pattern-matching, guards, good compiler messages, casting, etc.
You've also got fantastic testing framework, and good conventions like tagged tuples {:ok, x} vs {:error, y}.
On top of all of that, you've got the Erlang underpinnings: immutability, crash-fast, app umbrellas, etc.
It's a very safe language to develop in. I don't miss the strict static typing at all.
> limited ability to take full advantage of some of its unique features in many cases. The runtime and the included OTP library/paradigm has some really cool features with its approach to processes and concurrency with the actor model, and features like hot code reload. But IMO the industry and popular best practices have evolved in a different direction that make these things less compelling.
Think about it this way. You already reap a lot of benefits by just handling requests with Phoenix. Pre-emptively scheduled light-weight processes that does not have to run GC in most cases is already a huge win. Don't you think?
You certainly don't have to be 100% buy-in in every single OTP or Beam feature. Really. Actually, it makes sense to do things "the old" way when you feel more confident about them.
> 1. no static typing. With typescript having taken off, and now even python and ruby becoming more and more feasible to use in production with static typing, switching to a new dynamic language is a hard sell for me.
While it's true that Elixir is a dynamic language, there's much less "magic" compared to Ruby or PHP, the language server has good autocompletion and warnings.
Yeah, I can't really tell if the overall community will adopt it or not, but you may well be right. Last time I commented something about ruby not having static typing I got downvoted by people claiming Sorbet is already used heavily in production.
But either way if I'm switching off of ruby, I don't really want to go to something else that doesn't have static typing.
A few huge companies like Stripe use Sorbet. Thats really not a good representation of Ruby users though. I guess youre right, for dynamicism Ruby is awesome but if you need types just switch to a true typed language.
I've been involved in interviewing for Elixir positions and found that we got more senior candidates than I've ever seen before. Part of it might have been pandemic displacement. But I'm not seeing a lack of work in my freelancing and I'm not seeing any particular skill shortage.
.Net and Xamarin integration. No clue. Samr as for any other non-.Net language I imagine.
I've never seen anyone complain about this, so maybe I'm alone, but the runtime error messages are absolute garbage. Especially if you get an unexpected nil that bubbles up, you'll often see cryptic erlang messages that don't really identify what went wrong. (Think type errors that don't identify the expected type nor the type passed.)
And by that same line of thought, it's frustrating as a functional language given its almost complete absence of built-in monadic types and helpful sugar to use them. Instead of `Maybe`/`Option`, for example, you pass tuples around tagged with atoms. This wouldn't be the end of the world except that...
There's no static typing. Which means that `match` blocks can't enforce completeness. This isn't a huge deal, but for a dynamically typed language, it's surprisingly cumbersome to introspect at runtime. Languages like Ruby make such things first class, such brings me to...
Elixir is nothing like Ruby. With the exception of `def`, `unless`, and `do`, there are nary a few similarities. This isn't necessarily a negative, but the whole notion that Elixir and Ruby share syntax is only barely—and completely superficially—true. In large part, this is because...
There is no method-style syntax. That's not uncommon for a functional language, but it's problematic when the standard library is hugely inconsistent. Is the function you want in the `List` module? Or the `Enum` module? Or is it part of the `kernel`? Hunting around for the right module is a pain, but not as bad as...
Inconsistent naming of functions. Sometimes they're fully spelled out; other times they're abbreviated. And if you're really unlucky, if it's in the kernel, you can expect 1970's Unix-style abbreviations that are so short to be unreadable and have no consistency in how they're formed. US state abbreviations follow more strict rules than Elixir kernel function names. At least one thing Ruby got very right were easily-guessable method names.
There's a lot of good in Elixir; don't get me wrong. But I've spent over a year in it and keep stumbling on very un-aesthetic issues. For such an otherwise wonderful developer experience, these pain points ring loudly.
Frankly, unless you need a lot of parallel things to happen behind the scenes in real-time, I just don't see much use case for Elixir. Its ability to fail and keep going (a major selling point) is great, except that I find it too easy to write code that fails, which can bubble up and create inconsistency in its state. I much prefer something that will help me avoid failure in the first place (Rust us great for that), or something that lets me code fast and loose and makes that experience really enjoyable (like Ruby).
I think I'm alone in these criticisms, however, because I never really see anyone talk about them, so take this all with a grain of salt. I have used a ton of languages in my 25 year career, and I had a lot of hope for Elixir. But, frankly, I just don't get it.
For highly parallel networked applications, it makes sense. For very small things that would otherwise need external service dependencies (Redis, sqlite, etc), it makes sense.
But if your focus is any other use case, I really struggle to justify its adoption. It's not as fast as advertised for anything non-realtime parallel. (Go, Java, Rust, et al all provide much faster alternatives.) It's not as quick to whip up for medium sized projects. (Like Rails.) And it's not as fault tolerant as something like Rust, which can help you avoid the faults in the first place.
LiveView—the latest "must have" for web development—is likewise disappointing, in case that intrigues you. Single-language back- and front-end development sounds great. But it's just back-end streamed to the front end, which is problematic for any significant latency. None of the benefits of front-end except not refreshing the page. It's a fun (and very impressive) toy, but you get almost none of the benefits of a real front-end app. (Such as UI changes while the data is loading.)
While I only have a little experience with LiveView, I have plenty experience with latency-laden server-side echoing to know that when it breaks down without the client doing its own best-guess updates, nobody will have a good time.
Maybe I'm just salty because I expected the Elixir experience to be more than it turned out to be. And I do enjoy some of the things it forces you to do, by virtue of its being a functional language. But at the end of the day, I personally find its warts to be significant and not worth dealing with outside of very specific use cases that it uniquely handles very well.
Your mileage may vary, but I would ask yourself: does my application needlots of real-time, parallel functionality? If the answer is anything short of "hell freaking yes!", then I would look elsewhere for serious development.
I appreciate all the hard work Jose and Chris (and of course all others) have put into their respective portions of the Elixir experience. But I think it was oversold. And I think the number of packages that haven't been touched (or issues responded to) in over 3 years may indicate that others struggle to find its value in many areas in which it was advertised to be a game changer.
Elixir is a fantastic language. I wrote an app several years ago and haven't had to update or do any maintenance on it since and it has happily served several million requests a month without errors. Actually the only reason I've touched it is to upgrade the Heroku stack it is on. The best part is I actually had a lot of fun writing the app and even writing the docs. So much of my preference for Elixir is in the developer experience and how quickly I can ship changes with high confidence; all of the amazing performance and distributed aspects I may never need for my projects.
Great read. Two days I wrote about my own experience learning Elixir to build Xkit[1]. As I wrote there, the language guide is one of the best I've ever seen and is pretty much all you need to get started.
There are drawbacks of course (typing, deployment) but the pros far outweigh the cons for me so far. Here's to the next ten years!
I've been loving Elixir for the past 2 years now (off-and-on). I try to build most of my personal projects in it (as I'm still trying to get better at it)
My latest project is a Discord bot library written in Elixir, seemed like a good fit as the Discord backend is written in Elixir as well
My only complaint is IDE support, though VS Code works well enough for me (and for HTML I use Webstorm, as I find the Jetbrains Elixir plugin is a little better for EEx)
Celebrating my sixth year with Elixir! The adoption rates here is still quite low (Malaysia) but I'm glad to say that onboarding new Elixir developers has always been a breeze.
Sometimes I think to myself, why bother to submit things to HN? Everytime I submit something (and recheck twice I am first), nothing happens... until someone else resubmits the same thing.
I submitted this one 2 days ago when it was fresh.
There is an art to it, and I just got lucky. I saw someone had posted it yesterday and it got no attention. I reposted it in case it went better and it did.
Usually HN doesn't let you repost, but in some cases it does if the original article flew under the radar and didn't get much attention.
As an Elixir fan, I wanted this important milestone for the language to get more than a couple points.
The article was published earlier this week and I have a quick addendum: regarding Erlang/Elixir, my goal has always been to bring new developers to the platform. After all, Erlang developers already have the most important part of Elixir, which is the Erlang runtime!
There are also key people in both communities working hard to make sure the tooling is consistent across all languages. A lot of this effort happens under the Erlang Ecosystem Foundation (https://erlef.org/) too.
All to say, regardless if you pick Erlang or Elixir (or Gleam, LFE, etc.), I hope you will fall in love with the platform as much as I did 10 years ago!