Readit News logoReadit News
Posted by u/jstummbillig 3 years ago
Ask HN: So, what's up with Phoenix (web framework)?
While I have noticed that Phoenix is a thing people are generally happy about, I was surprised to see, that it beats the Loved/Dreaded section of the current stackoverflow survey by a staggering 20% over Express and RoR.

I suspect this is due to some rather fanatical following and coordinated effort to skew the outcome. Still, I am curious, specially since the latest blog update is nearly from one year ago, which gets me at least a little suspicious in web world.

Any takers? What's the current feeling around Phoenix? Is is the end all superior fullstack framework (at least form the devs side) this survey makes it out to be?

chrismccord · 3 years ago
Creator of Phoenix here. I was delightfully surprised to see Phoenix as most loved on the survey since I forgot SO survey was a thing this year. So we can rule out some coordinated voting effort. Truthfully, while we’re still a smaller community, the folks that find us tend to love us and stick around.
brightball · 3 years ago
Thanks Chris.

Phoenix revitalized my interest in programming at a time when I was so frustrated by the state of things that I was ready to change careers.

cultofmetatron · 3 years ago
On year 3 of a startup I cofounded in 2019. A lot of our success dealing with scaling and reliability for our users come directly from how well designed phoenix is. Channels and OTP power some of our killer features and I wouldn't envy someone trying to replicate what we have with javascript or go.

Some people say ecto is limited. I love that it lets sql be sql. It lets me think of the solution in sql and write that sql almost directly in elixir with better ergonomics (being able to make a subquery a separate variable that I join into is a HUGE improvement over raw sql). Those uses of fragment can easily just be turned into macros that integrate cleanly into ecto when I use them enough.

Thanks for one of the best developer experiences I ever worked with. when I have a side project, I'll be trying fly.io and I've already recommended it to other founders. We be using it if it was at its current state in 2020.

AlchemistCamp · 3 years ago
I've been using it for almost 6 years and I've found that the dev experience is fantastic and improving. That's why I stuck with it even after winding down the startup that pushed me to learn Elixir.

For 95% of web apps, I'd say Phoenix is the best option these days. It just solves a whole class of problems that send users of RoR and JS frameworks reaching for Redis, Sidekiq, etc. It's also great in terms of debuggability, which I'm now seeing in a project I've taken over that has immense technical debt.

As far as community buzz, I'd say it's been a slow, gradual growth. There have been more books, conferences and podcasts than I'd have expected for the size of the community, but it's still a fairly young and niche language.

The biggest weakness is lack of 3rd-party support. E.g., Stripe documentation will leave you hanging if you don't use a language they've written a client for: https://stripe.com/docs/payments/checkout/fulfill-orders

Dowwie · 3 years ago
What are you doing to handle replication among nodes? There's still a great reason to reach for Redis for caching and messaging despite using Elixir: when the Application crashes, the state is gone.

As for Stripe, some client developers have been code-generating their client with mixed success. ExAws, however, is essential.

liveoneggs · 3 years ago
replication is built in to mnesia and your "app" crashing really shouldn't be taking down the entire OTP on your local machine, so ETS would persist on a single node
yellowapple · 3 years ago
A lot of what's great about Phoenix is simply that it builds on top of Elixir, which is already great and which itself builds on top of Erlang/OTP, which is, too, already great; it's the "standing on the shoulders of giants" concept. The overlap between Phoenix devs and Elixir devs helps, too.

