- Web development with Phoenix and Liveview is immensely enjoyable and fast
- AI with NX, Axon, Bumblebee
- Audio and Video streaming and manipulation with Membrane
- CQRS and Event Sourcing with Commanded
- Embedded with Nerves to make your own devices
- Mobile apps with Liveview Native ( in development )
- Queues, pipelines and batch processing, etc... natively or with GenStage, Broadway or Oban depending on your use case
but for me, the killer feature is IEX, Elixir's REPL. Being able to interact directly with my running code easily ( in dev or in production ), introspect it, debugging it, is just life changing.
Adding types is indeed the last piece to the puzzle to bring even more confidence in the code we ship.
- ExUnit for incredibly easy tests
- Hex package manager that just works
- FLAME for the ability to scale different processes to different computers with nearly 1 line of code (the whole library itself is just a few hundred LoC if I remember)
- Ecto for interacting with SQL databases in a functional manner (I still never know how to feel about ORMs, but I was able to write a few composable queries and get rid of 90% of my SQL, so I'll call that a win)
After months of struggling with deployments, uptimes, segfaults, package times, etc I moved my webserver & data layer over to Elixir + Phoenix. It's more well tested than ever, so much easier to reason about, I trust it will scale, and deployment was a breeze.
Because of convention over configuration, I was able to get up and running _insanely_ quickly with Phoenix (way more than FastAPI). I really wish I did this months ago.
Now I'm training models in Nx, playing around with Bumblebee/Livebooks, and adding presence/live functionality to my app for nearly free.
Quick suggestion, it would be nice if the landing page [1] has more information or links to actual examples of how to use LiveView Native. That page has not been updated in a long time and give the (misleading) impression that the project is on hold.
This is the hard missing piece for me and why I'm looking curiously over to Gleam. Coming from a language with a very powerful and useful statical typesystem, I just can never go back to something like Erlang or Elixir in my life. :-(
Having a good REPL just removes so much of the friction you normally have to contend with in programming. You can build up ideas piecewise and test things as you go, instead of having to make guesses and run the whole damn app just to poke some troublesome piece of code. The Elixir standard library is great, and it's extremely easy to access the docs via the REPL, which I find really helps me stay in the flow. When I'm coding in Elixir, popping over to a browser window to search small questions is pretty rare, because I can usually find the answer without leaving the REPL. This also encourages me to write good docstrings for my own code!
But it gets even better, because you can run the REPL while also running your code. I mentioned above having to "run the whole app to poke a piece of code" - when you find yourself needing to run the app, you're welcome to, and you can manipulate live data (in dev, of course ;) ) and inspect what's going on in ways that you either can't do or need a debugger for in other stacks. And now, with the introduction of some typing facilities, I expect the tools to get even better.
Then there's all the fun and power of the functional paradigm while still having extremely robust ways to deal with mutability and state, and not having to deal with the syntax of LISP (sorry LISP). It's a language that just hits every note for me, I'm a huge fan.
Comping from a LISP, the Elixir REPL really is not world-class. It's a really far, distant second. It's nice, I enjoy it more than python's personally, and more than what I remember from irb back in the day -- but nothing beats the integration of structural editing and nREPLs.
LISP doesn't have to be for you, but there's still a lot to learn from that REPL experience if the Elixir community wants to grow ;)
Don't many other languages have this? Ruby has IRB for example. Is there anything IEX does that IRB doesn't?
[0] https://hexdocs.pm/iex/1.12/IEx.html#module-remote-shells (the remsh flag)
As with many things Elixir/Erlang related, there isn't a lot that's unique and not seen anywhere else. It's more that the pieces are carefully thought through and come together to make a fantastic whole.
You have to search through libraries to find out which one is being maintained.
For example if you want to use an OpenAI API client, you wouldn't want to use the most starred one because that hasn't been maintained in 7 months.
If you just use Python you get to use the one maintained by OpenAI. Using a language like Python, JS, Go ect. you almost never run into this problem because libraries are usually maintained and aren't abandoned and if they are there are usually enough users that a fork appears.
So yeah Elixir has great uses, but is it worth the possible future headaches of having to maintain a bunch of libraries to get your app going? Instead of using Go, Python, JS ect where you can rely on a massive community
Very very few companies build and maintain SDKs for Elixir.
NIFs and small services can often fill the gap if really needed.
If I had to use OpenAI API I would pick my favorite HTTP client and just use the Rest API and write a small wrapper around it for my needs.
This is true with any tech until it gets traction. React/Next is backed by a big company, but Vue/Nuxt still managed to grab its piece of the pie.
In order to get traction Erlang / Elixir needs enthusiasts who are ok with risking and introducing it to their company or product, at least partially.
No offense, but instead of condemning the Elixir ecosystem, why not embrace it in your company or product, as many have done (including me)? I think most devs should be OK with taking a tolerable risk if they see opportunity to increase productivity by N times
I've never been more excited about a release. I've been watching commits to both Elixir and OTP for awhile now and I feel Elixir/Erlang has really picked up steam.
Thanks to everyone involved for making my life easier!
I wish Elixir was able to decouple itself from LiveView in a sense in the minds of developers. Even without LiveView and realtime/channels, just using Elixir as a backend for a simple API has been really fun.
Now it would be awesome if rabbitMQ and its client would run on OTP 27, would love to upgrade :(
I'm absolutely certain the real time processing would be unfeasible in any other technology in terms of complexity and the minimal compute resources it's running on.
Modules like broadway, ash, oban, phoenix liveview ... make it not just a pleasure to work with but insanely performant.
With over 20 years of programming experience, I can say with certainty that there is no language that makes me as productive as elixir. It's at least 10x my python productivity (despite being at an expert level in python as well).
We've used the SSL cert client login method for years, and have been very happy with the reliability.
Cheers, =)
By the way, you hear a lot about the BEAM and it's power - but in my experience you can go a LONG LONG LONG way before you ever have to even think about that part of your stack. Phoenix does such a tremendous job abstracting that for you. You just get the gainz with no effort. Other parts of the stack also just abstract that for you.
Case in point: Oban. You get powerful, flexible and easy to use background jobs for essentially free. Right there in Postgres, with your Elixir code. It's crazy.
Try it.
Writing robust LiveView flows, and testing them well, is exactly as intellectually complex as writing stateful genservers with multiple non-linear flows and various call/cast entry points. LVs use different jargon and have small convenience layers like async-assigns, but mechanically genservers are literally what they are. I'd say that's crucial to understand well if you want to use them effectively.
Love Oban and miss it deeply in other ecosystems.
In [2], Wojtek Mach explains how the team behind Elixir build Livebook Desktop. He explains how the project started, some subtle bugs found when building the app for MacOS, some limitations of wxWidgets in Windows, and many other implementation details.
It would be awesome if the Elixir team releases something like elixir-desktop based on Livebook. That is, forking the Livebook repo and release an official template project for generating desktop applications based on LiveView. Right now, Livebook is distributed as an executable for Windows and Mac. Why not follow the same approach to allow developers to publish self-contained executables pretty much like Electron?
I am aware of LiveView Native [3] but I think they follow a different direction.
[1] https://github.com/elixir-desktop/desktop-example-app
That seems surprising to me as an Elixir developer. Are you looking in the US, or elsewhere?
And you have to be careful because some of those are
* "Bob wanted to try out Elixir, so now we use it for this one microservice, but we're mostly a PHP/Rails/Java/Python/whatever shop and we'd like to rewrite it one day, because Bob left a few years ago" - places where someone wanted to play with something shiny and new.
* Early stage firms where someone is a true believer that BEAM is some kind of magic scaling bullet or secret sauce.
If `foo` returns `nil`, accessing `bar` won't raise.
get_in(struct, [Access.key(:foo), :bar]) if struct.foo do struct.foo.bar else nil endIf you have decent familiarity with Elixir, understanding Erlang isn't very difficult. You spend 20 minutes grokking the slightly weird syntax and then it's generally just a subset of Elixir. This is of course a bit of a simplification, but it's close enough for when you're trying to understand someone's Erlang code.
I like VSCode fine, but I'd definitely be interested in a Jetbrains level IDE for Elixir stuff.
The next milestone will include a mechanism for defining typed structs.
Interestingly, gradual set-theoretic types are flexible enough to let you gradually implement type inference for that system. Hence, the gradual gradual type system. :-)
https://elixir-lang.org/blog/2022/10/05/my-future-with-elixi...
> We present a gradual type system for Elixir, based on the framework of semantic subtyping ... [which] provides a type system centered on the use of set-theoretic types (unions, intersections, negations) that satisfy the commutativity and distributivity properties of the corresponding set-theoretic operations. The system is a polymorphic type system with local type inference, that is, functions are explicitly annotated with types that may contain type variables, but their applications do not require explicit instantiations: the system deduces the right instantiations of every type variable. It also features precise typing of pattern matching combined with type narrowing: the types of the capture variables of the pattern and of some variables of the matched expression are refined in the branches to take into account the results of pattern matching.
[0]: https://www.irif.fr/_media/users/gduboc/elixir-types.pdf
Gleam uses a modified version of the Hindley-Milner Type system. (Which is a rock solid tested type system.)
A Set theoretical type system is more expressive(which suits the dynamic nature or Elixir better.) You can do Union and Intersection Types, and Negation Types, among other things, that you can't do with a HM type system. but it comes at the cost of how fast the program can be typed.
HM types systems have amazing type inference capabilities and do so at O(n). Im not sure what the time complexity of the algorithm they are using to do the type checking for Elixir programs, but I bet it's more expensive than that. (Which is probably why they are rolling out the type system slowly.)
I doubt that Python's static type hints existing within a formal mathematical framework, but it's interesting that intersection types have been under consideration for a long time now: https://github.com/python/typing/issues/213
And Elixir check types at run-time?
(If at run-time, would that mean it would slow down your entire app as a result?)
> We chose the name “shift” for this operation (instead of “add”) since working with durations does not obey properties such as associativity. For instance, adding one month and then one month does not give the same result as adding two months:
I'm not exactly sure why adding one month and then one month would give a different result compared to just adding two months. Don't you in reality want the same thing? Why is "shift" more useful than "add"?
What's two months after Jan 31? Mar 31.
Maybe you think it should behave otherwise, but they picked a way and changed the name so you wouldn't think of the addition operation and its expected properties.
I once wrote a billing system for my own small business. If the customer signed up for a monthly plan near month end, on a day >= 28, their next billing date was always on the 28th to keep things simple.
https://indiecourses.com/catalog/build-an-mvp-with-elixir-6i...
I just can't do liveview. I have a very hard time grokking it, and it has a lot of footguns. (ex: if you need to remember to perform auth checks both doing a `pipe_through` in a router and using the `on_mount` callback in a LiveView, see [0].)
In fact, the fact that the above sentence has zero meaning to a new-to-phoenix-and-liveview dev is proof enough to me that liveview should not be the default way of doing things.
It creates a very steep learning curve where, crucially none is required. elixir/phoenix are easy.
I would even say that the correct learning order for a new-to-elixir/phoenix dev should be:
- Phoenix with deadviews (MVC style).
- "Elixir in action" to learn the basics of OTP. This book is was both easy and utterly eye-opening to me and changed the way I code basically everything.
- Then, and only then, LiveView.
[0]: https://hexdocs.pm/phoenix_live_view/security-model.html#liv...
If you have other footguns in mind, feel to shot me an email at jose dot valim on gmail!
I'd be keen to hear your development workflow for building an MVC style app, what you use for the front end, and how you go about refactoring, e.g. when editing a struct which is stored in the DB and shown in a view is when I particularly feel like I'm flying blind.
Meanwhile deadviews + channels is /miles/ better than python/rails/laravel (imho).
Sure when I need to write a REST route + its consumer in the client I die a little because I know that's the part I could have avoided...
Saying this as a die hard Elixir fan who's been using it since 2015.
> decouple itself from LiveView in a sense in the __minds of developers__
This isn't a technical knowledge issue or if a given technology should be the default on install. Assuming I understand your original post correctly this is a mindset issue: too many people dismiss Elixir and the rest of the ecosystem because the first thing they think about is LiveView while ignoring the rest of the ecosystem and that's a shame, because it's much more than that... and I would agree with that point. Even Phoenix is more than LiveView.
It's possible to have solidly productive, cost effective Elixir applications not involving LiveView or even Phoenix for that matter. The choice of Elixir in the backend should be more common than it is, though I understand some of the conventional wisdom and fears that motivate other choices.
ElixirConf 2023 - José Valim - The foundations of the Elixir type system
Cf. Castagna's et.al. For semantic subtyping.
I love LISP in general - was a big Clojure fan for a while - but I feel like Elixir threads the needle of usability much better for me.
Anyway, I'll stand by my claim - Elixir's REPL is leaps and bounds better than Python's, and better than irb and pry by some smaller amount. It's a pleasure to use. I would love to see a world where I can send expressions for evaluation to the REPL as easily as you can with LISP. Maybe we'll get there someday!
The Observer, :observer.start(), is another very nice tool. Might require some widget libraries for the GUI but you'll likely have set that up on the machine you're doing the introspection from.
It's also very hard to be as concise with more vanilla syntax when competing with put_in/update_in instead. The pattern and ability to generalize it is valuable IME.
For sets it's usually recommended to use Elixir MapSet. There is a Queue-wrapper around the FIFO-queue in OTP as well. For fun and learning you can also implement your own queues, or things like process pooling around the tooling already available.
(mostly joking, if anyone is actually interested in ML, NLP, and Elixir, I have more pragmatic reasons for switching. Feel free to get in touch)
Whether it works for you really depends on your needs. I always hear the offline tradeoff but for most businesses it's not a deal breaker. What % of websites do you use every week where you expect it to work offline?
But for non-production single nodes I just created a Dockerfile and deployed it because the other options were too much hassle. Can't remember the details, but in my (in)experience, deploying was always the hard part with Elixir.
I will need to try it again, it's been a while and the ecosystem has improved dramatically in the meantime ... and it was already excellent before. Good stuff!
I think you'll find that my argument ("LiveView shouldn't be the default way of doing things") is fairly common.
It's not necessarily about the footguns (or lack thereof), or improving the docs: it's about there being a shared vocabulary among people that do web development that LiveView is alien to.
Web frameworks have historically been great tools to drive adoption of programming languages (Ruby/Rails, react/ts). The same could be true of Elixir.
However, in order for that to obtain, the learning curve can't be too steep, at least in the initial portions of it. I think you'll find that with LV the learning curve looks like a step, and imho that step is a bit too high.
Of course, all these arguments apply both at the individual level and the company/org level. Think about a new hire's time-to-productivity if they first have to learn elixir, then phoenix + liveview vs just elixir & MVC phoenix.
If there's a way I could contribute to an effort that helps people learn elixir sans lv--perhaps writing, sketching, or even reading a guide/documentation--I'd be happy to give it a crack.
We should always improve the learning curve, regardless of its steepness! Any work in this direction is always welcome. I don't have anything in mind at the moment but if you do stumble upon anything, feel free to PR. :)
But what you wrote matches my understanding. I have some routes that are pure LiveView and some that go through controller routes with HTML, and it was clear to me where I needed auth when I made them.
Each liveview is an isolated process. You can easily inspect this in the process tree with the phx dashboard that is bundled. State & messaging is certainly the hard part to grok with the beam. I found elixir in action to cover these concepts very well and nothing has really changed since it's first release.
Your experiencing trying to follow data through Phoenix is the complete opposite than what I had when I picked it up many years ago. The request response cycle is pretty straightforward to follow being a struct piped through the endpoint. Liveview isn't much different. Breath of fresh air for me really. Coming from a year or two studying rails which is a nightmare in comparison with all the metaprogramming.
While I do think you can be productive in this stack without knowing much about the BEAM, just taking a week or so to get to know it will pay dividends. It's a paradigm shift compared to a lot of what's out there -- but isn't one that I found difficult to grok as a new developer in the middle of my CS undergrad at the time. Many of my friends shrugging it off for python found their way to elixir eventually :)
In any case, thank you for your work.
Elixir has been around for 12 years now and still hasn't gained any meaningful traction.
The risk of using Elixir vastly out ways the benefits today if you are trying to build a product.
There is a reason why almost every product today is built using JS and Python because it easy to find developers, it's easy to find everything you need, almost every service supports it and there are tons of resources for it.
We switched for Elixir to JS and we only have to maintain the app itself. We have hundreds of OSS helping maintain the libraries we use most of them working for companies that the libraries are for. That's the massive advantage of using popular languages that everyone uses.
Elixir is a fun language but that's about it.
Packages depending on packages not maintained or containing security issues.
I don’t know how many times Next has released broken updates without any mention of it in their change log and then you find a GH issue where it’s essentially “works on vercel hosting”…
Easy to find developers is often touted as a plus, but the process for making sure you get the right ones are scarce, and JS code bases almost always ends up as complete spaghetti as a result. As someone doing JavaScript for a very long time my statement is that it’s one of the hardest ecosystems to get right and it requires exceptional developers to do so, unfortunately it’s also where many start their journey and without exposure to other technologies becoming great at it is very hard.
The fact that I can do `mix hex.outdated` and get a code diff on dependency changes makes me smile every time, compared to the insanity that is updating npm packages in any sizeable project with hundreds of updates weekly.
Similar thing recently, there was an obscure Scala version mismatch error when trying to use it with spark. (Not that significant of a problem).
It is definitely a headache trying to cope with the conditions till we get better especially with smaller teams who can't afford to fork and maintain something. A
I've worked with a wide spectrum of type systems and none of the things that caused issues for me due to typing in large JS or Ruby projects ever did in Elixir. The schema-based structs and pattern-matching make a huge difference. I don't feel quite as confident of a poorly tested Elixir code base as one written in Rust, but I'd take it over one written in TypeScript or Obj-C any day of the week.
https://phoenixonrails.com/blog/you-might-not-need-gradual-t...
That's often not the limiting factor though. Elixir makes it very easy to have excellent parallelism on your work so you actually take full advantage of processor. The design of the BEAM means that things are naturally quite low latency, and often you lose performance due to just waiting for things (this characteristic is why webservers on the BEAM are pretty fast).
The other key aspect is NX - like ML libraries in Python, Elixir is just orchestrating and the number crunching is done in C libraries or on GPU etc.
Compared to squeezing performance out of multiple cores with the JVM it's absurdly convenient and consumes way less RAM. I have two reasons for still working with the JVM, multiplatform desktop GUI and high quality PDF libraries that support rather low-level aspects of the standard that I need. It's kind of obvious why these things aren't readily available on the BEAM, though.
(Spawning an asynchronously yielding C# task is ~100B of allocations depending on state machine box size, with very small overall overhead and threadpool handling millions of them, they are cheaper than Elixir tasks which make different tradeoffs (and are subject to BEAM limitations), you can try this out on your machine by running the examples from this thread: https://news.ycombinator.com/item?id=40435220)
There are no plans for runtime checking AFAIK
For instance, without even introducing annotations, if a function head has a guard `is_boolean(x)`, using the + operator on x within that function would lead to a type error.
If not, maybe it's hard to understand where I come from. On top of that, people are different. Maybe Elixir is the right thing for you, but still not for me as I'm more prone to typos and such kind of small errors.
I recommend reading Giuseppe Castagna's work for those who want to dig deeper: https://www.irif.fr/~gc/
I’m sure I’m missing something as I have no doubt you’re by far more knowledgeable than I am, but TS also represents types as sets (semantically, dunno about internal implementation), structural typing seems to inherently map to set theory
For example, about bounded polymorphism the article says “Of course, we can provide syntax sugar for those constraints”: seems like this sugar could be ‘a extends number’ to me, like typescript does. I don’t see how TS does _not_ map to set operations
It is fair to call both TypeScript and Elixir as set-theoretic type system. The big difference is that Elixir's implements semantic subtyping. Here is the paper you can use to dig deeper. I hope it helps: https://www.irif.fr/~gc/papers/lics02.pdf
If Elixir can pull off soundness without compromising expressivity that will be a huge feat, and I'm excited to see it!
[0] https://www.typescriptlang.org/play/?strictFunctionTypes=fal...
That being said, I don’t think it’s possible to “pull off soundness without compromising expressivity” because the expressivity in this context is self-referential types which equate to non-terminating unification logic (and thus, unsoundness). Still, I’m excited to see what they do with this type system! Reminds me a bit of Shen’s type system.
(Edit: to be clear, allowing to refine function types in the way they do is part of the solution, the unsound part is that it is not checked afaik)