We are considering writing a very large scale public facing web application using Phoenix LiveView. Considering the internal customer for which the application is developed, we know that the application will be used by millions of simultaneous users, and we expect huge spikes of growth (tens of thousands to hundreds of thousands of people).
We initially intended to write the application as a Single Page Application using typescript like we are used to. However the issue is that this particular application has a number of features and sections that we do not want curious people to learn about by reading or reverse engineering the client-side source code.
Clarifying our use case
This is not about secret algorithms (such things are safely running on the server), but to make a long story short, the operational model of the company leaks in the domain model of the source code but users and curious competitors must never know what’s going on behind the scenes. This is not adtech so we’re not doing any spying or shady stuff, simply the business processes, and the business model - literally speaking - have a lot of value.
This is akin to having all your family members impressed by the way every time they come for barbecue they find the time spent at your home exceptionally enjoyable. However they are not aware that the reason for this consistently exceptional experience is that you prepare their visit in a professional manner using an operational model similar to the one of an hotel resort. Among many other things, you do not want them to know that you refer to them as “clients” internally, to them this is just a family meal and this has to remain that way.
My point is, there is a huge difference between the operational model perceived by users and the actual operational model of the company, and very often we simply do not want users to know that certain features and processes exist. Therefore, we cannot let funny JSON objects representing our domain model appear in the network tab of developer tools .
Phoenix LiveView vs Blazor Server
Because we usually use .NET for our backends, we were attracted by Blazor Server. The benefits are: server-side rendering ensuring that the domain model never leaves our server and that only the DOM is sent to clients, a component-based model allowing us to build the application as a composition of various UI-components, and the ability to use our back-end code without needing to build an API layer first.
The only - but huge - downside I see, is the scalability of Blazor Server. Apparently 3.5gb of memory is required to serve about 5,000 users and 14gb to serve about 20,000 users. I find it 1 or even 2 orders of magnitude too costly, and this is already having an impact on the business decision we make. For example, the product was initially supposed to have newspaper-like modules providing a modern and interactive user experience for a niche yet massive audience severely lacking this offering, but the traffic profile of such a module (hundreds of thousands to millions of daily users bringing in no income to the business - since we are actually against ads) made it prohibitive at such costs so we had to reduce our vision.
I recently came across Phoenix and LiveView and realized that this could actually be a great fit, considering the fact that the whole stack was built for scalability, and I have seen inspiring phoenix benchmarks. The developer productivity story is great, and the .NET backend would not limit us in terms of scaling since we use a middleware based on a Virtual Actor Framework. The benefits would be:
- Much better scalability, Phoenix would allow us to accommodate any load in a cost-efficient manner.
- WAY MORE better handling of disconnects and application updates (the client can reconnect to any server, the client-side viewmodel is sent again upon reconnects etc…).
- Generally speak, in addition to looking like the whole stack has been built for this kind of use from day 1, Phoenix seems more mature, robust and easy to reason about. While I love .NET for the backend, Microsoft’s ASP.NET offerings tend to be over-complicated and carry too much luggage for compatibility and historical reasons. So I’d welcome not having to use them for the front-end (I however do not feel convinced by the idea of switching to Elixir in the backend as on the one hand, I feel OOP is better suited to model evolving business domain models and at the same using a dynamic language in the backend is a big NO to me - but dynamic languages are fine in the front-end and even tend to simply things).
The downsides I can see for switching to Phoenix LiveView are:
- having to learn a new programming language. However I believe it is important that we be able to use the right tool for the right job especially when there is such a great alignment of stars. Beyond the efficient runtime of Elixir and Phoenix built on the Actor Model and BEAM, I am under the impression that UI building and diff-based re-rendering are a natural fit for functional programming.
- Need to write an API layer to bridge the gap between .NET and Elixir. But may be able to reduce the pain by using something like GraphQL. I am also pretty sure that we will need to develop specialized alternative clients anyway (desktop, mobile apps etc…) so having the API early may be a good idea to avoid developing bad habits that will make things more difficult for us down the road.
- and the one I am here to discuss: domain model leaks. In this Youtube video, the presenter shows that some data loaded by the LiveView component can be seen using the network tab of developer tools. This one could be the deal breaker for us, so I’d like to understand why JSON is sent over the wire if the DOM is rendered server side? And generally speaking, to which extent does this happen? I would expect that only HTML or DOM nodes be sent over the wire.
Beside this, if anyone has any top of the head recommendation on how we could reduce the pain of developing an API layer for consumption in Phoenix that would be great. I looked into using gRPC and GraphQL and it looks like the GraphQL library of elixir is more mature, ideally for selected solution elixir should be able to automatically generate client objects to consume the API (so that we only need to do this work once on the backend).
Thank you for your help!