Domain State vs. UI State
When my company was a lot younger with a less mature team, I remember having the best time with Meteor because I could write Isomorphic code and everything just worked. I didn’t think about performance, nor was I concerned about clean code, I was trying to build features as quickly as possible. It wasn’t until we hired some really experienced people, from companies that have scaled applications to millions, that we started to evaluate the complexity of isomorphic code. There is so much state that exists in modern applications these days. As our designs and UX ambitions increase, the state of our client side applications increase. As data and analytics become more important, the state from our domain/database/server increases. As full-stack developers, how do we manage this complexity? I think there exists a fine line between the Client and Server. After some horror stories with client/server performance in isomorphic states, our solution was to separate these states and provide clean public APIs to manage both of them independently.
But what is STATE?
The truth is, there isn’t just one “State” in an application. State comes in different types and it’s best we clear up these types so we can manage efficient web applications.
Domain State is the state of the server side of your application. It is the state of the application given the domain it is written for. Let’s say I am writing a web application for a Grocery Store, we could expect to find typical states in the application: authentication, validations, error states, but we would also expect to find state/data specific to the industry of Supermarkets. This is called Domain Specific Business Logic, which applies to business logic written under the constraint of the industry it is written for.
Domain State comes from our server, as this state needs to persist across user sessions and helps us answer questions about of our users and even the health of application features.
I’m going to show you an example of Domain State using GraphQL queries.
In GraphQL we can write “queries”, or request certain data from our Domain state. Above we are querying our persistent data, “user” and for this user of id “1”, we would like an object with his/her name and a list of friends names as well.
The output would look like something like this:
Let’s write a query with more domain specifics:
Here we’re querying the jobs table for a certain id and asking back for domain specific data relating to jobs. This would look something like this:
The Domain State only represents half of the core state you need to manage. The browser represents that other half, and has its own responsibilities and capabilities. Browsers are “stateful” because they have the ability to store different pieces of information. While there are aspects of UI development in which we create stateless components, the majority of the browser’s capability is to store useful information the user has either typed in or configured. Browsers can also cache pages, set cookies, set tokens in local storage, load css, and that’s just talking about WEB BROWSERS.
In addition to web browsers our client side application architecture might also have some constructs for state management. For example, if you’re using React and have adopted a one way data flow, you are probably using some flavor of a FLUX library. Flux libraries aim to help engineers manage the client side concerns of state. Examples of this state could be hiding/showing user interface components, collecting user input, reacting to user interaction, or even displaying in relation to the size of a user’s screen. The list goes on.
Lets represent our UI State as Redux reducers:
In Redux, reducers explain how our UI State changes. You can see these are written as functions that describe, given the current state of the world, what the next state looks like.
To visualize our state tree:
Let’s say the user interacts with our button and sets off the visibilityOfButton function?
Separate your concerns
Let’s break this down further.
As a Client Application developer, this public API is all I need to know and frankly all I want to know. As the consumer of this API, I expect this interface to be stable with backwards-compatible changes. Changes to the API which are not backwards-compatible are new major versions to the API and are not expected to be frequent.
The client has to support and manage 2 types of application state. That of user interaction and that of the result in changes to the user within a certain Domain. With that, we need to manage our state in a clean and predictable way. Having separate APIs between client side state and domain state is integral in keeping your responsibilities low for the code you write. You don’t want your modules to have too much knowledge of outside systems. Just be careful when working with this, because mistakes can be costly! I’ll probably blog about some horror stories in state management soon :)
As an implementor of the API, our goals revolve around the stability and performance the API provides its end user. This is most likely the client application developer, or if you write full stack code, YOURSELF. I do not want to concern myself of UI state in my implementations of domain specific business logic. I may use several tools that help manage my state: databases, caches, web services, etc. but I don’t want to mix anything that doesn’t concern the pure server side implementation.
I use Redux as the public API to manage the UI state of my application. It is well documented and has a great community behind it. GraphQL is great to separate concerns even further. With GraphQL, the client requests state from the server in the form of a query. The GraphQL Server then puts together the state, possibly from many locations, and returns the client a representation of that domain state. The client can manage this state without putting constraints on how the server is built/managed.
As you can see, the types of state we have to manage gets complex the more our applications grow. Managing this complexity defines what we do as Software Engineers.
This post is part of a series called Mastering Meteor and Redux. You can read the course syllabus here. Follow me on Twitter @abhiaiyer and I’ll see you for the next chapter.