Adam Solove
Blog/UI engineering
21 Apr 2017

What are the important problems in UI engineering?

Let’s escape the day-to-day to survey what’s coming next

By Adam Solove · Published 21 Apr 2017 · Reading time 11 min

Very early in my programming career, I read a transcript of the talk “You and Your Research”, by Richard Hamming, a mathematician whose name appears in the title of at least six Wikipedia pages for important things he invented.

I was struck by a question which he persistently asked of his colleagues:

What are the important problems of your field?

and the observation he made of the successful scientists around him:

Great scientists have thought through, in a careful way, a number of important problems in their field, and they keep an eye on wondering how to attack them.

and also by his scheme to devote at least a little time each week to that question and long-term thinking:

I finally adopted what I called “Great Thoughts Time.’’ When I went to lunch Friday noon, I would only discuss great thoughts after that. By great thoughts I mean ones like: “What will be the role of computers in all of AT&T?’’, “How will computers change science?’’

This evening I spent my regularly-allotted time thinking about the important long-term problems in UI engineering and catching up with the research on attacking them.

I thought it might be worthwhile to share my own thinking and ask for your suggestions of important problems or ways of attacking them. Please comment if you think I’ve left something out or if you know of relevant attack vectors that I don’t mention.

The three problems I think the most about are: structured concurrency, understandable behavior, and data synchronization. Let’s look at each of them:

Structured concurrency

Especially on the web, but also in native mobile development, it is still very easy to get concurrent behavior wrong. It is rare to see the code of a user interface that doesn’t have data races or use-after-dead problems related to components that fire off asynchronous chains that eventually trigger mutations. Promises are a great API for asynchronous behaviors, but not a great structure for composing behaviors together or ensuring they play nicely with other state changes in the UI.

On the web, the problem is even more severe because most JavaScript runs on the main thread and there is no convenient way to yield control back to the event loop while retaining your place in a long-running computation. For this reason, React had to rewrite their core algorithm to remove its recursive call structure and replace it with a data structure so that it can pause to let the event loop run and to re-evaluate whether it is working on the most important thing.

There are some available, partial attacks on these problems:

And also more general, but not yet mainstream, approaches:

I’m quite excited about Concurrent ML and the idea of making it work in the browser, even if slowly, in WebAssembly. So, though it’s well out of my comfort zone, I’ve been trying to attack that problem for an hour or two a day for the past few weeks. So far, I understand interpreter implementations and continuations a lot better. But my C is rusty enough I still have trouble getting things to a state that emcc will build. But it’s a fun little problem and one I expect that someone, though probably not me, will make progress on over the next few years.

I’m also thinking about how structured concurrency can be taught to web developers like me. Could we use a “Synchronized Schemer” book to teach how to work with channels and CML events? What’s the best way to make this salient to developers who just want to get something built and don’t currently know their code has data races?

Understandable behavior

When building interactive systems, it is enormously difficult to understand their behavior because of the enormous state-space. You have to consider all the system’s data and operations multiplied by all the possible sequences of the user’s interactions. Unlike concurrent systems that don’t involve humans, which can often be defined narrowly in terms of fixed protocols, once a human being is involved and allowed to make decisions, the possible paths through the system become uncountable.

This raises a number of problems:

This problem is under attack from a number of angles:

In reflecting on this problem, I haven’t been able to find an angle of attack where I think I can help out. My current thinking is stalled on two ideas:

(Update on 8/10/17: after thinking about this problem more, I wrote the essay Pure UI Control, which describes the idea of “control state” and an explicit visual representation of UI behavior. This is an attempt to make it easier for programmers and non-programmers to share an artefact that allows them to reason about all the possible valid behaviors of a UI. I think that the conceptual separation of “data state” and “control state” can help us focus on the characteristics specific to control, which is what really creates the unique complexity in building interfaces.)

My current work on this problem boils down to using various methods to try to make sense of the complex behaviors in the interfaces I work on. I’ve tried some formalisms, different sketching techniques, etc., all things above the level of actual code but that aspire to fully encapsulate the code’s behavior. I try to read up on formalisms about effects, like Idris’ effects and concurrent typing. I’ve had some success with specific diagram techniques, but not anything I could make systematic. So I think about this a lot, but haven’t made any progress.

Data synchronization

The network eventually absorbs every application that used to live only on a single computer. From making small web apps work while offline to correctly merging multiple users’ edits on large documents, we are going to need a wide array of options for synchronizing data. Perhaps more importantly, we need a social solution for packaging these options and helping developers use them in practice. The domain of distributed systems, currently only inhabited by experts, will be an expected feature in run-of-the-mill apps and websites.

If the community gets this wrong and doesn’t package up good options and help steer people towards the right tool for their use-case, we’re going to end up with some truly terrible problems. Our current problem with slow-loading sites will look like nothing compared with sites that have data cacheing problems or that silently merge away your changes when they sync with the server.

I know of a couple fronts in the battle against this problem:

An example of a real system built with these ideas is Eve, a new model for programming that is built on top of a fast distributed data store and uses a Datalog-like pattern matching language for expressing rules. I spent some time writing toy Eve programs a few months ago and really enjoyed it. The current programming IDE and docs have some rough edges, and the things it can currently do aren’t that hard to with JS. But because Eve is built on top of a solid model for distributed data, once the distribution and permissions parts are available, it’s going to be a very interesting way to write distributed apps.

This is a hard but important problem, probably the most important one for the field. But I don’t know enough to help with it yet. So I’m keeping my eye on CRDT stuff in Erlang and JavaScript, and waiting for distributed Eve to become available, but not actively working on the problem.

Those are the three important problems for UI engineering that I think about the most.

Did I miss some vectors of attack for those problems? What other important problems do you think about? Leave a comment or write me a long email!

Responses


Originally published on Medium.