Originally posted on github.
In the early days of networked computing, mainframes did all the heavy lifting: users connected to massive machines with video terminals that could do little more than send and receive text. Then in the 1970s, personal computers came along and made it possible to do serious computing on the client-side as servers handled tasks like authentication and storage in many networks. The rise of the internet in the 1990s swung the pendulum back to the server, with web browsers taking on a role not unlike terminals in the mainframe era.
Phoenix isn’t the first platform to offer a way for back-end developers to create front-end interfaces—Microsoft’s ASP.NET Web Forms for Microsoft .NET existed back in 2002—but it did inspire many new tools. Caldara for Node.js, Livewire for the PHP framework Laravel, and StimulusReflex for Ruby on Rails, to name a few. Microsoft, meanwhile, released a new .NET feature called Blazor Server that modernizes the old Web Forms idea.
“My goal is not to get rid of single-page applications, but to obviate them for a large class of applications,” Phoenix creator Chris McCord says.
My goal is not to get rid of single-page applications, but to obviate them for a large class of applications.
The (not so) good old days of web development
Let’s say it’s 1997, and you want to make a web-based calendar app. In these early days of the web, your app would live almost entirely on the server. The server would render a static page with your appointments for each day, organized in a table of 31 boxes. You wouldn’t be able to drag and drop appointments from day to day. Instead, you’d have to include a form at the bottom of the page to add a new appointment to the calendar. Clicking the “submit” button would send the data to a server, which would store it in a database and render a new version of the page to reflect the change. In short, updating one day would require the whole page to refresh.
For many applications, those trade-offs are worth it—for example calendars that need offline support or games that require a lot of client-side application logic. But Phoenix creator Chris McCord argues that for applications that rely heavily on a network connection, it makes more sense to handle application logic and page rendering on the server side.
McCord originally wanted to create a similar experience for Ruby on Rails, so he created a library called render-sync that could re-render partials on the server and send them to the browser via WebSockets. But he wasn’t happy with the performance of render-sync. He wanted something faster and more responsive than Rails, which wasn’t designed for real-time applications. After evaluating several other programming platforms, he landed on the Elixir language for the Erlang platform.
Erlang was created by a team at Ericsson in 1986 to power telecommunications applications. “They were dealing with distributed systems very early,” McCord says. “They weren’t worried about multi-core systems yet because they didn’t exist, but the architecture they created was perfect for the future of computing.”
Crucially, Erlang was engineered around the need to support massive numbers of concurrent users. “Elixir will run millions of lightweight threads,” McCord says. But what really sets Erlang apart, for McCord, is its ability to preschedule processes so that the CPU doesn’t get hung up on any single thread. That way, if one user starts some sort of particularly long, CPU-intensive process, other users don’t have to wait for that process to finish before they can complete their own.
While it’s possible to build this sort of fault tolerance into other platforms, McCord likes that Elixir makes it so easy to handle. “You don’t have to write your code in a special way,” he says. Elixir gave McCord confidence that he could create a server-side rendering system to support real-time applications with long-lived WebSocket connections between the server and the browser—not unlike a telnet or SSH connection. This enables developers create stateful applications, rather than having to “hydrate” either the client or the server with application, as the old ASP.NET WebForms system did.
McCord started building the Phoenix framework for Elixir with an eye towards eventually adding the LiveView feature. “LiveView was always the end game, but I needed to do the plumbing first,” McCord says.
“LiveView was always the end game, but I needed to do the plumbing first.”
Though McCord opted to build LiveView on Elixir instead of Ruby, there are now a few different approaches to building real-time front-end interfaces in Ruby on Rails. One is StimulusReflex, created by Nate Hopkins. Another is Hotwire, a set of tools for building real-time, WebSocket-based Rails applications, developed by Basecamp for its own Hey.com email service.
Rails developers say this new crop of tools suits their needs. Matt E. Patterson, a developer at Atlas Obscura who worked with both StimulusReflex and Hotwire in a previous role, says that even though Rails has historically been able to scale to meet the demands of a wide variety of users. “I’m not going to say Ruby is the fastest language, but most of the scalability issues people see in the real world are related to running too many badly written database queries and have nothing to do with Ruby or Rails,” he says. There are plenty of applications that don’t need to support tens or hundreds of thousands of simultaneous users. In these cases it might not be worth it for developers to learn not only a new programming language but also an entirely new paradigm. That’s a big part of why the core ideas behind LiveView are finding their way into so many different languages and platforms. When Caleb Porzio saw McCord’s LiveView demo in 2018, he was inspired to create a version for the PHP framework Laravel. “I had just left my job and I was supposed to take a break from work and coding,” he says. “But on the second day of my sabbatical, I watched Chris’s presentation on LiveView. It really popped for me. I realized you could take Laravel to a whole new level.” He created the first prototype of what would eventually become Livewire for Laravel in a single day.
Porzio first tried to make Livewire work much like LiveView. “I had these long-lived processes running on the back-end using WebSockets,” Porzio says. “But PHP isn’t really built for that.” He wanted something that would work well on existing PHP infrastructure without the need to create custom architectures. So he switched to using AJAX requests to pass state back and forth from browser to server. In other words, Livewire isn’t technically “live” in the same way Phoenix LiveView is. “But we can fake it pretty well,” Porzio jokes.
Yes, this is slower than opening an always-on connection that maintains state. But Livewire does a few things to make this more efficient, like prefetching. And Livewire is able to avoid addressing certain pitfalls, like what to do if a user’s connection breaks.
The end of the pendulum?
Vue creator Evan You agrees. “I don’t think either model is fundamentally superior to the other, they come with different trade-offs and it really depends on the type of app that is being built and what mental model/language the developers feel they are more productive with,” You says.
Meanwhile, the line between front-end and back-end frameworks is blurring. For example, a forthcoming feature called React Server Components gives React the ability to offload more computing to the server. Today, the library’s server-side rendering simply renders a set of UI elements and sends them to the browser. From then on, application logic runs in the browser. But with Server Components, some of a React application’s logic will run on the server. Conceptually, it’s similar to Phoenix LiveView, but differs in that state is maintained in the client rather than on the server. This makes sense for an application that runs most of its logic in the browser.
Perhaps what we’re seeing is not so much a pendulum swing, but a state of equilibrium where computing happens on both client and server in equal measure depending on the needs of the user.