Demand-driven architecture: Relay, Falcor, Om.Next
I was revisiting the state of application development at the bleeding edge, a topic which I’m very interested (ok, I’m obsessed with).
Through the development of many applications over the years, I began to feel acutely that I was repeating myself, not just a little but a lot; that most of my time was spent on wiring and internals of an application and not solving the problem at hand, the one everyone outside the codebase talked about.
Bugs, wiring, state, coordination: these are all lower level concerns than what things I was trying to create, that we’re all trying to create: delightful products backed by an intelligent and correct information system, one that scales up as more smiling users pile on, as we sit back and get rich, and ship features…living the dream.
Moreover, the frustrations I felt spanned languages and frameworks: repeating validations, triggering re-renders, duplicating logic on both sides of the stack. Not only are these implementation details not fun to work on, small mistakes become the source of bugs, leading to poor user and developer experiences.
Each of us is an engineer, product designer and artist in our own way; as such, we’re driven by a desire for maximum leverage over the expression of our creative facilities. When the details move as fast as the vision does, it feels delightful to develop, and in turn produces systems that are equally delightful to use. Anything short of flow, for the developer or user, feels frustrating.
The solution, it seems, isn’t just a new framework or language, its a new architecture, a new way of approaching and declaring rich client applications. Demand-driven architecture is a term I first heard last year in a talk from David Nolan and Kovas Boguta. It’s used in production by Facebook and Netflix, who have open sourced their tools (Relay, GraphQL, Falcor). David Nolan has been working on and Om.Next, which steals the best ideas and adds even more.
The architecture is designed to improve the performance as products and the teams that build them scale. See: Laney Kunzel, Facebook UI Engineer, explaining her team’s rationale behind Relay. Its patterns give developers greater leverage over the expression of a system of user-facing applications.
Compared to existing frameworks and patterns, these ideas are very new. But their newness doesn’t diminish the fascinating concepts and the exciting potential they have for application development, specifically on feature velocity and user experience. For that reason alone, they’re worth understanding.
React is often the topic of conversation vis a vis other front-end frameworks, but it’s really just a view rendering library — one that says: given data x, you’ll efficiently render ui y. Flux and Redux provide two patterns for managing the data backing React components, but they don’t address reconciliation with the server-side.
React’s greatest win is that it lets you move on to more interesting problems than the plumbing of rendering data as DOM: demand-driven architecture is where, I think, we go next.
Happy developers = happy users.
These are implemented in various ways by React+Relay+GraphQL, React+Falcor, Om.next. See videos linked above and below for visuals.
- An approach to declaring and reconciling data between an application client and server
- Driven from the client, starting from the smallest UI element up the UI tree
- Clients demand their data needs by describing them in data. This description is called its query
- Render down, query up: Parent components render their children, passing data down, but build their own demand up from child’s component’s demand
- Entire demand available at the root UI element, if the above pattern is followed
- Client sends this aggregated demand data structure (via HTTP to server)
- Server knows how to parse this demand structure recursively, fetching all data that is needed
- Data store agnostic — the query demand is in the language of the app, not the DB, so any can be used and interchanged
- Query language is app-specific and supports recursiveness, which allows for arbitrary UI development with no server-side changes
- Client receives full demand, and simply passes it into the root, which hydrates the rest of the UI. Here, the parallelism between the nested demand structure and the fulfilled demand comes to fruition. Check out the GraphQL request/response syntax; this is a key concept.
- Co-located queries, change one file and data is fetched from server with no server change.
- Declarative: express render and query functions; thats it. No plumbing or imperative details. Say what, now how.
- Demand language also deals with mutations, specified, like queries, as data.
- Precise queries down to attribute level; data is never over or under-fetched
- Single HTTP request / response needed to hydrate whole UI; minimal http overhead/latency/joins
- Client cache and reconciliation allows it to fetch only what it needs when the UI demand changes as the user moves through the product.
Sep 30th, 2015 Laney Kunzel, Facebook UI Engineer, on Relay at JSConf
May 27, 2015 Laney Kunzel, Mutations in Relay