How to save users from their own network connection

2023-12-20

Scroll to comments

The dilemma

Consider you have an app. It could be a web app, a native mobile app, or a desktop app. If you have a web app, we are going to assume the app is already client-side rendered and does not need to load from the server every time it is opened, as it is cached in a service worker. I talk about this kind of web app and its tradeoffs more in this article.

Setting that aside, whenever you have some data to store or some computation to do you have a critical decision:

Server-side or client-side

This decision is not just for web apps, but also for mobile apps and desktop apps, as they also might need to use cloud services. In this article, I justify a particular rule of thumb to use for making these decisions, the exceptions to this rule, and some general development tips which fit well with this rule.

Do things on the client-side if you can, and on the server-side if you must

The network connection

When you fetch data over the network, you are passing over a gigantic void of unpredictability, which you cannot control. Your users' devices are no longer tethered to a relatively stable wired connection. Many users will be using WiFi or cellular connections, and sometimes these connections can grow slow, congested or drop out completely. Users no longer have the patience to wait for slow network connections; we all know the three-second statistic.

The solution is to do everything that can be done on the client-side on the client. Here are some examples:

UsageClient/Server
Settings for a single deviceClient, only needed on that device
Social Media postServer, needs to be stored centrally so many users can access it
QR code scanClient, most devices are powerful enough to run QR code scanning code without needing cloud support
Access controlServer, the client side is not a trusted environment and therefore cannot perform access control in a trustworthy way
Running an LLM...

When a network connection is faster than doing the computation on the client

Consider the last example in the table. With our rule, we would run it on the client, as technically it can be run on the client, but on most devices it would be far faster to run it on a server and wait for the dreaded network connection. If, for a significant proportion of your users, it is faster to do a computation on the server than on the client, then its best to do it on the server if possible. Another approach if this proportion is not your entire user population, is to start the operation on the client and server in parallel, and when one finishes abort the other.

How to make the network more bearable

Sometimes you have to fetch across the network, like accessing a piece of shared data or something that needs access control. When this happens, we can still make some optimisations to make it feel more user-friendly. Here are some things you can do to improve your user experience for fetching server-side data:

This is not easy to implement yourself. You may want to use a data-fetching library, sometimes called an async state manager. This library will be responsible for syncing server-side state with a client-side "store", which your app can deal with, so you don't need to worry about the network as much. I personally use TanStack Query for web apps, and I've heard good things about SWR. I don't currently have any recommendations for native. Also for things like periodic sync and persistence you may need to do some extra configuration. For validation of network requests on the Web, I use zod.