I’ve been using RxJS / Kefir / flyd with d3, webgl and now React, but eager to learn about other approaches.
Let’s assume a SPA that has a LOT going on, similar to the chart widget here: http://www.ig.com/uk/ig-indices/ftse-100 (click around and see buttons on the bottom, e.g. adding indicators, annotations; customising indicators etc.).
For the sake of this example, consider all the things going on. For example, panning sideways has a lot of downstream effects. It of course moves the chart left and right. But panning can be limited by overscrolling (spring effect), or subsequent release can cause an elastic bounce at the edge, or of course, kinetic autoscrolling. There’s also zooming which not only influences the time domain but the shape rendering (e.g. whether bars have strokes or not). So we can say that one specific source of actions has downstream effect on a number of things. Recognising there are a lot of effects necessitated by panning/zooming, let’s now focus on the subsequent impact on the visible temporal domain (the period that is shown at the moment). This in itself gives rise to complex behavior. For some layers, the SVG transform attribute must be updated to visibly scroll. For a (hypothetical) WebGL layer, the boundaries set in gl.drawArrays need to change. If previously unseen annotations move into the visible window, they have to be rendered. If there are indicators, they possibly even need calculation (e.g. if they aren’t precalculated for the entire history). Moreover, independently (asynchronously) of this, there are new bars coming in from the financial streaming service, which impact a lot of things, e.g. how far you can pan, or the actual, rendered glyphs. You can also imagine things like automatically switching among display forms (OHLC vs candles vs line) as a function of zooming.
I could go on and on but it’s a real life application (disclaimer, I worked on it some) with around a million mobile downloads (this web example is but a version). So let me just say that there are deeply nested dependency chains (some of which can be made synchronous and some are asynchronous — irrelevant now). So let’s just agree that this SPA can be modeled (or implemented) as a complex Directed Acyclic Graph of FRP streams/observables. Some user action or WebSocket action happens, and it has a cascading effect, rippling through long chains in the data flow dependency graph. There are hundreds of nodes and the depth of the DAG can reach 6–10 layers. In the name of DRY, no matter how you implement it, you de facto model a DAG data flow model, which of course FRP inspired libraries are designed to cover well.
How would you model that efficiently (in developer time and runtime) with something like redux? I understand how you can have a store that represents application state (to be more specific, the state represents a FUNCTION which derives a new application state from the old application state, given new actions). But how do you represent all the dependencies?
One possibility is that you only capture primary input in the redux store object, and everything is calculated on demand as pure functions. I.e. the application state is minimal — you just keep a log of ALL user actions, and run the downstream calculations in rendering time, which reduce/integrate (=FRP scan), map, filter etc. on the basis of original input. There may even be some kind of pruning action which sometimes gets rid of old actions, replacing them with some new initial state in the store.
I understand this can be done and have been testing this idea, but one ends up with trading one type of complexity with another — in this case, having to worry about periodic history truncation, memoization of function applications (for efficiency — we talk about 60fps custom animations etc.) and the resulting memory management, for essentially similar results (though easy rehydration, serializability and undo/replay are big pluses). While I see the merit of both approaches, things like redux seem to focus on implementation detail (an inert store object is beneficial for serialization etc.) while FRP seems to focus on the content, i.e. the domain-specific relations among variables, more in line with how machines, or mathematical variables work.
This got long but I’d be interested in thoughts about it. E.g. what experience people have with approaches like redux for complex use cases like the link above to the financial charting tool. The tired TodoMVC examples and similar, low complexity CRUD is uninteresting as they’re trivial; isolated solutions to aspects like animation with React also aren’t directly relevant to the question (as they seem to focus on specific tools such as spring animation). Someone who’s done it, how do you go about managing deep, complex dependency chains for real time operations, and what lessons have been learned?