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.
Then the upgrade doc will work and people won’t get stuck trying to follow those instructions with a Phoenix 1.6 app using whatever version of LiveView they had before.
There were a number of things not covered in the upgrade guide. Lots of small changes between what the new app generator provides, csrf tokens being set in a different way, etc..
With Phoenix 1.7 being released, will there be a new edition of "Programming Phoenix"? The latest one covers Phoenix 1.4, which is already slightly outdated.
I think having an up-to-date book would be of great value for Phoenix beginners :)
> instead of simply being able to change the code, you need to find the exact hook or configuration to get the behavior you want.
I don't think that this is a bad thing. This is the purpose of a framework. To extend its functionality. If I wanted to re-write everything (or change the generated scaffolds) then I'd skip the framework and use libraries directly.
I'd like to point out the biggest problem with scaffolding: Let's suppose I use scaffolding to generate a scema / database table in phoenix, along with all the bells and whistles. I'm happy; instant code. I customize all the scaffolds as I like (i.e change html layouts, fix the schema/migration for fks, fix the queries, improve forms etc). I'm happy; everything works as I like. After 1 hour I notice understand that my table is missing a field. I'm sad. Now I've got two equally sad options:
* Delete everything that phoenix has generated for me, drop the schema, re-generate the scaffold (with the new field) and re-apply all my customizations or
* Add the field myself by adding a migration, adding it to the schema, fixing the tests, adding it to changesets, fixing the templates, fixing the queries and praying I haven't forgotten anything.
Now I'm very sad.
What would happen in that case (forgot a field in the database) in Django? Add the field to the model and re-run the migrations. That's it. Happy days!
> You can migrate (or not) at your convenience
Yes, I know that the views are still there but my understading is that they won't be generated anymore (so the steer is to not use them anymore, at least for new code). However, my main argument was that Django is better at holding your hand to produce acceptable code even if you are not experienced with the framework nor you have mentoring. The fact that now you have even more options (i.e you can use views if you want and think you need them) strengthens that argument.
If you need to change it, you would add it to the migration, schema, and then in the necessary templates. Some fields are private, read-only, etc. so you would change your templates accordingly. Some fields you want to change via a button press, others via a form, and so on. The whole point is that you can evolve the generated structure based on your needs.
> (i.e you can use views if you want and think you need them)
I was mostly speaking about existing applications. New applications have a clear path forward.
I don’t think this strengthens your argument the way you think. I _bet_ Django also has features that were used in the past and are no longer favored now, but still supported for backwards compatibility. This is in no way a phenomenon exclusive to Phoenix.
If your argument is that a configurable framework is easier than code gen for beginners, I agree. But that said, you don’t seem to be acknowledging the fundamental tradeoff which cuts both ways. Ultimately it depends on how close you want to stay to the paved path. I’ve built enough web products at this point that I’d rather have auth primitives than a configurable framework as the latter will be way more complicated than necessary to meet my needs.
For me it comes down to keeping business logic out of my framework. The logical extension of the framework + hooks model can be seen in something like Drupal. You can get amazing volumes of functionality launched quickly, but the UX is ERP-like in its rigidity. Obviously Django is not like this in the large, and the auth/admin stuff are much higher power-to-weight ratio than anything in Drupal, but it’s an interesting case study in looking at the implications of drawing different logical boundaries between framework and application.
> “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.
My experience as well. The generated code is absolutely kept and used (excepting the template, but even that serves as a nice example to follow for people who are newer). Mainly the only changes are to add validation code and some business logic here or there depending on how complex the behavior needs to be (again mainly validation). The generated code is a big help, and we still use it for every new model despite being able to easily add new stuff manually.
> 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].
It is only sound advice if you already know Python/Django really well and don't mind context-switching your language. If you know Elixir/Phoenix well, you can easily crank out simple sites that don't use any real-time stuff as well as any other framework, and you get the added benefit of blazing fast (pre-compiled) templates and a highly robust database connection pool. Personally I prefer to keep as much as possible in the same language/ecosystem rather than having to straddle.
sticking within a single capable ecosystem is optimal here-and-now but your mileage might vary as we go forward. its always hard to forecast but even if you discount alot of the ML/AI hype, its quite likely that 2-3 years from now expectations will be for much "smarter" services.
whether delivering such upgrade can be achieved with microservices and API's or whether a platform can deliver functioning "monoliths" that compete also in such a new landscape is not clear (not to me anyway)
Concurrency is a pet use case for 99% of projects. Library ecosystem is the primary and dominant factor when choosing general-purpose technologies and Python has it beat.
In a multi core world concurrency and parallelism are no longer pet use cases.
Unfortunately The slowness of python, gil and really bad design choices of Asyncio in python 3 relative to how elegant parallelism and concurrent programming is in Racket, haskell, elixir and erlang make python a non starter for many basic use cases
This is absolutely not true, because most of the industry uses Python for web services and serving web pages is still the same thing as it was 20 years ago. You scale by bringing in more processes.
Multicore concurrency is still a pet use case because high performance is still a minority of applications and async programming is not necessarily faster, per many benchmarks. Most companies will rewrite the high-performance component in the proper manner and continue to do everything else the way they did.
Nobody's writing production Haskell or Erlang for this save maybe a half-dozen companies; it's all C++ or Java, and it represents a very small minority of the code as critical paths are usually tiny slivers of a codebase.
Real time like a chat app, or a video game or something. Not just a fast site. Seems like most "real-time" sites are slower as they have a harder time taking advantage of caching and the like, or use a lot of slow client-side javascript that inevitably works poorly.
Basically if you need the server to be able to change the data a user is currently looking at, collaborative multi-user stuff mostly. Liveview could be great if you're building google docs, but you could probably build youtube using just a more traditional framework like django.
Been looking at CRDTs lately for this, sounds like Elixir would be a good fit. Although what I've seen before has used C++ or Rust? to compile to wasm for the graphics part of the front end. Do all these technologies work together well?
Phoenix has used CDRTs going back to version 1.2 when Phoenix Presence was introduced. Here's a podcast about it (2016): https://changelog.com/podcast/208
Not really. Real time is not the same as super-fast. You can be real time but super slow or super fast using traditional request/response web apps.
When I mentioned real-time I was talking about apps that need to use web sockets to have fast client-server communication. There aren't many apps where this is required (or worth it).
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 "visibility" of frameworks and the onboarding "ease" are important features for many reasons but there are more attributes that shape people's choices. Talking primarily about open source ecosystems, being able to economise on resources is a major advantage. A "hello world" web app or a "neural net without dependencies" might be quick to do in any modern language but one major pathway to add value is when non-trivial domains are represented in usable detail. This is where a community culture that promotes pooling resources behind a few core libraries or frameworks plays an important role. It enables building on top a second layer of abstractions, plugins, interoperable API's et. Django is one example but the Python world has also "one stack" for numerical calculations (numpy, pandas and friends) and that was maybe more instrumental for adoption.
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.
Yeah, for a big complicated system, I don't think defining everything in models is great. I don't do that, and it's also not how fastcomments is built.
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.
Yes, I skimmed through that and was surprised to see it be compared to Django. It's different.
Django is for building CRUD apps quickly. That's it. It's not for the long haul of super complicated apps, which many projects don't ever reach before they fail/get abandoned.
I agree that there are better options for long-term maintenance of large projects, but let's not act like Youtube or Instagram don't exist - both of which used Django to some (high at the beginning) degree.
99% of line-of-business apps are CRUD. There's nothing special about "super complicated apps" that isn't brought in by the Python ecosystem. Where exactly do you think Django fails in that regard?
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.
> 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.
Andreas pattern matches on the magic byte, then encoded string length, then the string (using the previous matched length), then an int, all in the function header, no if-else-try-catch mess.
What are the major differences between elixir and erlang? Does elixir lose some of the advantages of the rock solid erlang improved over the years at Ericsson
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.
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.