Connecting front end and back end side is difficult. The main problem is the protocol itself. It is stateless. Connection is being re-created each time. HTTP/2 changes this behavior a little bit, but this is the transport layer only. Multiple requests/responses can be handled in a different order. It means there are many traps waiting for a developer.
Another problem is that front end developers have their own world of SPA. They are focused more on the UI part and its responsive design, than on the whole system picture. But the software is not only UI. The back end solutions based on Message Bus are way outside of their way of thinking about application. They like “REST” world, because their first impression is that it is simple and safe. They need to make a request and wait or react on response. Later, they are surprised that they need to add retries etc.
The reality is different. When you create a WEB application your goal should be to create an equivalent of Windows Forms application. I know it is sounds strange, but from user perspective this is exactly what should be expected. A good application should behave like desktop one. But this means that you have to change your communication layer with back end as well. It should be asynchronous not only at HTTP level, but on a logical level as well. Do not be afraid of the reaction of end user. People are familiar with this model when they send e-mails to co-workers with a request and react on response. If a co-worker does not respond in a specified time-frame, they escalate. This is a standard in big corporations. Why your application should not follow this rule? When a manager requests something from you, they do not stand at your back waiting for a result. Effective world is asynchronous.
When SignalR appeared on the market, my main thought was that developers would catch an idea of messaging between front end and back end. Especially, since it gives them some kind of “abstraction layer”. Unfortunately, this did not happened. Maybe there are solutions using SignalR that way, but the community does not talk a lot about it. And I am not talking about games 😉 . I guess that one of the reasons is that SignalR does not implement reliability of delivered messages. But, to be honest, how many of you are thinking about reliability in the first place? Implementation of reliability itself is difficult, but I think SignalR helps a lot with its Hub model.
Secondly, and more sadly, synchronous thinking is easier than reactive programming. Yes, you read reactive. Good design needs a lot of design patterns mixed together to create an easily developed solution. You do not use a hammer to solve all your problems. You should use adequate tools, patterns and techniques to develop good software. Message passing by its asynchronous model gives you a multi-tool for highly scalable architecture. Service Bus itself gives you an abstraction layer which makes you follow SOLID principles.
Various developers and architects try to help with this aspect (check e.g. this presentation Powering front end apps with NServiceBus). Authors of that presentation focused on message response and various methods of failure handling. The main issue is what happens when your browser reconnects into a different WEB server. Remember that your browser is not permanently connected with the server. So you have to handle answers from the server in a different way. What is missing in this presentation, in my opinion, is the real scaling out. Even an ignored message has to be delivered. So, in my view, network resources are wasted with broadcast approach. If you add reliable message delivery into SignalR and you use NService SAGA emulating Actor Model, you should scale out this solution better. One actor per client should solve the problem. Solution which I can see, is more complicated and that is the reason why they did not propose it, but I guess they have something similar in mind anyway. My solution creates something like Message Store or Event Store (maybe less politically correct with NServiseBus philosophy 😉 ), but in my opinion one aggregate per user gives you real scaling out solution.
Description: When a browser reconnects into the second WEB server, the second WEB server registers to Actor by control queue with last handled message ID. Actor re-sends all messages to a newly registered WEB server. WEB server forwards them to the browser. First WEB server ignores all messages, because the browser is disconnected. Browser is a source of truth for the last handled message ID.
If you create SAGA per user, you can handle messages at server side. Key value or document store (they are using a kind of hashing distribution function) gives you the real scalability. WEB server only has to “know” which partition contains data and messages assigned to the user. Another option – WEB server can be absolutely stupid and register connected front end client on NServiceBus SAGA “actor”. In this case “actor” will forward messages to registered WEB server, which will forward messages to the browser.
When browser loses connection, it has to ask the WEB server for missing messages. This is the exact solution presented by Event Source solution and its subscriber model. This presentation of Greg Young GOTO 2014 • Event Sourcing • Greg Young explains how to do that in 38th minute. But if we create a reliable connection between browser and WEB server, I guess we do not want to rebuild the aggregate state at browser level. Some kind of proxy calculating the state is better.
By mixing these few solutions you can prepare a really scalable front end platform. SignalR client library can be run in your .Net application as well. Conclusion ? You can create mobile application as well as desktop layer using the same library. With this “actor” model at server side, you can coordinates various clients’ applications and prepare their state as well. I guess you are using your mail client as a mobile application and a web application sometimes at the same time. Do you think that the “actor” model is a bad idea to realize it in the way described? So if this model works for mails, why do not use it for other applications? I have chosen NServiceBus as an example, because it internally guarantees reliability of message delivery. So the only problem to be solved is front end and back end channel reliability.
There are more solutions on the market waiting for you. To realize the actor model you can use e.g AKKA.NET as well. This framework solves more scalability issues. The main problem is that it is more a tool for customization, as I understand. By using it you have take care of reliability on your own.