After you work with Phoenix/LiveView is soo hard to come back to anything else. I love the fact it's very opinionated and most times there's a right way to do things.
LiveView is game changer, same user experience (even better) with 10x better developer experience. No much dual state management and things just work.
While I agree wholeheartedly, I do want to point out that while it has opinions in its high quality documentation, it is in no way opinionated in the same way that something like Rails is. You can use Phoenix in the same way you'd use Sinatra or Flask or the like [0], there are just no generators for it. I just wanted to bring this up in case anyone would be put off to try it who is afraid opinionated frameworks. However, if you prefer the opinionated option and want to be given clear guidelines on how to solve many common problems, Phoenix does indeed have you covered :)
I'm always amazed by how malleable the BEAM and the patterns built on it can be. I don't think anyone predicted Erlang to (IMO) reign supreme in frontend development. I say this having written tens of thousands of lines of React and Svelte in production, on top of all the hobby projects over the years.
In hindsight it makes sense. Networked servers need resilience to failure, to keep running, and to make concurrency as painless as possible, especially as CPU cores count increases.
Off the top of my head there's not many languages that can easily handle a million processes on consumer hardware, while the developer only has to think in single threaded mode because deadlocks and data races are literally impossible.
If you're building a server of any kind, the BEAM is the bee's knees. You can always resort to using a sidecar process or a Rust NIF for the high performance hot path.
> million processes ... think in single threaded mode
This is a big component of the secret sauce. Writing top down, happy path code as if you're just exploring an idea and then decide to scale it to distributed nodes without changing the implementation is just absurdly practical and blows every other VM out of the park.
> while the developer only has to think in single threaded mode because deadlocks and data races are literally impossible
Does Elixir somehow automatically solve the case where a row in a database is loaded into memory simultaneously across multiple requests and a value is incremented? (can be easily solved with row locking, but still needs to be done explicitly at the application level)
Usually one would use Redis for this problem, and you have a Redis-like system (but based on pattern matching) native to OTP, ets.
If you need a global, cluster wide counter, spawn a process with name {:global, :whatever} and let it be the source of truth for this value.
Depending on the problem, there are multiple approaches you can take. And a single Postgres instance is able to deal with massive concurrency, there might not be any need for premature optimization when SQL transaction could do.
You get a concurrent request processing spread across all of your cpu/vcpu cores out of the box. The fallback controller pattern for error handling is incredible for boilerplate error handling. Worst case latency is very stable. The query builder/data mapper, Ecto, is IMO far better than ActiveRecor being more explicit and prevents N+1s out of the box. Eex is built on compile time linked lists rather than run time string interpolation like the options in Rails and Django.
> You get a concurrent request processing spread across all of your cpu/vcpu cores out of the box
That's neat, but this doesn't matter until you reach serious scale, as scaling a rails app horizontally by throwing more server instances works for a long time
> The fallback controller pattern for error handling is incredible for boilerplate error handling
Sounds just like controller inheritance in rails
> Worst case latency is very stable
So is rails, worst case latency is generally caused by slow SQL requests or having to render complex documents (which can be offloaded to the background easily)
> The query builder/data mapper, Ecto, is IMO far better than ActiveRecor being more explicit and prevents N+1s out of the box
I don't have a problem with ActiveRecord, and while N+1s are easy to create, there are a ton of tools to help prevent these in rails. Can be a hinderance for junior devs or devs without rails experience though
Once things get complex, you're gonna be writing SQL directly anyway
> Eex is built on compile time linked lists
Cool but sounds irrelevant for 99.9% of cases, string interpolation isn't what causes rails apps to be slow
I'd say those points deserve a deeper look. Take concurrency for example. It is not only about scaling, it can actually affect every step from development to production:
1. Development is faster if your compiler (or code loader), tasks, and everything else is using all cores by default.
2. You get concurrent testing out-of-the-box that can multiplex on both CPU and IO resources (important given how frequently folks complain about slow suites).
3. The ability to leverage concurrency in production often means less operational complexity. For example, you say you can offload complex documents rendering to a background tool. In Elixir this isn't necessarily a concern because there are no worries about "blocking the main thread". If you compare Phoenix Channels with Action Cable, in Action Cable you must avoid blocking the channel, so incoming messages are pushed to background workers which then pick it up and broadcast. This adds indirection and operational complexity. In Phoenix you just do the work from the channel. Even if you have a small app, it is fewer pieces and less to keep in your head.
At the end of the day, you may still think the bullet points from the previous reply are not sufficient, but I think they are worth digging a bit deeper (although I'm obviously biased). :)
1. makes sense, our app is limited locally because docker on mac is not fast
2. Our test suite is pretty good! It's limited by the longest test runs (basically selenium tests that are slow because browser interactions are slow), circleCI allows pretty easy parallel testing
3. I think the same reason we offload long-running rails processes still applies . The only thing a long running rails request blocks is further requests to that particular thread handling the long request. Usually some other request will end up getting queued to that thread which is the issue. So it's a load balancing issue, as well as a UX issue (you don't want an HTTP request to take 3 mins loading a long report). Unless Elixir can indefinitely spin up new threads, this is still a load balancing issue, determining which server incoming requests are routed to
We don't use action cable so I can't comment there
2. You should be running multiple Selenium instances (or equivalent) in parallel even on your machine (unless you run out of memory or CPUs).
3. Exactly. This is not a problem in Elixir. If it takes 3 minutes to render a request, all other incoming requests will progress and multiplex accordingly across multiple CPUs and IO threads. This also has a direct impact on the latency point brought up earlier.
Let me quickly address these to the best of my ability, knowing Jose's answers are probably better :)
> That's neat, but this doesn't matter until you reach serious scale, as scaling a rails app horizontally by throwing more server instances works for a long time
You can do that, but its cheaper to get more out of each cpu and Elixir/BEAM give you that for free with a similarly flexible dynamic language.
> Sounds just like controller inheritance in rails
Not exactly, it works on the basis of pattern matching and the Fallback functions are included into the plug (think Rack) pipeline. This makes it faster and you don't have the problems of inherited methods stepping on each other. You also get to match on really specific shapes and cases to handle really granular errors without much effort or cognitive overhead, and you don't need to do things like catching errors like people often do in Rails controller error handling with rescue_from.
> So is rails, worst case latency is generally caused by slow SQL requests or having to render complex documents (which can be offloaded to the background easily)
You elixir application will often be doing things like background work and managing a key value store. You can do all of this and saturate the cpu without latency exploding. The scheduler in the BEAM will de-schedule long running processes and put them in the back of the run queue. Again, you get this for free.
> I don't have a problem with ActiveRecord, and while N+1s are easy to create, there are a ton of tools to help prevent these in rails. Can be a hinderance for junior devs or devs without rails experience though
That's all well and good but it's a nice feature in Ecto. Ecto also hews closer to SQL, and you can compose reusable pieces of queries in a way that is far more manageable than anything ActiveRecord scopes offer. We (where I work) write anything short of complex CTEs in Ecto's DSL, a lot of stuff I'd never try to do with ActiveRecord. It's just a lot closer to SQL and gets some nice compile time assurances.
> Cool but sounds irrelevant for 99.9% of cases, string interpolation isn't what causes rails apps to be slow
Rendering collections of nested partials in Rails has always been slow and eats memory. This isn't an issue with EEX. They also render faster locally.
I have tried Liveview and I have looked at alternatives and I have to say that even if I don't use Phoenix or Elixir on daily basis, Liveview is easily the best out there.
The developer experience is great and Phoenix is just a great framework. The speed in which one can create stuff is mind blowing which is going to be the biggest pull factor into the language imo. My main issue is that Elixir is great for a lot of hard problems but for the easy, common problems it is lacking a lot in libraries and so on. It also has a high learning curve.
Although it is probably just going to get better in time the learning curve will probably not.
IME a lot of the learning curve is functional programming, shortly followed by OTP. If you've ever worked with a functional language picking up on the OTP abstractions (eg. GenServer) is a small hill to climb in order to become effective on a day-to-day basis.
That said, with every new language comes idioms, tools and libraries that one has to learn, but this is true for all languages.
True and honestly, as an experienced developer it wasn't that huge of a step to start coding in Elixir. It's just that I (at least) is still thinking in an object-oriented way even when I'm working in Elixir because that is what I am used to.
I think the hardest part is to let go of some of the old practices and embrace functional programming as much as you can.
I would like to work with elixir professionally but have yet to find an employer that uses it in production :)
Yeah, 100%. I'd say half or more of the Elixir devs I've hired had no Elixir experience before. I've found most people pick up the basics easily, and the language is super approachable.
What libraries are missing? So far, I've only missed having a library for interacting with Google Sheets. I got around that with a Lambda running Python. Everything else either had an Elixir library or there was no library in any language.
Well.. tons of specific libraries are obviously not there that exist in other languages that makes completing tasks faster.
And even if they do exist, the documentation is often very sparse or the library is not super actively maintained like in the big popular languages.
These are all stuff that obviously only get better with time and when people start working with elixir. It's not something that makes Elixir bad, it is just that you have to take that into account that when you want to do something very specific with an image or want that api wrapper for that api that isn't well known then you 'll have to implement it yourself instead of relying on some third party package.
I read somewhere that it's good to learn new prog language every some time but there's not enough time in one's life (especially after having kid(s)). So I used Elixir (Phoenix/Ecto) on a new project some 18months ago and every project I start now is using that tech stack!
The best thing for someone like me (back-end dev) is no need to write JavaScript, care about zillions of build systems, having the Node/npm drama yet I can create nice and "progressive" web apps. In fact one of the projects I'm building is a powerful online forms builder.
I haven't read the entire article but my biggest complaint is the lack of tutorials to deal with the new way of defining forms and tables using the new function components in Phoenix 1.7. Yes, the official documents do explain how function components (in general) work and are defined but what I really wanted was a superficial guide to use specific components without delving into the internals. I did bite the bullet and read the documentation and looked at the source code but I feel I didn't really need to do it. Just tell me the new tags I could use, what the attributes mean but I don't need to know how the sausage is made.
I love working with Elixir and hope to be able to find a new gig where I can continue doing that. That's the hardest part unfortunately still.
But more ontopic, has anyone here already used these LiveView Streams in production? Based on this example it feels like I'm having to manage a lot more myself with the only real advantage being less memory usage, right?
I'm just wondering where/when it makes sense to play with this instead of, for example, temporary_assigns with phx-update="append". Are there more advantages than the memory usage reduction?
I refactored my profiling library to use them. They reduce the amount of stuff to manage. Instead of keeping a whole list of stuff organise, you just pass stuff to the stream and everything just works with good diff.
It seems to look very similar but I didn't see whether LiveView has the "sticky" websocket server requirement like Blazor. With Blazor all of the user's state is in memory on one specific app server. And if a connection is lost the app is completely unresponsive.
It's a great dev experience but I've seen comments about scaling and interaction latency concerns. Seems like it'd be great for intranet corp apps.
Is anyone running either tech as a public facing service?
Hey vryotek, short version: stickiness is not necessary or important. It does use a websocket.
To elaborate a bit, while each LiveView client is indeed associated with a long lived process in the LiveView server, the Phoenix framework provides hooks and other lifecycle management tools to minimize the impact of disconnects from eg blue green server deploys. Most interestingly for example with forms, the "automatic form recovery" does a process where when the reconnect happens it delays re-rendering until the client side has had a chance to send the current form state back to the server and allow it to synchronize.
> I wonder if the framework is particularly tied to Elixir or if it could be done in a more popular language so more people will take it up.
All programming languages are Turing-complete thus compatible. So you shan't need much more than Brainfuck.
But if you consider all the benefits the language and the platform it sits on (the BEAM) provides, no, you cannot do Live View as easily and comfortably than you can do on Elixir. Because its model is strongly tied to lightweight processes, message passing, mailboxes and pattern matching.
You can implement Live View in assembly or Python or Rust, but it's not going to be very quite as ergonomic and productive.
Also, you don't need to know Erlang to be productive in Elixir, but knowing the Erlang ecosystem (i.e. OTP) is going to pay dividends, since it's very powerful and at your fingertips from the Ruby-like comfort of Elixir.
>All programming languages are Turing-complete thus compatible. So you shan't need much more than Brainfuck.
XSL-T 1.0 is Turing complete but you can't really write a C compiler in it - despite what some people may have been heard to claim at various XML conferences in 2000 - because what matters in most things is what rights and accesses the language offers you and XSL-T 1.0 does not give you the possibility of loading in non-XML files.
You really don't need to learn Erlang. Would it help to understand some of the deeper stuff in some libraries or the beam itself? Sure, but then you could argue you need to learn Javascript and C to use Node because a lot of low-level stuff in node is C. Will it help to become a better Node dev? Probably doesn't hurt but you def don't need to learn C to work with Node.
When you learn Elixir, you basically also learn Erlang semantics, with only the syntactic details to work out later. Plus you get a few extra perks, like macros.
> I wonder if the framework is particularly tied to Elixir or if it could be done in a more popular language so more people will take it up.
My understanding of the origin of Phoenix is that Chris McCord tried to create something like LiveView in Ruby, but the concurrency system didn't support the vision he had for how it would work. He cast around a bit, discovered Elixir and create Phoenix and then LiveView.
The concurrency story in other languages is improving over time, but they're still trying to catch up with what Erlang was doing in the 80s. Building complicated applications on top of the BEAM and OTP is a joy compared to any other system that I've used. You learn a few simple approaches, and many things you've had to think about just go completely away.
This is true, but I would add an asterisk. While not knowing Erlang is not a hard requirement, eventually, you will greatly benefit from being able to read and write some basic Erlang.
That said, learning Elixir first will at least get you in the right mindset, and then Erlang becomes an easy lesson in syntax.
> I wonder if the framework is particularly tied to Elixir or if it could be done in a more popular language so more people will take it up.
As others have pointed out there already are lots (missing at present are LiveWire and there is even a LiveView.js that uses the same JS that Phoenix LiveView uses... it's a very unfortunate name).
Having said that, most of these implementations aren't "live" in the same way you get with the Erlang virtual machine where each user has a dedicated process. It's at least possible in Go, but most of these other implementations resort to AJAX and the like.
When I've seen LiveView mentioned in the past, the one major problem seems to be its reliance on sockets, which causes problems in certain environments and also can cause too much latency on slow internet connections.
An example of the kind of problems is at [1]. It's not hard to find other such discussions.
The other thing I wonder about is cross-platform. If you're using something like React or Flutter there are various solutions. But I haven't run across anything substantial that's oriented towards Phoenix LiveView.
The fallback to polling is generally a good solution. I think the sorts of problems that dev ran into are very much the exception, not the rule, given the kind of absurd environment they were working in. Also worth calling out that LiveView was _very_ new when that post was made.
The latency issue is a real one. Long polling can also help there, but realistically if a substantial portion of your user base is on poor connections you’re going to be much better off with a traditional server rendered web application than something like LiveView or a SPA.
I’m not sure what you mean about cross-platform. LiveView is for building web apps, so there’s only really one platform to speak of: the browser.
> I’m not sure what you mean about cross-platform. LiveView is for building web apps, so there’s only really one platform to speak of: the browser.
Similarly, React is for web apps but React Native has emerged such that your knowledge and some code can carry over, and now there's even React Native for Web so that you can write React Native and run it on the web in a way that at least tries to maximize code portability. It sounds like there hasn't been an emergence of equivalent tools with LiveView... but that's fine. As you say, LiveView is for the web and if that's the one thing you're targeting, especially for an internal app so internet connectivity is reliable, it's fantastic and possibly the best solution that exists now. There's certainly nothing wrong with making a great tool to full a particular (major) need!!
Everytime LiveView or Phoenix pops up here in HN, people always mentions how much they enjoy the framework. It feels to me like it's something I am missing out on?
I am Ruby/Rails developer myself and StimulusReflex seem to be the equivalent but idk, is my feeling true?
My dream stack that I am using for my business is Phoenix, Live View and Stimulus.js with Tailwind.
I have built projects on Laravel, Django, RoR, React and a long tail of in house frameworks, and nothing feels as good as this stack for web apps. Ruby on Rails is quite underrated, but the BEAM is a spaceship that fits neatly in the list of unknown unknowns for 99% of software engineers: they do not know what the BEAM can do for them. Its process and mailbox model feels futuristic in its expressiveness and simplicity.
It's easier than you think to get used to Elixir's functional language model. For me it was super easy, while with stuff like Haskell or Prolog I felt like I had to rewrite my brain from scratch.
To end my proselitism, I am adamant that the first Live View demo by McCord and Valim will have the same staying power if not popularity as DHH's first demo of Ruby on Rails which spawned the modern MVC framework architecture of the past 15 years.
The Live View model is in my eyes the next generation of interactive web architecture, the true successor to MVC.
For very small interactions, there is no need for a round trip and state held on the server.
Imagine a disappearing burger menu, or a tooltip widget, or a "click here to copy to clipboard" link. For those sprinkles of interactivity, you need JS and Stimulus is ideal for that use case.
Oh wow that's brilliant, I hadn't ever considered combining LiveView and Stimulus.js. If you don't mind me asking, what is the benefit over using `phx-hook`? Portability/interop with RoR, or?
Either way, I'm shipping it to production immediately!
phx-hook is a nice convenience that works only with Live View.
It seems to me a better investment of my time to learn a solution that's just as lightweight, but I can use everywhere (i.e. in other projects, or in static non-Liveview pages)
Makes a lot of sense, thank you! I'm not much into Rails these days, but that's one thing I really appreciate about RoR's "frontend" efforts - their work tends to be quite reusable across ecosystems, e.g. Stimulus, Turbo, and apparently even Hotwire itself [0]. Heck, that even seems to apply to a lot of their non-frontend stuff, such as MRSK [1].
Yeah RoR with those libraries are also moving towards the "as little JS as possible" approach as well.
Client-side logic makes sense in a vacuum, but then your crappy React app is in fact a distributed system, with all the complexity that entails. The radical idea of Liveview and similar efforts is that it's better just to return to basics and keep the logic on the server. It would be lunacy to try and build a distributed system with Javascript, yet that's the direction the SPA world is/was taking us.
Thanks for the info, most examples I'd seen of Stimulus.js used it for making server requests which seemed to double up with LiveView. Am I right that its main distinguisher over other JS frameworks is using controllers, and loading and initialising those on-demand?
I've never used alpine, so I'm not the one to ask. I've just given it a cursory look a couple years ago.
I do not like how it's trying to fit logic in custom HTML attributes. Doesn't look great to me, and would pollute my Liveview templates with a matryoshka doll of nested logic: There's a top-level Elixir module, which contains a HEEX string that creates HTML, which itself contains Alpine.js logic as an attribute.
Feels cleaner to me to just create a new .js file that exports a controller, and just instantiate it from LiveView (which still pollutes the HTML, but much less than Alpine does)
That said, there is no good or bad answer. Alpine or Stimulus are certainly better than instantiating Vue or React. HTMX could fit very nicely as well. Use what you're comfortable with.
Live View, I'm not sure which is the first demo. There's "Build a real-time Twitter clone in 15 minutes with LiveView and Phoenix 1.5" (https://www.youtube.com/watch?v=MZvmYaFkNJI)
The new LiveView streams are a good start - they are missing reordering though which is needed for lists but is not a normal property of a stream.
I've been working on a personal project which is very list heavy. I started it in pure LiveView using streams but ended up switching to a React SPA hosted in a non-updating LiveView div. Along with missing the reordering (which is needed a lot in the app) the amount of state I needed to hold on the server to wouldn't scale.
LiveView goes far beyond what htmx offers. Or at least makes it much more fully integrated across the whole stack.
htmx is a frontend library first and foremost, that dictates some patterns you may want to implement on the backend. LiveView is a backend-first framework, with excellent support for interactive frontend stuff.
It's done this way to collocate related (business) concerns. The views are in their own functions and don't contain any logic and, yes, they can be pushed into separate template files if that's what you prefer. This has been a thing since React came out and its merits have been debated to death already.
Ha, yes, I've been saying this since long before React (I don't actually use React). We were never doing "separation of concerns" even in the 2000s/2010s, simply separation of languages.
I noticed this in React and it's also a reason why I didn't like React. Fortunately or unfortunately, I've never had occasion to use React in prod. lol. Can you point me at any of the debates you mentioned so I can catch up?
In Rails this would have been a "partial" with some underscored filename
I assume searching for "JSX sucks" would do it. I certainly haven't bookmarked any debates from the past 10 years, lol. Incidentally JSX is the only thing I like about React. I find components are much more flexible and cohesive than partials (Rails was my thing for years and I still have a soft spot for it). But to each their own and I no longer enjoy debating it!
I sometimes just like to look at code and ignore the rest since it's not something I have experience with. But damn this is some next level ugly mess of code in my eyes.
LiveView is game changer, same user experience (even better) with 10x better developer experience. No much dual state management and things just work.