Wednesday, June 22, 2022

State management and user interface design

In this post, I will address Clojure's management of state. The importance of persistent data structures, state models, temporal databases, etc will be considered in both the fields of human-computer interaction and concurrency.

Clojure's handling of state

Clojure handles state differently from most other programming languages. Clojure divides logical entities into two types, values and identities.
  • Values: immutable data
  • Identity: an entity associated with a series of values over time
Values do not have state and are therefore immutable. Identities have states, which are their values at certain points in time.

Principles of user interface design

The first principle of user interface design is to always respect a user's decisions. After the user does something, you should never open a modal dialog box saying "Are you sure?." Modal dialogs always take away attention from the user. At the same time, a user may actually change his mind or make a mistake, and need to go back.

The means of supporting this is universal undo. Every major graphical user interface application has some sort of undo functionality. Take web browsers as an example. The key feature of HTML is its support for hyperlinks, which let you browse from one web page to another. Browser's enable the handling of a user's browsing history with forwards and back buttons.

Another example is text editors. They always support undo/redo functionality so that as a user types he/she always has the option of going back to a previous time in his/her typing history. Paint programs, video editors, or basically anything else that supports changing an entity over time supports undo. Undo is already vital to a wide variety of graphical user interface applications.

The key to supporting undo is the temporal management of the state of an application over time. In order to support universal undo we need to move away from the naive view of state, and instead view it a series of values over time. A user may change his mind at any time, which necessitates that we need move the value of our identity back to what it was at an earlier point in time. Furthermore, state managament like this should always be the default in all kinds of graphical user interface applications.

Temporal databases

The implementation of changes in values over time can be provided by temporal databases. A temporal database is like an ordinary database, except it also records changes over time. This is like what we need for graphical user interface applications, as it can be used to model the change's in an application's state over a time provided by the user. These temporal databases will then be the means by which we implement undo.

Interactivity in general

We see that the reason we need to explicitly model state in human-computer interaction is that it involves two different entities interacting with one another. When a human and a computer come together, it necessitates the management of identity so that a common understanding of the state of a program can be reached. This is actually analogous to the situation with concurrency, which involves different processors interacting with one another.
  • Concurrency: the interaction of different processors with one another
  • User interface design: the interaction of humans and computers
The issues in concurrency are somewhat similar: we need to reach agreement about the changes in shared state over time. Clojure's state management mechanisms like software transactional memory will make this easier for you. Concurrency is much easier if you explicity manage identity and state, just like user interface design. The only time when the naive model of state is sufficient is when creating single core programs that don't interact with the user at all.

External links:
Values and Change: Clojure’s approach to Identity and State

No comments:

Post a Comment