ArchiveAboutFeed

On client state complexity

For some reason my development experiences have always been on the client side. Not because I wasn't interested in platforms or backends, but usually because I worked with people way more experienced than me. I did my share of work in mobile app development, and different client server apps on the web. The apps became larger and the complexity increased. I started by doing design and user experience development (poorly), and later I learned to work with designers, who knew more about making things look good and work well.

Another shiny new tool

As complexity increases solutions to tackle that complexity appear as well. We learn new tricks, new languages, new algorithms, new libraries or frameworks. And while these solutions tend to offer the promise that things will be better when using them, I have found the hard way that this wasn't always true. We tend to replace one type of complexity with another.

Right now, I am looking at a UI project that is based on Clojurescript, Re-frame, different time libraries (time and date calculations get messy very quickly in my experience), a library for charts, a library to crop images, a library to deal with zip, several libraries dealing with drawing stuff on maps, and (as so often) react. It is used at my company in a production environment.

Client and server

This UI project connects to a server where most of the actual complexity of the service is located. There are APIs to other platforms, there are databases, async processes, and user interaction via large API's that must be managed.

When you aren't an expert in everything, and perhaps do not have every expertise in house, you are forced to come up with solutions while learning about it. I suspect that often happens. While it usually works out fine, it tends to bite you at a later stage due to some unforeseen complexity. I've probably made every mistake in the book over time.

I struggled with implementing designs, as CSS development is a nightmare of its own, building UI components that weren't readily available in some library (you know how designers always want something slightly different from standard), getting API calls to work (especially handling the vast amount of possible 4xx errors elegantly).

These challenges are in the end minor issues compared to the one thing that is nearly impossible to get right imo, client state.

The complexity of client state

To me Client state is the most complex issue to manage. There is the obvious problem of figuring out if client and server state match, if the correct state is displayed, the correct event triggered, async processes, etc. In our universe, we are lucky to have Re-frame, probably one of the best Clojurescript frameworks, that helps a developer to tackle data flow inside user interfaces.

That still does not make it easy, although it makes it simpler. You must think about local databases, specs, events, subscriptions and ensure that data flows correctly through your client so that the user can accomplish whatever task he needs to do. Changes in data coming from the server lead to changes in the client code, and there must be some form of version control for each API call to ensure this can be managed.

The internal state

But there is also internal state (a lot of it). Think about buttons that can be pressed, a text displayed that might change colour if some event is detected, an input form field where the user types in a currency value, an incorrect input, the list is endlessly long. I've spent endless hours debugging client code where in many cases the ultimate issue was related to some internal state not being handled correctly. Or trying to trace events and subscriptions that did or did not fire, just to make sense of why something was failing.

And while I think I have learned enough about these tools to call myself an acceptable developer with Clojurescript UIs, I am changing my mind about the simplicity of it. I am beginning to think (and I am clearly not the only one, nor am I the owner of such ideas) that reducing state and state management in a client will make life simpler.

Yes, there are still issues that remain, and some of it could very well be related to things like speed, responsiveness, and efficiency. At the same time, there are plenty of use cases where there really is no need for a client to have as much local state, especially if that state is already available on the server. We aren't all building games or apps that require super-fast rendering.

A single source of truth

Imagine if there is only one source of truth, instead of two+. It would take away a lot of complexity from the client. No need to figure out if everything is still aligned. No need to perform complex reasoning over that state, or generating other or new state. There is just the server that holds state, and the end user that may or may not manipulate that state on the server using the tools the client provides.

This is not a new idea of course. There are already excellent solutions available to support this. In the Clojure world Datastar immediately comes to mind. And as a person that has been on the receiving end of having to manage this complexity, I think I would prefer to start my next UI project as a server-state project instead of using the usual path of client and server state solutions.

There are of course other things one might do. Things that really are easier to manage in a client (like component behaviour) will always have to work with some form of state, even if it is only within the component.

My journey with Web Components

It is one of the reasons I started experimenting with Web Components. Not because they offer the ultimate solution (they do not), but because using the browser platform might be a way to remove some of the complexity we currently see.

They can be utilised, whether it is done with client or with server state. And they are portable to any JS framework as they rely on the browser platform. There are downsides too, especially since they are pretty low-level objects, you will need a few things extra to make things like rendering on a screen simpler and more efficient.

It is an interesting journey, in which I am discovering the pros and cons of creating and using Web Components. As that journey is not over by a long shot, more on that in another post in the future.