No offense to TFA author, but I don't think this is doing to sell Elixir to Python people. In fact, I have serious doubts as to whether most Python lovers would be willing to set aside their beliefs and practices to learn the Elixir way.
Perhaps Phoenix and LiveView will be the gateway drug, but even to reach that point requires a lot of effort to understand functional programming and Elixir.
Python has some functional capabilities, but in my experiences with Python devs, those are little used and even shunned. Imperative, mutating loops are the Python way; and to suggest otherwise is to hear "But why would I need that? This (long functions with mutations everywhere and loops) is fine."
I went from Ruby to Elixir, and even with my basic Clojure experience, it was an effort. It was worth it, but I think the apparently similarity of Elixir to Ruby is actually a negative. They look awefully similar, but their use is vastly different.
As for Django vs Phoenix, I would argue that Phoenix has a much cleaner story for doing everything that Django can do and more. People promote Django for the "batteries included" aspect, which mostly just means "I get free user/auth system and built-in scaffolding for my CRUD." But those are things which are very easy to add to Phoenix (and Rails, which Phoenix is roughly similar to). Yet people choose Django for these little freebies which almost always get thrown away or ignored in real production worlds. For a quick proof-of-concept, it's nice. But for real projects it doesn't add value enough to offset the crufty boilerplate OO-centric code that results.
I've got experience in both Phoenix and Django and I disagree.
In my view, Phoenix is the less clean one: Django does not generate anything through scaffolding like Phoenix. Your CRUD (and auth and forms and everything more or less) is generated by overring the built-in Django classes or the classes offered by the packages. Nothing gets thrown away in real production; you use your class hierarchy to change it to your requirements. I know that inheritance and polymorphism seems like a 90's technology but this actually is a solved problem in web frameworks and does work excellent.
On the other hand, I agree with you that everything that Phoenix generates through its phx.gen generators are for demo purposes and will get thrown away eventually. This, along with the fact that everything is a function results in having to re-invent the wheel multiple times in your project without any saferails on how to actually architecture it. Should I use a context? What to put there? What's the point of views? Oh views are removed now? So, unless you are really very careful or have much experience/guidance this will result to a total mess.
The batteries included aspect of Django means that if you are a novice developer and follow the best practices you'll get a fine project without too much effort. It isn't really about the batteries, it's about the fact that you'll know how to implement each thing you need in a web project. I can confirm to that that because we've got 12-year old production running Django projects which were developed by a totally novice Django developer (me).
Try to do that in Phoenix (still being a novice developer).
Now I don't want to abolish Phoenix. It's a fine framework considering its age and its popularity and number of people contributing to. However you must be very careful before considering to use it for a real project that will be used and supported for the years to come, expecially if your alternative is something as proved as Django. Personally, I use Phoenix only on projects where its real-time capabilities will be the protagonist.
> Django does not generate anything through scaffolding like Phoenix
I was one of the co-authors of Devise, which is an integrated authentication solution for Rails (similar in spirit to Django), and you will easily find people who swear that the code generation solutions are miles better. That’s because eventually they’d want to customize how the framework or library work and then, instead of simply being able to change the code, you need to find the exact hook or configuration to get the behavior you want. Eventually, you end up with hodgepodge of changes that you can only understand when looking at the framework and your code side-by-side.
Perhaps this is one of the topics where there is no “superior” answer, besides personal preferences and past experiences. I totally understand why someone would prefer Django or Devise, but our premise is that eventually you will want to customize it, therefore giving you control upfront is the better way to go about it. However, I would say it is incorrect to say they are for demo purposes in both Phoenix and Django cases, as there is plenty of evidence otherwise.
It is also a matter of framework philosophy. Phoenix aims to give all the necessary foundation for building applications, and then not get in your way, rather than owning all aspects of your application lifecycle. I believe frameworks like Ash (which also runs on Phoenix) take the latter approach.
> Oh views are removed now?
To clarify, Views are not removed. Phoenix is still MVC. The difference is that the templates in your view are defined via `use Phoenix.Template`, rather than `use Phoenix.View`. You can migrate (or not) at your convenience.
> “On the other hand, I agree with you that everything that Phoenix generates through its phx.gen generators are for demo purposes and will get thrown away eventually.”
The parent didn’t say that and it’s not true in my experience writing Phoenix apps over the past six years. I usually add to the generated contexts, controllers or now live views, but I often leave the migrations as is. Even when making a migration to edit an existing schema, I still use the Ecto generators. The _only_ thing I’ve often thrown away large parts of was the template.
I’ve taken over about as bad of a Phoenix app as you can imagine (made by a rotating cast of outsourced contractors over years, no use of Ecto relations, no use of “resources” (just get and post), not using built-in validations, pinned to a version of LiveView from two months after its initial release… and using jQuery to drive it). Due to Elixir’s immutable, functional nature, rehabilitating the code base has actually been a bit easier than some Django apps I’ve seen. The most painful part has been unraveling the jQuery.
IMO, Django still hasn’t caught up with 2014 Rails.
> I use Phoenix only on projects where its real-time capabilities will be the protagonist
Yep, that feels sound advice (and motivation). I would add more broadly "federation capability" (in the style of the fediverse / activitypub but also wherever that decentralization path might take us in the near future) as an important dimension to look into. Remains to be seen if the "telecoms/erlang" pedigree of elixir is a critical element in this respect. There are already some important projects based on elixir [0] [1] but also some django based efforts [2] [3].
There is this joke that you don't need to outrun a python, you only need to outrun the humans it is chasing.
Elixir does not need to outshine Python it only needs to position better than other "functional style" languages on offer as the "go-to" language if one wants to add such a capability in their programming toolkit.
In practice this means outshining Clojure. And on this front Elixir definitely does a good job: E.g., there is no such thing as Phoenix in Clojure. People seem to advance some arguments along the lines: "you don't really need frameworks, just compose your own" but this is not cutting it for the masses :-)
In a universe where there are millions of different ways of doing things having a well thought, opinionated, proposal is actually an advantage. The limitations (if any) show much later in the cycle when the choice of programming language might even be the least of your worries.
I don’t think these languages really compete outside of a fairly narrow dimension. They both seem to be doing well. But that’s beside the point.
People in the Clojure community have been trying to build such frameworks. But every one of them seems to stay in a weird niche where they’re not comprehensive and _easy_ enough to draw in people who’d use something like Django et al.
I think one of the reasons is that they’re all trying to cater to the crowd that wouldn’t use such a framework anyway.
Secondly it’s already very quick to create a web app in Clojure. If you use a set of libraries you pay with some initial setup/thinking/choosing cost. The benefit is then to have a program that is more malleable and composable, which is kind of the point for many who choose Clojure in tge first place.
There’s really a mismatch of expectations and philosophy I feel.
The Phoenix docs don't look like they even hold a candle to Django. I spent 5mins in it and still don't know how to define a model. I eventually figured out a doc section called "Ecto" - so i had to know what ecto was to find it. Then, in those docs I still don't know how to define models. Do they expect me to manage my database and schemas separately and generate the models from that?
That's completely opposite what Django does, and that's partly why Django is so productive.
I don't think Pheonix and Django are competitors. They are too different.
Phoenix doesn't have the concept of a "model". The functionality of what Rails (and I guess also Django? Idk) calls a "model" is split between a few different places: schemas, changesets, queries, the repo.
It felt weird at first, coming from Rails, but after getting used to it I don't miss "models" at all. ActiveRecord models in Rails are a vastly overloaded concept anyway and pretty much always degenerate fast into an ungodly mess as your app grows. I prefer Phoenix's approach.
I'm not really familiar with Phoenix, but skimming through the section linked below, it seems to cover what you're looking for? Basically, you use a tool to generate your model + migration code and then run the migrations.
As for the comparison to Django, I don't really expect any web framework to have docs at that level. They are simply huge and have been around for quite a while.
I think this article does capture the magic of elixir phoenix live view that is impossible in the async await madness hell in python. I cannot wait to try elixir Phoenix live view, elixir |> pipes, :atom pattern matching and ets pids to send and manage processes across servers none of these AFAIK are currently possible with the GIL and single threaded nature of python
As the venerable prof Joe armstrong would say
you need erlang and haskell for fp you need c for high performance you don't really need cpp Java python c# etc
Also as an aside does anything in haskell have something similar in spirit to phoenix or live view?
You can pattern match on basically any shape, not just atoms. Imagine you’re parsing a protocol over tcp and want to grab groups of characters between deliverers, you can pattern match that. I rewrote an hl7 parser from Java to Ruby to Elixr some years ago and the elixir implementation performed as well as Java and was more readable by miles.
I think I fall outside of the "most Python lovers" then.
I love(ed) python for close to 20 years, and have written a ton in it as my main language.
One project I worked on had us writing IronPython and IronRuby stuff (this was some years ago). I was forced to work on Ruby, and really hated it. Python, for me, was far superior. It really did not speak to me in any way.
With that said, I started to look into Elixir 3-4 years ago, and it just clicked with me. In a short span of time I stopped developing anything new in Python, and now use Elixir as my go-to language of choice.
I say this to say that it's worth the effort to at least expose people to new languages. It doesn't hurt anyone, and if other's aren't interested, they simply will not move to the new language. Others though might be pleasantly surprised to find out what other languages have to offer.
"Python has some functional capabilities, but in my experiences with Python devs, those are little used and even shunned. Imperative, mutating loops are the Python way; and to suggest otherwise is to hear "But why would I need that? This (long functions with mutations everywhere and loops) is fine.""
Thank God I'm not stuck with low talent clowns like that.
Writing highly functional python isn't hard anymore, especially making use of mypy strong types, data classes, generator expressions/etc.
Using dict unpacking combined with things like list comps is a really simple way to get trad Python devs getting more functional. My team is a bunch of experienced Python devs who happen to live Haskell/Clojure/etc so I guess that makes things easier.
> Thank God I'm not stuck with low talent clowns like that
Woah! Python’s a multiparadigm language. Using loops and mutation is a perfectly fine way to write Python code. For sure there are some kinds of code that lend themselves to a functional style, but equally, there are other cases where mutation is the more straightforward approach.
It seems like the basis for your comment is weird stack tribalism that you’ve very evidently bought into, rather than anything actually…worth discussing.
It then comes as no surprise that throughout your entire comment you didn’t seem willing you yield any ground to Python or Django at all.
It then comes as no surprise that your assertions about Django are counter to my experience, as someone that by the sound of things has worked with Django a lot more than you have.
I have only worked on one production Django project that *didn’t^ use Django’s auth system. And the fact that you call Django’s generic class-based views “scaffolding” - a term that I seldom hear in Django spaces but hear all the time in Rails spaces - further speaks to your lack of familiarly. Most production Django projects I’ve worked on have made extensive use of either these generic class-based views or the Django REST Framework analogues, which - whilst not part of core Django - still speak to the usefulness of the pattern.
It honestly sounds like your experience with Django - if any - has been treating it like Rails. Which - honestly - is mostly fine. In my eyes, the frameworks are comparable in…most ways. But your assertion that these batteries are thrown away in production contexts is just wrong. Unless you want to tell me that I’ve spent ~a decade earning a living working with Django and somehow not managed to do any “real” work, perhaps consider the global applicability of your personal experience.
It’s really disappointing to see the re-uprising of Ruby (and Elixir) developers positioning themselves as the enlightened elite against the hoards of plebeian Python developers. I without a doubt include your comment in this critique. I understand that given Elixir’s increased FP focus that the community can’t avoid FP elitism. Doing it for Ruby though? It’s just cringey. I’ve got no beef with Ruby, Rails, or the development communities of either, except for the fact that people are feeling the need to pick up this ridiculous turf war.
Given that Python is my daily driver, Python spaces are where I’m usually active in. Ruby is seldom mentioned. Whenever I go to a Python-related HN thread, I don’t have to scroll far to see some Ruby developer making some thinly veiled assertions that Python developers are un enlightened idiots. If I look at a Ruby thread, there’s always someone salty about not being able to get the Python drones on their team to use the One True Language. It feels like I’ve gone back in time 15 years.
It is perhaps utopia but it would be nice if we could discuss those topics without falling into camps.
For example, I could argue for hours about the benefits of immutability, but I still believe that imperative loops are clearer than functional ones. There is even a repository with solutions for nested traversals in different languages and the Python one is my preferred by some margin: https://github.com/josevalim/nested-map-reduce-traversal
> Python has some functional capabilities, but in my experiences with Python devs, those are little used and even shunned.
I like to use things like filter, map, reduce or list comprehensions, but I see very few of those in my coworkers' code bases.
When Python introduced pattern matching, it was rather a pattern-aware switch/case, which does not return a value, as such a construct in a functional programming would do.
> I went from Ruby to Elixir, and even with my basic Clojure experience, it was an effort.
I tried out Elixir twice so far, and since the last time, I worked through 300 pages of SICP. I still have to twist my mind when I'd like to process nested maps or the like in Elixir now.
> It was worth it, but I think the apparently similarity of Elixir to Ruby is actually a negative.
However, Ruby provides a lot of higher-order functions, such as group_by and the like. If you're used to functional-style Ruby code, the transition is easier.
I’ve personally found Elixir to be a nice balance compared to something like Haskell or even Rust in terms of FP. Most things, certainly testing are made simpler by immutability and the actor model makes parallelism much simpler to reason about. I’ve no doubt python is a great language for some things but once Elixir figure out the best way to add types I’ll be extremely happy that the language does everything I want. Especially with ChatGPT now you can ask it about topics in language learning that you don’t understand and it gives really great examples to help, so for me learning idiomatic ways of programming in Elixir or another language got a lot easier.
I use Django not just for the framework, but for the larger Python ecosystem of packages for just about any eventuality, whether that be NLTK, pandas, or whatever (and if I didn't need the full weight of Django there's always Flask or FastAPI).
That's not to knock on Elixir or Phoenix, and I like Elixir a lot, but there is usually more to projects I've worked on than CRUD apps, and I've found with languages with smaller mindshare and ecosystems that you can spend more time reinventing wheels because a particular library is missing, or it's there but is no longer maintained.
My perhaps slightly biased input on Python vs. Elixir (I worked with Python for different projects for a couple years, and have been using Elixir full-time for ~1.5 years).
Elixir as a core technology for application development (as opposed to data science/ML/AI - it’s still early days for Nx/Axon/etc.) is better than Python in just about every way that matters; e.g. immutability by default eliminating whole classes (no pun intended) of bugs, having the full power of OTP available if you need a distributed system, more convergence around libraries and frameworks (to the point that José Valim also works on Phoenix, LiveView, Nx, etc., not to mention having Mix, EEx, and ExUnit built in).
I do wish Elixir had significant whitespace rather than do/end, but that’s not a hill I’m willing to die on…
My one major gripe with Elixir’s ecosystem compared to Python’s is that, IMO, Django would have been a better source of inspiration for a dominant Web framework compared to Rails; Django’s model layer is top-notch, with all your basic model information for an app contained in one models.py file. In Rails and Phoenix, you don’t get auto-migrations out of the box for simple use cases, and your model layer ends up being distributed across schema/ActiveRecord files, a “structure.sql” or “schema.rb” file, and the migrations. In my real-world use, this has been… “sub-optimal” compared to Django, to the point that I sometimes dream about building my own Django-ish framework for Elixir. Django+Django REST Framework are that good - if you stick with Python and are not using them already, do yourself a favor and check them out.
Also, Django’s admin is old, crusty tech, but it does what it set out to do really well.
I will admit Django’s implicit queries can cause DB performance issues, I wish there was an explicit analogue to Ecto’s Repo.* functions to force devs to think about when to make the DB call.
If you don’t mind, I have some questions as I would like to learn more. Are you aware of a large models.py for reference and learning purposes? Is it expected to define the schema of all my models in a single place but none of the logic?
Also, don’t you run into scenarios in Django where the automatic migration is not enough and you need to provide custom commands? In such cases, how do you provide them?
And can you have scenarios where you have two models pointing to the same table, but perhaps to a subset of fields (this is specially useful in read-only cases)? How is that handled?
The sibling to this post (by “traverseda”) is more informed and informative than I could hope to write. I will add that Django has Manager classes that have default behavior included for interacting with the query API, and they can be customized to your needs. You can even have multiple managers for a given model.
It’s been a few years since I used Django, but I remember its model layer fondly, and still follow the framework’s release processes.
One of the areas where Django lags is being fully async (Python imposed a lot of limitations on async operations for most of its life). The upcoming 4.2 release of Django is laying the groundwork for async DB operations.
>Are you aware of a large models.py for reference and learning purposes? Is it expected to define the schema of all my models in a single place but none of the logic?
Django models are normal python classes. Depends on exactly the logic you're dealing with, but generally you can make logic be a method on that class. Try to avoid logic that spans multiple tables in general, and if you have logic that does span multiple tables you probably want it to be a function and not a model method.
There are also signals that get sent on different things like model delete/create/etc, but they're to be used even more sparingly.
Logic for querying data should probably go wherever you're going to use it and you should just pass the model objects directly to your views. To start don't worry about optimizing queries or the n+1 problem, but as you get more experience you can use `prefetch_related` in order to avoid the n+1 problem.
>Also, don’t you run into scenarios in Django where the automatic migration is not enough and you need to provide custom commands? In such cases, how do you provide them?
You shouldn't generally need to. That said django's migration system is very powerful and you can hand-write a migration if you need to.
>And can you have scenarios where you have two models pointing to the same table, but perhaps to a subset of fields (this is specially useful in read-only cases)? How is that handled?
I mean you can using proxy models but that's not really a thing with django. Models are for developers and generally developers have all the permissions any way, so the solution to making a model read only is to just not write to it. If you want to present a read-only model to an end user you can reference it in a view of make a read-only serializer with django-rest-framework. It's python, not java, there's no such thing as private/protected members just convention to put an "_" in front of things other developers probably shouldn't be messing around with.
> Also, don’t you run into scenarios in Django where the automatic migration is not enough and you need to provide custom commands? In such cases, how do you provide them?
Data migrations are the obvious case where you need to write migration code manually. It comes up in schema migrations too on big projects. It’s easy to modify the auto-generated migration; it’s just Python that gets run by the migration tool:
I don't think this is something that will come down to technical merits.
Unfortunately it is a popularity contest, where entrenched network effects are working against Elixir.
As a Python programmer, I truly believe Elixir/Phoenix is the best stack out there from a technical perspective.
However the incredible breadth of libs and resources ... and most importantly the mind share (both available devs, but more importantly available jobs for seniors who commit to Elixir) means that it is still just not a competitive choice.
Almost all commercial software dev is not about technical excellence, but rather about applying the available tech to a particular business domain. And there Python (and .Net, Java, PHP, Ruby ... even Go) are so far ahead that sadly Elixir doesn't look like it will make it.
I don't know that anything can be done about this. For all that I think Elixir is better, I, like most devs, am not about to sacrifice (or even impair) my career for the cause. Personal remuneration wins out.
I'm familiar with neither Rails nor Django so I dont fully follow what you're describing. Are you just talking about the difficulty of maintaining the schema/DB mapping with the migrations ran against the DB?
I’ve never used Ecto outside of a Phoenix app, so yes, in my mind the line between them was blurry. Thanks for pointing out my mistake!
A very recent real-world challenge I ran into was having to coordinate updates and diffs to all the files involved and keeping them in sync while doing local development (before deployment but also while working on fixing a very subtle bug). Every time I changed the migration file (even to add an index), I had to remember to checkout the previous version of “structure.sql” or the migration wouldn’t be run, even during a complete DB reset (structure.sql is used to know which migrations have been run and synced with the SQL dump). Also, the schema in Ecto does not have a complete validation API, so you’ll need to do those in “changeset” functions. Overall I like Ecto, and part of me regrets letting myself get spoiled by Django’s model layer and DB tools.
I've been using Elixir with Phoenix and Liveview at my job for the past three months as part of a small team building a non-trivial web app (https://duffel.com/links). I'm mostly a front-end developer and was brought in to handle the UX side. Prior to this project I've spent the last 5+ years in the React world.
I found a lot of what the author says to be true. I'm used to the nightmare that is managing front-end dependencies, and it was refreshing to use something so 'batteries included' that comes with most of what I need.
It took me a while to get my head around the Phoenix + Liveview way of doing things, but when my mental model clicked into place and I stopped trying to do things the React way I became a lot more productive. When I had an autocomplete updating live as the user typed all going over the websocket without me writing any JS, it felt magical.
However I definitely found a lot of sharp edges that the author doesn't mention. We struggled a lot with any non-trivial UX, for example with the autosuggest mentioned above I had to add a lot of JS to handle things like being able to use the keyboard's arrow keys to select options. Whenever I jumped into the JS world it often felt like I was fighting against Phoenix, and had to resort to using 'phx-ignore' a lot. It was frustrating to continually struggle to do things I knew how to do easily in a pure JS environment.
Another area I struggled a lot is Elixir's syntax. To me, it feels like there are too many operators. The author touches upon it towards the end when they mention things like '\\' for default arguments, '<>' for joining strings and '++' for joining lists. It's a lot to wrap your head around at times.
Some of the fault for this lies with me; we were working to a tight deadline so I didn't have time to dedicate to learning Elixir, Phoenix and Liveview from first principles, I just jumped in out of necessity. Had I spent more time on the foundations first I may have been able to avoid some of these pitfalls, but I do think it illustrates that like many 'do everything' frameworks, there's a steep learning curve to doing non-trivial things. It's a powerful tool and I'm optimistic about its future, but I'm undecided if I'd choose it for a future project that has significant front-end requirements at this stage.
It sounds like you were able to be reasonably productive without even any time to learn the framework, so I’d say you did alright!
I’d say up until the recent focus on LiveView, Phoenix has been very easy for devs with experience with Rails or Rails clones in other languages to learn. Recently, with all the LiveView changes and the new components, it’s been harder, but I think it’s finally stabilizing a bit and I’ve got to say the newly-released Phoenix 1.7 is another significant step forward in terms of productivity for new apps.
Which part of this app is using LiveView? Since what you link to is using next.js. Are you guys mixing the two?
I really want to find a reason to build something with elixir, and it might be viable for my current work project. We won't be replacing our next.js frontend, though, that's for sure, though I wouldn't mind experimenting with it.
I'm mostly interested in deploying elixir on the backend, since we are using microservices, and there would definitely be a couple of services where elixir seems like a great fit. OTOH, we are also pushing some data through ML models, and it seems like Python is still the only real choice for this kind of stuff. I really wish it weren't the case, since the python interpreter with its GIL is just a piece of crap, to be frank.
Ah sorry, I should have clarified in my original message. The page I linked to is our public marketing site, which is a static site built with Next. The Phoenix application is the product that the site is talking about (Duffel Links).
> Whenever I jumped into the JS world it often felt like I was fighting against Phoenix
I've had the same experience and this is something I've tried to tackle recently. I've started working on LiveSvelte which allows you to plug in Svelte components directly into your LiveView, while still being able to push events to the server with a `pushEvent` function on the client. I've only started working on it this week but I think it's a promising idea. It's not React though but you could develop a similar package with React, I just much prefer Svelte :)
Serious question—if you were on a tight deadline, why did you choose a tech stack that you still had to learn? Leveraging existing knowledge is exactly what anyone in a rush should be doing.
I wasn't personally involved in making this decision, I was brought onto the project after it was taken, but there was a perception that we'd be faster if we did everything as a full-stack application. In fairness, we did deliver what we set out to do so it was a success, even if there were some rough edges to deal with.
Also bear in mind that I'm only covering my front-end perspective on this. I think the back-end developers involved on the project found it much easier to work with as they were already experienced with Elixir and Phoenix. For them, a tightly-coupled front and back end meant that they could change the way things worked and it was straightforward to update a few functions in Elixir and then the HEEX template, as opposed to a decoupled setup where we'd probably have been communicating using a JSON API and changes would have had more of a barrier to adopt.
I was randomly watching youtube videos about Elixir ("The Soul of Erlang and Elixir " by Sasa Juric), and I have never really been interested in it... I was completely wrong. BEAM/Erlang is amazing piece of technology, and Elixir does excellent job to bring in new people in.
If you do web development, then just for the sake of professional curiosity, I urge you to go watch a couple of videos to make yourself in idea. I have found that some (many) features which I would go learn and use another tool for, are already included into Elixir ... Now I feel sad for doing Django for my daywork
I work for an org that does a lot of Elixir (on other teams though, I’m actually a Django developer!). I’ve heard from those team leads that they’ve had trouble hiring people with FP / Elixir experience, which is not that surprising to me. Guess it’s a matter of right place right time.
I've been programming my web projects exclusively in Elixir for the last few years and I've been deeply enjoying the language.
Although at first, some unfamiliar design decisions annoyed me, for they were not well explained in the tutorials I was learning the language from – e.g `arg: value` as a shortcut for `[{:arg, value}]` in function arguments and other places – over time, I've grown to love and appreciate the language and I now more or less regard it as an elegant programming language put together by a thoughtful person with great programming taste.
The Phoenix framework is a great bonus point if you want increased productivity for writing web apps. I don't miss Python at all.
Elixir rests on the shoulders of giants though, and the Erlang/OTP is yet another elegantly engineered piece of technology, enabling one to develop concurrent, distributed and fault tolerant systems with ease, and in this regard I think the Erlang/Elixir ecosystem takes the crown. The actor model is simple, yet very powerful.
For reference, I've also been learning Nim and F#, and they're also pretty unique and well designed languages in their own ways. I love Nim's fast compilation times, efficiency and expressiveness and F#'s powerful type system which enables one to develop domain models with ease. I've also been occasionally taking stabs at Rust, but it always feels just a tad too complex for my brain. I'll continue playing with it though, maybe it will eventually make sense.
Ultimately, every design decision is also a tradeoff. I don't think we'll ever have a perfect, human designed language.
My dream language would probably be a combination of Elixir and F# though, a language with an advanced and powerful type system, functional programming and the actor model as the building blocks. I guess fast compilation times à la Nim wouldn’t hurt either. :)
> Although at first, some unfamiliar design decisions annoyed me, for they were not well explained in the tutorials I was learning the language from – e.g `arg: value` as a shortcut for `[{:arg, value}]` in function arguments and other places
What kinds of things have you been coding or reading in your Rust learning so far? I'm a pretty big fan of Herbert Wolverson's Pragprog Rust book and open source Roguelike project, as well as Tim McNamara's Rust in Action (which I've only gone through part of due to how each project leaves you wanting to keep building it after the book moves on to another).
I wish I had this when I learned the language. :) I'll take a look, as your playlist is quite comprehensive it appears. Thanks for sharing!
Re: Rust - I've been trying out basic examples, simple web servers, etc; nothing too fancy. But it just seems too ceremonious to get even the most basic things done. I own the book "Rust in Action", I just didn't have the proper time to go over it.
Yeah, I've known about Gleam, but I don't recall exactly why I wasn't too compelled to use it. I installed it with brew a while back, I tried a few basic examples and since then it's just been sitting there. I guess I should revisit. But thanks for the reminder anyway.
What is the productivity advantage of Elixir/Phoenix over other frameworks when using it for implementing more mundane SaaS (some dashboards, some CRUD,...) rather than the game lobby feature mentioned in the post?
I am a developer with significant non-web development experience (Although I know pure JS and Erlang quite well), who is interested in learning some full-stack development to implement a SaaS on the side and would like to zone in on the most productive framework possible.
For me it's not just the framework (although that is nice) but really the VM that it runs under (BEAM/OTP). Running an app on the BEAM means removing the need for external servers like redis/memcache for cacheing and whatever queue management system you pick.
For a SaaS app this means instead of trying to orchestrate a bunch of services via some complex system (k8s, etc) you run everything under one VM that both scales across both local CPU cores and distributed nodes in the same network easily.
As for dashboards and CRUD UI that is improving in the latest Phoenix release. I have a 5 year old Phoenix app that I wrote that is still running in production and I generated all of the backend admin and most of the frontend using Phoenix's generators. However that did result in a lot of nearly duplicate view code. With 1.7's focus on shared common UI components the shear volume of template code is reduced, (but not eliminated).
If I were you I'd wait for 1.7 to fully release and then try it out for a couple of hours and generate some simple app to get a feel for it. I've been programming professionally for 30+ years and I've written in a lot of languages and writing Elixir code just feels good. José Valim got a lot right with Elixir (and he sets a great tone - just read his comments in this very comment section).
Although, if I were an absolute beginner, I might still consider waiting a little bit for the various resources to be updated to 1.7. That seems to be happening fast, at least. Or just go for the excellent Phoenix guides, which are already updated: https://hexdocs.pm/phoenix/overview.html
As long as you don't have any dynamic part to your app, it's pretty much the same, it's the dynamic areas that are very very productive with live view.
I've implemented a simple multiplayer card game in about a day for example.
Assuming the author is in the comments, the paragraph about data immutability is wrong. Integers are immutable in Python, when you created the lambda the name x is in its closure. When you assign to it it changes where the name is pointing to. Elixir does something wild and completely different. When you assign x that second time at that moment is creates a new variable behind the scenes and you transparently start using that one when you now refer to x in that scope. So lambda has a reference to x@0 and your outer scope has a reference to x@1.
Perhaps Phoenix and LiveView will be the gateway drug, but even to reach that point requires a lot of effort to understand functional programming and Elixir.
Python has some functional capabilities, but in my experiences with Python devs, those are little used and even shunned. Imperative, mutating loops are the Python way; and to suggest otherwise is to hear "But why would I need that? This (long functions with mutations everywhere and loops) is fine."
I went from Ruby to Elixir, and even with my basic Clojure experience, it was an effort. It was worth it, but I think the apparently similarity of Elixir to Ruby is actually a negative. They look awefully similar, but their use is vastly different.
As for Django vs Phoenix, I would argue that Phoenix has a much cleaner story for doing everything that Django can do and more. People promote Django for the "batteries included" aspect, which mostly just means "I get free user/auth system and built-in scaffolding for my CRUD." But those are things which are very easy to add to Phoenix (and Rails, which Phoenix is roughly similar to). Yet people choose Django for these little freebies which almost always get thrown away or ignored in real production worlds. For a quick proof-of-concept, it's nice. But for real projects it doesn't add value enough to offset the crufty boilerplate OO-centric code that results.
On the other hand, I agree with you that everything that Phoenix generates through its phx.gen generators are for demo purposes and will get thrown away eventually. This, along with the fact that everything is a function results in having to re-invent the wheel multiple times in your project without any saferails on how to actually architecture it. Should I use a context? What to put there? What's the point of views? Oh views are removed now? So, unless you are really very careful or have much experience/guidance this will result to a total mess.
The batteries included aspect of Django means that if you are a novice developer and follow the best practices you'll get a fine project without too much effort. It isn't really about the batteries, it's about the fact that you'll know how to implement each thing you need in a web project. I can confirm to that that because we've got 12-year old production running Django projects which were developed by a totally novice Django developer (me).
Try to do that in Phoenix (still being a novice developer).
Now I don't want to abolish Phoenix. It's a fine framework considering its age and its popularity and number of people contributing to. However you must be very careful before considering to use it for a real project that will be used and supported for the years to come, expecially if your alternative is something as proved as Django. Personally, I use Phoenix only on projects where its real-time capabilities will be the protagonist.
I was one of the co-authors of Devise, which is an integrated authentication solution for Rails (similar in spirit to Django), and you will easily find people who swear that the code generation solutions are miles better. That’s because eventually they’d want to customize how the framework or library work and then, instead of simply being able to change the code, you need to find the exact hook or configuration to get the behavior you want. Eventually, you end up with hodgepodge of changes that you can only understand when looking at the framework and your code side-by-side.
Perhaps this is one of the topics where there is no “superior” answer, besides personal preferences and past experiences. I totally understand why someone would prefer Django or Devise, but our premise is that eventually you will want to customize it, therefore giving you control upfront is the better way to go about it. However, I would say it is incorrect to say they are for demo purposes in both Phoenix and Django cases, as there is plenty of evidence otherwise.
It is also a matter of framework philosophy. Phoenix aims to give all the necessary foundation for building applications, and then not get in your way, rather than owning all aspects of your application lifecycle. I believe frameworks like Ash (which also runs on Phoenix) take the latter approach.
> Oh views are removed now?
To clarify, Views are not removed. Phoenix is still MVC. The difference is that the templates in your view are defined via `use Phoenix.Template`, rather than `use Phoenix.View`. You can migrate (or not) at your convenience.
The parent didn’t say that and it’s not true in my experience writing Phoenix apps over the past six years. I usually add to the generated contexts, controllers or now live views, but I often leave the migrations as is. Even when making a migration to edit an existing schema, I still use the Ecto generators. The _only_ thing I’ve often thrown away large parts of was the template.
I’ve taken over about as bad of a Phoenix app as you can imagine (made by a rotating cast of outsourced contractors over years, no use of Ecto relations, no use of “resources” (just get and post), not using built-in validations, pinned to a version of LiveView from two months after its initial release… and using jQuery to drive it). Due to Elixir’s immutable, functional nature, rehabilitating the code base has actually been a bit easier than some Django apps I’ve seen. The most painful part has been unraveling the jQuery.
IMO, Django still hasn’t caught up with 2014 Rails.
Yep, that feels sound advice (and motivation). I would add more broadly "federation capability" (in the style of the fediverse / activitypub but also wherever that decentralization path might take us in the near future) as an important dimension to look into. Remains to be seen if the "telecoms/erlang" pedigree of elixir is a critical element in this respect. There are already some important projects based on elixir [0] [1] but also some django based efforts [2] [3].
[0] https://bonfirenetworks.org/docs/architecture/
[1] https://docs.joinmobilizon.org/administration/install/source...
[2] https://docs.funkwhale.audio/stable/installation/
[3] https://docs.jointakahe.org/en/latest/installation/
As a web user (not dev) I would say real-time (as in super fast?) should always be the protagonist?
To me that's the most important factor that makes the difference between nice and shtty website.
Elixir does not need to outshine Python it only needs to position better than other "functional style" languages on offer as the "go-to" language if one wants to add such a capability in their programming toolkit.
In practice this means outshining Clojure. And on this front Elixir definitely does a good job: E.g., there is no such thing as Phoenix in Clojure. People seem to advance some arguments along the lines: "you don't really need frameworks, just compose your own" but this is not cutting it for the masses :-)
In a universe where there are millions of different ways of doing things having a well thought, opinionated, proposal is actually an advantage. The limitations (if any) show much later in the cycle when the choice of programming language might even be the least of your worries.
People in the Clojure community have been trying to build such frameworks. But every one of them seems to stay in a weird niche where they’re not comprehensive and _easy_ enough to draw in people who’d use something like Django et al.
I think one of the reasons is that they’re all trying to cater to the crowd that wouldn’t use such a framework anyway.
Secondly it’s already very quick to create a web app in Clojure. If you use a set of libraries you pay with some initial setup/thinking/choosing cost. The benefit is then to have a program that is more malleable and composable, which is kind of the point for many who choose Clojure in tge first place.
There’s really a mismatch of expectations and philosophy I feel.
That's completely opposite what Django does, and that's partly why Django is so productive.
I don't think Pheonix and Django are competitors. They are too different.
It felt weird at first, coming from Rails, but after getting used to it I don't miss "models" at all. ActiveRecord models in Rails are a vastly overloaded concept anyway and pretty much always degenerate fast into an ungodly mess as your app grows. I prefer Phoenix's approach.
https://hexdocs.pm/phoenix/ecto.html#using-the-schema-and-mi...
As for the comparison to Django, I don't really expect any web framework to have docs at that level. They are simply huge and have been around for quite a while.
As the venerable prof Joe armstrong would say
you need erlang and haskell for fp you need c for high performance you don't really need cpp Java python c# etc
Also as an aside does anything in haskell have something similar in spirit to phoenix or live view?
There are the major benefits of Elixir itself, including FP, plus the array of features and tools for building distributed systems via OTP.
Only talking about LiveView is underselling Elixir.
I say this to say that it's worth the effort to at least expose people to new languages. It doesn't hurt anyone, and if other's aren't interested, they simply will not move to the new language. Others though might be pleasantly surprised to find out what other languages have to offer.
Thank God I'm not stuck with low talent clowns like that.
Writing highly functional python isn't hard anymore, especially making use of mypy strong types, data classes, generator expressions/etc.
Using dict unpacking combined with things like list comps is a really simple way to get trad Python devs getting more functional. My team is a bunch of experienced Python devs who happen to live Haskell/Clojure/etc so I guess that makes things easier.
Woah! Python’s a multiparadigm language. Using loops and mutation is a perfectly fine way to write Python code. For sure there are some kinds of code that lend themselves to a functional style, but equally, there are other cases where mutation is the more straightforward approach.
It then comes as no surprise that throughout your entire comment you didn’t seem willing you yield any ground to Python or Django at all.
It then comes as no surprise that your assertions about Django are counter to my experience, as someone that by the sound of things has worked with Django a lot more than you have.
I have only worked on one production Django project that *didn’t^ use Django’s auth system. And the fact that you call Django’s generic class-based views “scaffolding” - a term that I seldom hear in Django spaces but hear all the time in Rails spaces - further speaks to your lack of familiarly. Most production Django projects I’ve worked on have made extensive use of either these generic class-based views or the Django REST Framework analogues, which - whilst not part of core Django - still speak to the usefulness of the pattern.
It honestly sounds like your experience with Django - if any - has been treating it like Rails. Which - honestly - is mostly fine. In my eyes, the frameworks are comparable in…most ways. But your assertion that these batteries are thrown away in production contexts is just wrong. Unless you want to tell me that I’ve spent ~a decade earning a living working with Django and somehow not managed to do any “real” work, perhaps consider the global applicability of your personal experience.
It’s really disappointing to see the re-uprising of Ruby (and Elixir) developers positioning themselves as the enlightened elite against the hoards of plebeian Python developers. I without a doubt include your comment in this critique. I understand that given Elixir’s increased FP focus that the community can’t avoid FP elitism. Doing it for Ruby though? It’s just cringey. I’ve got no beef with Ruby, Rails, or the development communities of either, except for the fact that people are feeling the need to pick up this ridiculous turf war.
Given that Python is my daily driver, Python spaces are where I’m usually active in. Ruby is seldom mentioned. Whenever I go to a Python-related HN thread, I don’t have to scroll far to see some Ruby developer making some thinly veiled assertions that Python developers are un enlightened idiots. If I look at a Ruby thread, there’s always someone salty about not being able to get the Python drones on their team to use the One True Language. It feels like I’ve gone back in time 15 years.
For example, I could argue for hours about the benefits of immutability, but I still believe that imperative loops are clearer than functional ones. There is even a repository with solutions for nested traversals in different languages and the Python one is my preferred by some margin: https://github.com/josevalim/nested-map-reduce-traversal
I like to use things like filter, map, reduce or list comprehensions, but I see very few of those in my coworkers' code bases.
When Python introduced pattern matching, it was rather a pattern-aware switch/case, which does not return a value, as such a construct in a functional programming would do.
> I went from Ruby to Elixir, and even with my basic Clojure experience, it was an effort.
I tried out Elixir twice so far, and since the last time, I worked through 300 pages of SICP. I still have to twist my mind when I'd like to process nested maps or the like in Elixir now.
> It was worth it, but I think the apparently similarity of Elixir to Ruby is actually a negative.
However, Ruby provides a lot of higher-order functions, such as group_by and the like. If you're used to functional-style Ruby code, the transition is easier.
That's not to knock on Elixir or Phoenix, and I like Elixir a lot, but there is usually more to projects I've worked on than CRUD apps, and I've found with languages with smaller mindshare and ecosystems that you can spend more time reinventing wheels because a particular library is missing, or it's there but is no longer maintained.
Elixir as a core technology for application development (as opposed to data science/ML/AI - it’s still early days for Nx/Axon/etc.) is better than Python in just about every way that matters; e.g. immutability by default eliminating whole classes (no pun intended) of bugs, having the full power of OTP available if you need a distributed system, more convergence around libraries and frameworks (to the point that José Valim also works on Phoenix, LiveView, Nx, etc., not to mention having Mix, EEx, and ExUnit built in).
I do wish Elixir had significant whitespace rather than do/end, but that’s not a hill I’m willing to die on…
My one major gripe with Elixir’s ecosystem compared to Python’s is that, IMO, Django would have been a better source of inspiration for a dominant Web framework compared to Rails; Django’s model layer is top-notch, with all your basic model information for an app contained in one models.py file. In Rails and Phoenix, you don’t get auto-migrations out of the box for simple use cases, and your model layer ends up being distributed across schema/ActiveRecord files, a “structure.sql” or “schema.rb” file, and the migrations. In my real-world use, this has been… “sub-optimal” compared to Django, to the point that I sometimes dream about building my own Django-ish framework for Elixir. Django+Django REST Framework are that good - if you stick with Python and are not using them already, do yourself a favor and check them out.
Also, Django’s admin is old, crusty tech, but it does what it set out to do really well.
I will admit Django’s implicit queries can cause DB performance issues, I wish there was an explicit analogue to Ecto’s Repo.* functions to force devs to think about when to make the DB call.
Also, don’t you run into scenarios in Django where the automatic migration is not enough and you need to provide custom commands? In such cases, how do you provide them?
And can you have scenarios where you have two models pointing to the same table, but perhaps to a subset of fields (this is specially useful in read-only cases)? How is that handled?
Thank you :)
The sibling to this post (by “traverseda”) is more informed and informative than I could hope to write. I will add that Django has Manager classes that have default behavior included for interacting with the query API, and they can be customized to your needs. You can even have multiple managers for a given model.
https://docs.djangoproject.com/en/4.1/topics/db/managers/
It’s been a few years since I used Django, but I remember its model layer fondly, and still follow the framework’s release processes.
One of the areas where Django lags is being fully async (Python imposed a lot of limitations on async operations for most of its life). The upcoming 4.2 release of Django is laying the groundwork for async DB operations.
Django models are normal python classes. Depends on exactly the logic you're dealing with, but generally you can make logic be a method on that class. Try to avoid logic that spans multiple tables in general, and if you have logic that does span multiple tables you probably want it to be a function and not a model method.
There are also signals that get sent on different things like model delete/create/etc, but they're to be used even more sparingly.
Logic for querying data should probably go wherever you're going to use it and you should just pass the model objects directly to your views. To start don't worry about optimizing queries or the n+1 problem, but as you get more experience you can use `prefetch_related` in order to avoid the n+1 problem.
>Also, don’t you run into scenarios in Django where the automatic migration is not enough and you need to provide custom commands? In such cases, how do you provide them?
You shouldn't generally need to. That said django's migration system is very powerful and you can hand-write a migration if you need to.
>And can you have scenarios where you have two models pointing to the same table, but perhaps to a subset of fields (this is specially useful in read-only cases)? How is that handled?
I mean you can using proxy models but that's not really a thing with django. Models are for developers and generally developers have all the permissions any way, so the solution to making a model read only is to just not write to it. If you want to present a read-only model to an end user you can reference it in a view of make a read-only serializer with django-rest-framework. It's python, not java, there's no such thing as private/protected members just convention to put an "_" in front of things other developers probably shouldn't be messing around with.
Data migrations are the obvious case where you need to write migration code manually. It comes up in schema migrations too on big projects. It’s easy to modify the auto-generated migration; it’s just Python that gets run by the migration tool:
https://docs.djangoproject.com/en/4.1/topics/migrations/#dat...
Unfortunately it is a popularity contest, where entrenched network effects are working against Elixir.
As a Python programmer, I truly believe Elixir/Phoenix is the best stack out there from a technical perspective.
However the incredible breadth of libs and resources ... and most importantly the mind share (both available devs, but more importantly available jobs for seniors who commit to Elixir) means that it is still just not a competitive choice.
Almost all commercial software dev is not about technical excellence, but rather about applying the available tech to a particular business domain. And there Python (and .Net, Java, PHP, Ruby ... even Go) are so far ahead that sadly Elixir doesn't look like it will make it.
I don't know that anything can be done about this. For all that I think Elixir is better, I, like most devs, am not about to sacrifice (or even impair) my career for the cause. Personal remuneration wins out.
I'm familiar with neither Rails nor Django so I dont fully follow what you're describing. Are you just talking about the difficulty of maintaining the schema/DB mapping with the migrations ran against the DB?
A very recent real-world challenge I ran into was having to coordinate updates and diffs to all the files involved and keeping them in sync while doing local development (before deployment but also while working on fixing a very subtle bug). Every time I changed the migration file (even to add an index), I had to remember to checkout the previous version of “structure.sql” or the migration wouldn’t be run, even during a complete DB reset (structure.sql is used to know which migrations have been run and synced with the SQL dump). Also, the schema in Ecto does not have a complete validation API, so you’ll need to do those in “changeset” functions. Overall I like Ecto, and part of me regrets letting myself get spoiled by Django’s model layer and DB tools.
I found a lot of what the author says to be true. I'm used to the nightmare that is managing front-end dependencies, and it was refreshing to use something so 'batteries included' that comes with most of what I need.
It took me a while to get my head around the Phoenix + Liveview way of doing things, but when my mental model clicked into place and I stopped trying to do things the React way I became a lot more productive. When I had an autocomplete updating live as the user typed all going over the websocket without me writing any JS, it felt magical.
However I definitely found a lot of sharp edges that the author doesn't mention. We struggled a lot with any non-trivial UX, for example with the autosuggest mentioned above I had to add a lot of JS to handle things like being able to use the keyboard's arrow keys to select options. Whenever I jumped into the JS world it often felt like I was fighting against Phoenix, and had to resort to using 'phx-ignore' a lot. It was frustrating to continually struggle to do things I knew how to do easily in a pure JS environment.
Another area I struggled a lot is Elixir's syntax. To me, it feels like there are too many operators. The author touches upon it towards the end when they mention things like '\\' for default arguments, '<>' for joining strings and '++' for joining lists. It's a lot to wrap your head around at times.
Some of the fault for this lies with me; we were working to a tight deadline so I didn't have time to dedicate to learning Elixir, Phoenix and Liveview from first principles, I just jumped in out of necessity. Had I spent more time on the foundations first I may have been able to avoid some of these pitfalls, but I do think it illustrates that like many 'do everything' frameworks, there's a steep learning curve to doing non-trivial things. It's a powerful tool and I'm optimistic about its future, but I'm undecided if I'd choose it for a future project that has significant front-end requirements at this stage.
I’d say up until the recent focus on LiveView, Phoenix has been very easy for devs with experience with Rails or Rails clones in other languages to learn. Recently, with all the LiveView changes and the new components, it’s been harder, but I think it’s finally stabilizing a bit and I’ve got to say the newly-released Phoenix 1.7 is another significant step forward in terms of productivity for new apps.
I really want to find a reason to build something with elixir, and it might be viable for my current work project. We won't be replacing our next.js frontend, though, that's for sure, though I wouldn't mind experimenting with it.
I'm mostly interested in deploying elixir on the backend, since we are using microservices, and there would definitely be a couple of services where elixir seems like a great fit. OTOH, we are also pushing some data through ML models, and it seems like Python is still the only real choice for this kind of stuff. I really wish it weren't the case, since the python interpreter with its GIL is just a piece of crap, to be frank.
I've had the same experience and this is something I've tried to tackle recently. I've started working on LiveSvelte which allows you to plug in Svelte components directly into your LiveView, while still being able to push events to the server with a `pushEvent` function on the client. I've only started working on it this week but I think it's a promising idea. It's not React though but you could develop a similar package with React, I just much prefer Svelte :)
https://github.com/woutdp/live_svelte
Also bear in mind that I'm only covering my front-end perspective on this. I think the back-end developers involved on the project found it much easier to work with as they were already experienced with Elixir and Phoenix. For them, a tightly-coupled front and back end meant that they could change the way things worked and it was straightforward to update a few functions in Elixir and then the HEEX template, as opposed to a decoupled setup where we'd probably have been communicating using a JSON API and changes would have had more of a barrier to adopt.
If you do web development, then just for the sake of professional curiosity, I urge you to go watch a couple of videos to make yourself in idea. I have found that some (many) features which I would go learn and use another tool for, are already included into Elixir ... Now I feel sad for doing Django for my daywork
Although at first, some unfamiliar design decisions annoyed me, for they were not well explained in the tutorials I was learning the language from – e.g `arg: value` as a shortcut for `[{:arg, value}]` in function arguments and other places – over time, I've grown to love and appreciate the language and I now more or less regard it as an elegant programming language put together by a thoughtful person with great programming taste.
The Phoenix framework is a great bonus point if you want increased productivity for writing web apps. I don't miss Python at all.
Elixir rests on the shoulders of giants though, and the Erlang/OTP is yet another elegantly engineered piece of technology, enabling one to develop concurrent, distributed and fault tolerant systems with ease, and in this regard I think the Erlang/Elixir ecosystem takes the crown. The actor model is simple, yet very powerful.
For reference, I've also been learning Nim and F#, and they're also pretty unique and well designed languages in their own ways. I love Nim's fast compilation times, efficiency and expressiveness and F#'s powerful type system which enables one to develop domain models with ease. I've also been occasionally taking stabs at Rust, but it always feels just a tad too complex for my brain. I'll continue playing with it though, maybe it will eventually make sense.
Ultimately, every design decision is also a tradeoff. I don't think we'll ever have a perfect, human designed language.
My dream language would probably be a combination of Elixir and F# though, a language with an advanced and powerful type system, functional programming and the actor model as the building blocks. I guess fast compilation times à la Nim wouldn’t hurt either. :)
This complaint and a similar one for maps were the primary driver in me making an "Elixir tips" playlist of YT videos: https://www.youtube.com/watch?v=7w98voHko20&list=PLFhQVxlaKQ...
What kinds of things have you been coding or reading in your Rust learning so far? I'm a pretty big fan of Herbert Wolverson's Pragprog Rust book and open source Roguelike project, as well as Tim McNamara's Rust in Action (which I've only gone through part of due to how each project leaves you wanting to keep building it after the book moves on to another).
Re: Rust - I've been trying out basic examples, simple web servers, etc; nothing too fancy. But it just seems too ceremonious to get even the most basic things done. I own the book "Rust in Action", I just didn't have the proper time to go over it.
[0] https://gleam.run/
I am a developer with significant non-web development experience (Although I know pure JS and Erlang quite well), who is interested in learning some full-stack development to implement a SaaS on the side and would like to zone in on the most productive framework possible.
For a SaaS app this means instead of trying to orchestrate a bunch of services via some complex system (k8s, etc) you run everything under one VM that both scales across both local CPU cores and distributed nodes in the same network easily.
As for dashboards and CRUD UI that is improving in the latest Phoenix release. I have a 5 year old Phoenix app that I wrote that is still running in production and I generated all of the backend admin and most of the frontend using Phoenix's generators. However that did result in a lot of nearly duplicate view code. With 1.7's focus on shared common UI components the shear volume of template code is reduced, (but not eliminated).
If I were you I'd wait for 1.7 to fully release and then try it out for a couple of hours and generate some simple app to get a feel for it. I've been programming professionally for 30+ years and I've written in a lot of languages and writing Elixir code just feels good. José Valim got a lot right with Elixir (and he sets a great tone - just read his comments in this very comment section).
Good news: Phoenix 1.7 final was released yesterday! https://phoenixframework.org/blog/phoenix-1.7-final-released (HN: https://news.ycombinator.com/item?id=34929159)
Although, if I were an absolute beginner, I might still consider waiting a little bit for the various resources to be updated to 1.7. That seems to be happening fast, at least. Or just go for the excellent Phoenix guides, which are already updated: https://hexdocs.pm/phoenix/overview.html
The moment you need anything remotely dynamic, then the advantage is imho close to a 5x at least.
I've implemented a simple multiplayer card game in about a day for example.