Phoenix ain't quite my cup of tea for the same reason Rails ain't my cup of tea: it's big, and it does little to hide that bigness. It's why, when I was doing web development on Elixir, I ended up gravitating to alternative frameworks (like Sugar - which, as a disclaimer, I'm a very inactive maintainer of), for the same reasons I tended to prefer Sinatra or Padrino over Rails. For most people, though, "bigness" ain't really a problem - and Phoenix does a really good job of being "Rails but actually good". At the end of the day, it's a solid choice that probably won't bite you in the ass, and that's what matters.

chrismccord · 3 years ago
Phoenix is actually quite small if you look at the source and patterns. It would be interesting to compare to other frameworks. We get a lot for free from the platform, so even if you include Phoenix pubsub the feature set for size of the framework is going to be unmatched because of the process model and distributed runtime. Here’s an entire Phoenix app in 50 LOC https://gist.github.com/Gazler/b4e92e9ab7527c7e326f19856f8a9...
yellowapple · 3 years ago
That's true. By the same virtue, though, Phoenix is big compared to most other Elixir web frameworks - which also get a lot for free from the platform (and even more for free from Plug). Of course you can ignore the vast majority of what Phoenix offers and churn out a 50-SLOC minimal example like that, but then why pull in an extra dependency when you could accomplish much of the same while just using Plug?
brightball · 3 years ago
One of the things I like most about Phoenix is actually the size.

Rails significantly slows down Ruby, while adding a lot of value.

Phoenix has a negligible effect on Elixir performance, while adding a lot of value.

throwawaymaths · 3 years ago
I don't think it's that really. Phoenix pushes a lot of things (especially expensive metaprogramming) to compile-time. For ruby to handle those sorts of things inherently adds cpu time.

I don't super love Phoenix, because a lot of it's metaprogramming stuff "breaks" elixir conventions, but I have to admit, I've done some really strange things with it and never worried about sleeping at night.

mstipetic · 3 years ago
After using Liveview it’s very hard for me to go back to normal full stack development, the separation between frontend and backend with some rest api seems so arbitrary to me. Especially with doing anything realtime, with your custom websocket protocols, sagas etc.

I’ve been consulting with a few startups and it’s crazy to see how much effort is duplicated and coordination needed even in cases where there’s no public api necessary.

ATM I’m working on a few side projects and I’m enjoying being able to build all of the functionality necessary alone without reaching for anything outside elixir+postgres.

The biggest issue is a pretty steep learning curve and lack of beginner friendly documentation, lots of tinkering and code reading is necessary when starting.

foldr · 3 years ago
LiveView is kind of magical when it works. Where I struggle with it is the constant need to decide between implementing UX logic directly in LiveView or implementing it purely on the client side via the JS helpers. Sometimes you really want the logic on the client side for latency reasons, but then you lose the ability to test it properly (unless you resort to Cypress or something like that).
josevalim · 3 years ago
Generally speaking, if it can be done in the client, it should be done in the client.

Phoenix.LiveView.JS aims to tackle the obvious cases but it also documents a pattern that I tend to use a lot in my apps: https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.JS.htm...

The pattern above has a benefit that the dispatch still comes from Phoenix, so you are not relying on IDs or query selectors to attach functionality. You can see how we use it in Livebook here: https://github.com/livebook-dev/livebook/blob/main/assets/js.... However, if the callbacks get too complex, then you may indeed want to test them via headless browsers.

throwawaymaths · 3 years ago
> Where I struggle with it is the constant need to decide between implementing UX logic directly in LiveView or implementing it purely on the client side via the JS helpers.

Welcome to the world of distributed systems. Who owns what piece of state is the perennial difficulty that has plagued developers forever.

You are right though, responsive testability suck with liveview (and honestly just about any be+fe system). I don't see why in the long run it shouldn't be possible to shove a JavaScript engine into the VM (I played around with doing this with mozjs for a bit -- may come back to it) and use it to store a dom for testing.

cultofmetatron · 3 years ago
after 8 years as a nodejs developer, elixir's concurrency and parrallelism toolkit is lightyears ahead. sagas, promises, channels.. Its all a joke compared to what elixir offers.

Phoenix gives me a network synced crdta backed data structures, multicluster websocket support with long polling fallback, supervision trees with long lived processes and a descent pubsub system out of the box. we've gone 2 years in production and haven't needed redis or rabbitmq yet. its allowed us to focus on delivering features without drowning in infrastructure.

mstipetic · 3 years ago
For me the most depressing thing has been - once I've seen the OTP library and everything elixir (well, erlang) provides, I've realized we've figured out most of the things like 30 years ago and have kept reinventing the wheel constantly, just because of not looking back and checking has it been solved already. Erlang's introspection tooling is better than 99% of what the market offers now as an expensive SaaS.
papito · 3 years ago
> it’s crazy to see how much effort is duplicated and coordination needed even in cases where there’s no public api necessary.

Probably because they decided to use microservices (read: distributed systems) for no God-loving reason.

sodapopcan · 3 years ago
Microservices aside, writing a web API so a single client can talk to a server is perverse in my books.
sahruum9 · 3 years ago
It's a distributed system either way.

Acknowledging that opens up a whole world of already thought through solutions to problems in distributed systems.

eterps · 3 years ago
> with your custom websocket protocols, sagas etc.

What is meant by sagas in this context?

mstipetic · 3 years ago
Something like https://redux-saga.js.org/, basically doing complex background workflows, something that feels like event-driven browser JS was not really built to do
AlchemistCamp · 3 years ago
Can you elaborate a bit on the "steep learning curve" bit? What took the most time and what do you wish you'd known sooner?
mstipetic · 3 years ago
Hey, big fan of AlchemistCamp! I'd say there's plenty of short snippets on specific functionality of phoenix, but not enough of content on how things fit together (what exactly do you use genservers for, where do you place things in a project, how do you organize your repo queries - do you pass objects or PKs around, how to refactor a complex function, how do nested livecomponents work and what happens to assigns when you route back, what's the difference between live_redirect, push_redirect, redirect etc.) These are the things off the top of my head that I've struggled with, and ultimately built something but in the back of my head I'm not REALLY sure if I did it correctly.

I've also really enjoyed Pragmatic Studio's course on OTP where they build a genserver from scratch, thay was eye opening, a few more in-depth courses would definitely be welcome.

JanSt · 3 years ago
Is it possible to pack a liveview application for the app store (i.e with capacitor)?
bostonvaulter2 · 3 years ago
I think you may be looking for this neat library: https://github.com/elixir-desktop/desktop

Although to be honest it boggles my that it's possible to accomplish this on iOS.

klohto · 3 years ago
Yes, there are several. I don't have examples on hand, but elixirforum will find a few.
mavelikara · 3 years ago
Does something like Storyboard exist for LiveView?
bostonvaulter2 · 3 years ago
Yes! (well I'm assuming you mean Storyboard). There's a new project that accomplishes just that: https://github.com/phenixdigital/phx_live_storybook
sb8244 · 3 years ago
Here's an analogy that I've been using lately that talks about why I love elixir.

When I wrote apps in other languages in the past, I felt like I was building a big skyscraper. Everything was sorta connected and it was difficult to add new doors into the project. I was sometimes limited to building something I wanted because the runtime just wouldn't allow it.

When I'm writing Elixir, it's like I'm building a city. Everything works in concert, but I could build a small building next to a skyscraper next to another building.

This is because of the runtime, not the language. It's easy to build self contained "apps" that are deployed with everything else but isolated. It let's me build the app I want rather than forcing me into a very specific way of building.

And just to be clear I'm not talking microservice, that would be like building multiple cities connected only by little roads.

I'm work shopping this analogy since it's not as clear and concise as I'd like :)

PS. I'm pretty active in the community and other private communities and didn't know about the survey. I would have a hard time imagining large scale survey orchestration given that.

klabb3 · 3 years ago
My experience using channels in Go, was that I replicated state across "actors", similar to microservices (which is one of many problems that microservices have vs a monolith). Worse, this state is not in sync, so you end up worrying a lot about logical race conditions (if you're paranoid like me). I ended up still using channels, but a single message bus with a single threaded dispatch loop.

I am curious about if redundant state and state synchronization tends to be an issue in medium-to-large Elixir apps? If not, how does one design the component/actor hierarchy to avoid such issues?

throwawaymaths · 3 years ago
You tend to not write concurrency in elixir. You tend to borrow concurrency from your libraries and frameworks, which usually are fairly buttoned down. Most websites are basically stateless data fetch/transformation agents, and even the stateful ones are usually one process. Why muck around with all that when your framework does the right thing for you out of the box?
bostonvaulter2 · 3 years ago
I'm not super familiar with channels in Go, but one way to avoid the need to synchronize state in Elixir is to use ETS (Erlang Term Storage) which is a way to store data (terms) in memory.

If the state is in ETS than (optionally) any process on the node can read the state. Often this is paired with a single process that is allowed to update the state so that the state is always updated atomically. Often this pattern means that you don't need to distribute the same state to multiple processes, because instead they can just read the state they need from ETS (which is pretty fast/cheap).

sb8244 · 3 years ago
I've worked on a variety of different size apps, but I haven't run into many issues with state synchronization yet. Generally, I try to keep data as close to its source of truth as I can. So if I need to synchronize state between actors, it would be to achieve a task and not to have duplicated data.

This could be an artifact of how I build systems. I have heard of some people that build really small actors and do a lot of data exchange. Without knowing details, I'd lean towards that being an anti-pattern.

toast0 · 3 years ago
So in Erlang (and I assume Elixir), the idiom is that the Process (Actor) holds the state. If you want to change the state, you send the Process a message, if you want to find out something about the state, you send the Process a message. You shouldn't be keeping the same state in multiple processes, because of all the problems you mention.

Sometimes you have requirements where it's hard to assign any given piece of state to a single actor though, that's going to be challenging in any language.

An ETS table (the OTP in-memory key/value database, more or less) is isomorphic with a Process that holds the data, although the reality is different. Mnesia if everything is done with transactions might be as well, although where I used mnesia, we did not use transactions and it was helpful to understand how the data flows between mnesia nodes, and when you might read outdated data.

sieabah · 3 years ago
Well each process has its own state, so if you needed to sync that you'd be storing it in mnesia, ets, or an external DB. Processes can watch and get messages about other processes if something were to succeed/fail.
dfee · 3 years ago
The analogy makes sense if you’re implying that it’s a monodeploy of apps - all on the same “plot of land”.

I’ve never used the language, so no feedback to the value of the claim, but that metaphor does resonate.

skrebbel · 3 years ago
We use phoenix for a few years or so, and it’s very decent. I disagree strongly with the crowd that says it’s the best thing since sliced bread, it’s, well, just a framework. It has the basics for oldschool mvc and real-time stuff, and for the rest you just write regular elixir code. It has some weird naming quirks and, to my taste, a bit too much macro magic but nothing that can’t be learned in a few days.

I don’t mean to downplay the humongous effort that goes into building any framework that doesn’t suck. Phoenix very much doesn’t suck. But it simply got all the basic right and then the true benefits come from it running in elixir/beam, which means you can skip all the job runners, redises, microservices etc.

I don’t know where you got the idea from that something is up with it. It’s chugging along great.

namaria · 3 years ago
>I don’t mean to downplay the humongous effort that goes into building any framework that doesn’t suck.

I think you captured something I've been mulling about recently. The perception of software quality should be on an inverted scale, like incident severity where zero is the worst possible outcome. Software can't be better then "works well, has little accidental complexity". But it can be much worse than that. People rave about pieces of software that do their job and get out of the way because they're so rare, and not because they are magical unicorns that cook you breakfast and give you massages. But because they fulfill expectations at a reasonable cost.

spapas82 · 3 years ago
Ah yes! I wrote a very extensive comment about phoenix vs django and forgot one of the biggest drawbacks of phoenix and ecto: the very very heavy macro usage. This is really problematic. When using Django and get an exception you can see the line that threw and (usually) understand the problem. When using phoenix if the error is on some macro related code, you are lost.

Also in Django you can easily follow the code to understand what's going on under the hood. This is not very easy in phoenix since macros are involved.

Don't get me wrong I understand that macros are used to make the code more ergonomic and avoid repeating stuff. However macros are so complicated and out of my league that I don't even try understanding them.

You should not need an IQ of 150 to understand a web framework. That's the reason phoenix w could never be widely adopted. People need a tool not a way to show off their intelligence.

josevalim · 3 years ago
While I agree that Ecto is macro heavy, I don’t agree with this assessment for Phoenix. Macros in Phoenix are mostly contained within the router and then Plug (which is a thin contract).

Perhaps there are other factors that make Phoenix harder to grasp in your experience but I hope pointing out that it may not be macros help peel some of the complexity away.

Furthermore, if you get a bad stacktrace in either Phoenix or Ecto, please open up a bug report. Macros should not and do not imply bad stacktraces. In a very simplistic way, you can think of the Elixir compiler as a huge macro, and it still strives for great error messages and stacktraces. Many Elixir building blocks are implemented with macros too, and we have great error messages and traces there, and we aim for the same in Ecto and Phoenix.

sodapopcan · 3 years ago
I was with until your unnecessary last comment, but I'll respond anyway.

Macros are a pretty important feature of Elixir that helped get it wider adoption. Without them, things become incredibly verbose. While I totally agree they can be hard to grok, there is absolutely nothing magical about them as they are expanded at compile-time. You can call `Macro.expand` on any AST and see the static code it generates.

Otherwise, with a good, well-documented framework like Phoenix, the majority of users should be able to just use it as-is without needing to show off their intelligence by diving into the underlying implementation ;) <3

PS, I've never had a problem when there's an error in a macro. The line in my app that failed is always in the stack-trace which is all I ever need to debug (though I do wish is drew my eye to it somehow).

signaleleven · 3 years ago
I'm not as much of a fan of the Elixir/Phoenix/LiveView stack like many here, so I'd like to respectfully share my experience.

First off, Phoenix fixes pretty much everything I didn't like about Ruby on Rails and when I need to write an API for a weekend side project that I need to turn out quickly, I'll choose it without question. If you want to use a convention-based framework that includes support for migrations and instant DB mapping, it works well. The documentation is excellent.

I personally would not choose it for a large enterprise codebase, or for something with a rich Ux that you can't control the designs for (ie. you have a Ux team that calls all the shots).

LiveView is interesting. I have found certain things overly difficult to do that are easy in the js-based frameworks. For instance, a UI that has a list of children that you want to add and remove in memory and then save at the end. Obviously you can do this, and I've done it a lot, but there are quirks with the interaction of changesets, ecto, and your form that make it tricky for newcomers. I think the tight coupling between changesets and the form gets strange as soon as the page gets complicated. Schemaless changesets work well for this, but this is more to add to the learning curve.

Understanding the interaction between LiveComponents and function components will be tricky for newcomers as soon as you are past trivial implementations. Knowing where the memory is stored and what a genserver is is super important, but not intuitive. Targeting a specific LiveComponent to receive events if you have one that has another as a child isn't intuitive. Unit testing a LiveComponent and a function component is pretty sweet, but there's a learning curve there and I ran into a few frustrating bugs that didn't help (they were fixed after a few weeks).

There's a lot of these examples. The interaction with client-side js has evolved a lot this year, but it's tricky in my opinion.

I have personally witnessed experienced, talented and smart Elixir developers struggle with LiveView. The learning curve is real.

I know Elixir people love this stuff deeply, but I don't think LiveView will win in the marketplace of ideas, even if Elixir and Phoenix gain traction. People who aren't already bought in to this stack won't be willing to build complex websites this way. I know Chris and Jose are reading this thread, and I have deep respect for their accomplishment and talent, but LiveView isn't going to be for me.

josevalim · 3 years ago
The pain points that you brought up (forms and live component exchange) are real and they are definitely in our radar.

For example, the new function components are meant to reduce the reliance on LiveComponent and ease the learning curve. We don’t have an answer for complex forms yet.

I truly think the programming model is solid and is the next step in building server driven interactive and real time applications. But we will definitely stumble here and there as we iron out the finer details. :) thanks for the feedback!

sodapopcan · 3 years ago
Good points but I do want to point out that LiveView is not yet at v1. As you said and see, Jose and Chris are listening :)
enumjorge · 3 years ago
In the several years I’ve worked as a dev professionally I’ve seen the same pattern happen over and over again: a new tech/library/framework comes out that develops a very vocal fanbase, it manages to gain widespread adoption/traction, with time the warts come out, eventually some people sour on the technology and we get an uptick on “Why our team moved away from X”, some more informed than others.

I’ve seen it happen in various degrees to React, Docker, Microservices, Kubernetes, Rust and I’m sure I’m forgetting others.

Certain problems in software are so complex, that there’s no one size fits all solution. The problem with the early fanbase is that it tends to be a self-selecting group in one way or another. When you read someone’s anecdote that library/framework X “was a delight” you don’t always know for example that it was maybe used by a group of 3 devs for a startup pulling $50k in MRR. Will the same apply for you team that is 10x bigger? Maybe. The opposite can be true where you have some project get open sourced by a tech giant which gets adopted by smaller teams with very different needs or resources.

My point is, if you hear outsized praise for something it’s likely because it’s early in the hype cycle or it hasn’t seen enough wide adoption. No solution is perfect.

It’s better to take a look yourself since no one else will know your or your teams needs and preferences. This is where the buzz can come in handy. It can highlight new technologies worth trying out. You’ll usually learn something new in the process.

claytongulick · 3 years ago
> I’ve seen it happen in various degrees to React, Docker, Microservices, Kubernetes, Rust and I’m sure I’m forgetting others.

MFC, vb3,4,5,6, entity framework (every version), OLE, COM, DCOM, ActiveX (all of which were basically the same thing), as2, as3, PureMVC, Cairngorm, Flex, asp, asp server controls, DAO, asp.net, php (and every php framework), Cold Fusion, CFCs, JSP, servelets, beans, spring, dojo, jQuery, ext, Google's JWC, backbone, moo tools, knockout, meteor, angular, angular (x), react

Just off the top of my head of hype trains I've ridden.

Now I'm all about simple.

Express + web components + postgres is the magic combination of simplicity, time to market, performance and community for me these days.

nazka · 3 years ago
Why not use NestJS?