Wow, looks really interesting! With Flux/Redux I have control over when and how data is updated, but that is not the case here. What are the performance characteristics? Is there a limit to the number of observables before performance suffers? There is also the question of routing and history. What is the best way to use observables in a single-page app along with routing and history (i.e working back button)?
Mobx: Simple, scalable state management
21–30 of 30 posts
Re: Mobx: Simple, scalable state management
#22Earlier quoted context omitted.
I spent a lot of time trying to wrap my head around certain features of Redux. For example, all the currying used in various places (especially for middleware) makes it hard to follow what's going on. Indeed, the author points out in the guide on middleware tongue-in-cheek, "If your head boiled from reading the above section, imagine what it was like to write it." Part of my job is to figure things out and explain it…
Well, to be fair middleware is a rather advanced feature and most users don’t ever need to write one. Action creators are also a mere convention and are not essential to Redux. You can dispatch action objects inline if you prefer. Reducers do add some ceremony, and I wrote up a little on the reasons here: https://news.ycombinator.com/item?id=11187727 Glad you found something you like though! No solution is perfect, a…
Re: Mobx: Simple, scalable state management
#23I took a look. This seems intriguing because it doesn't bring the whole RxJS with it to make observables work. Though I'm a bit baffled by the developer's statements about immutability of values in his SurviveJS interview [1]: "With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." I'd like to know how this mutable values can be tracked while imm…
"With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." That statement refers to the fact that you loose (automatic) referential integrity when you start using Immutable data. Take the following scenario: you have an app with Users and Tasks. Tasks can be assigned to users. When you express this using immutable data you have two problems. The fir…
If something is mutable in real life, such as a child's height, then each measurement (sample) is timestamped, and it'll not lose its validity for this timestamp. This is called valid time. Beyond this, the wall time of the entry may be recorded as well, called the transaction time in bitemporal terms. It is possible that the reading was erroneous or entry was fat-fingered, so a new tuple is created with the (now hopefully) correct weight with the same valid date but a new transaction date. So, again, a new, immutable, persistent entry was made.
Databases such as DB2 implement features of SQL:2011 such as temporal tables. They allow the storage of such immutable entries and provide the collapsed (temporally resolved) views. Also, PostgreSQL uses the implementation technique called MVCC which purposefully does the thing you seek to avoid: via Multiversion Concurrency Control, preserve the snapshotted relations as they were at the beginning of a transaction, to ensure Isolation of ACID in the face of concurrency.
To me it seems that it's perfectly okay and desirable for observables to stream immutable pieces of data, i.e. values, while not engaging in an overly early binding to an optimization strategy that sacrifices the temporal aspect at the earliest moment - especially in a tool that claims to be a version of Functional Reactive Programming in its one-sentence summary.
It is possible to have reducers (scan) that collapse a primary, immutable measurement stream into required temporal resolutions. For example, one such resolution may do away with both valid time and transaction time, just emitting changes, and maybe some 'last measured' or 'last updated' time. Some other reductions may yield analytics, for example, to visualize how often certain values change, or how often values are revised due to reading or entry error. Also, even the most elementary reductions such as key=child may carry with them the relevant timestamps.
Deeper analytics may apply some applicable smoothing of the data over time, e.g. a child's weight might be smoothed via LOESS or just cubic splines. Also, the velocity of weight gain may be modeled as the differentiation of the weight over time. We're walking into proper continuous time FRP: this differentiation might be performed via some proper numerical technique e.g. using a five point stencil with backward finite difference.
I used the child weight as an example, but it's quite similar if one implements game-like user interactions where timing matters a lot, or consistent views over financial data streams on a trading platform.
All in all, I don't immediately see how mutability would add utility in this context, but I'm not familiar with MobX constraints which is why I made more general comments which are not new to you but might be interesting to someone else.
Re: Mobx: Simple, scalable state management
#24Earlier quoted context omitted.
That's a good point, but in Redux you subscribe to all changes in single state tree where all data lives. That means that every update of data (which has no upper limit) will cause your UI to re-render. Sure, you can implement shouldComponentUpdate, but still it will be called on every state update, plus you do can do exactly the same with mobx. The difference is that with mobx you subscribe to changes of certain dat…
The talk addresses this. The whole point of Reactjs is that updating the whole UI isn't very expensive so you don't have to worry about doing fine grained data change tracking (which is harder to optimise due it not scaling well as data sizes increase)
A full rerendering requires that all the functions be called. Indeed, there's a natural limit to how much data is updated on the screen (well, unless we use canvas or WebGL but I digress) but the render functions themselves may be expensive and wasteful to rerun, especially if there is inferrable knowledge that the nature of the change doesn't warrant a recalc in some branches. Even if it doesn't cause jitter, it may be wasteful on mobile battery.
Why do I think render functions may be expensive? Official React documentation steers people toward having stores that keep 'primary truths' rather than things that can be derived from them via pure functions; and it suggests that these calculations be part of the render functions. It works, it's functional and it's clean. But you potentially run a lot of calculations, depending on the domain. With plain FP, much of this will be wasted as causing no visible change. Not only this, but the needlessly executed render functions do generate virtual DOM snippets; and these snippets do get scheduled for DOM diffing. All these add up to what is, in my experience, a jank-inducing difference. I even introduced memoization, but just DOM diffing alone is significant on a sizeable app (which makes sense as there may be an order or two magnitude difference between VDOM elements that exist vs. ones that really may change).
With observables, e.g. reexecuting a calc or regenerating a DOM snippet, control is finer grained, without the manual and possibly erroneous performance optimization hinting approach known as shouldComponentUpdate. I had cases when blind function reapplication (memoized or not) caused jank on the desktop while observables were smooth even on the mobile.
Re: Mobx: Simple, scalable state management
#25Edit: I have been enjoying similar reactiveness using ractivejs but it hasn't managed to split the reactive data from the view logic.
Re: Mobx: Simple, scalable state management
#26seems like a very convoluted and inefficient way to have getter and setters without saying those words
Re: Mobx: Simple, scalable state management
#27I took a look. This seems intriguing because it doesn't bring the whole RxJS with it to make observables work. Though I'm a bit baffled by the developer's statements about immutability of values in his SurviveJS interview [1]: "With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." I'd like to know how this mutable values can be tracked while imm…
The concept of tracking data is actually quite simple — when you define some object property as observable it is replaced with a getter & setter that invoke a callback when you get/set that property. Then you can bind a function that will be called when data is changed (via setter). You can also wrap some code into special autorun function, that will track what observable data was accessed, and when that data changes…
Re: Mobx: Simple, scalable state management
#28I took a look. This seems intriguing because it doesn't bring the whole RxJS with it to make observables work. Though I'm a bit baffled by the developer's statements about immutability of values in his SurviveJS interview [1]: "With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." I'd like to know how this mutable values can be tracked while imm…
"With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." That statement refers to the fact that you loose (automatic) referential integrity when you start using Immutable data. Take the following scenario: you have an app with Users and Tasks. Tasks can be assigned to users. When you express this using immutable data you have two problems. The fir…
I have an project coming up that's going to integrate several previously separate apps into one. I can't imagine how I would combine their state into one with Redux. With observables I could just get the app observe their state changes and affect changes in others without contained apps being aware of each other.
Re: Mobx: Simple, scalable state management
#29Earlier quoted context omitted.
"With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." That statement refers to the fact that you loose (automatic) referential integrity when you start using Immutable data. Take the following scenario: you have an app with Users and Tasks. Tasks can be assigned to users. When you express this using immutable data you have two problems. The fir…
This definitely clarifies things. Thank you for your trouble. With Mobx I'm not handling a regular object, but a wrapped object (I think). This wrapper provised the observation capability for getters and updates to observers when using setters. So, the usage patterns look to be the same than with regular, unwrapped object, but the Mobx makes sure that when accessed it always gives the latest value and when updated, t…
This approach enables our partners to write plugins that are not only simple to write, because they can just work with 'plain' javascript classes and arrays (and don't need to learn the whole, for example, redux architecture), but which are also really easy to integrate in our visual tools. Our UI stays always efficiently in sync with whatever mutations plugins make. In an architecture with explicit subscriptions, events or selectors this would be a lot harder to achieve.
Re: Mobx: Simple, scalable state management
#30Wow, looks really interesting! With Flux/Redux I have control over when and how data is updated, but that is not the case here. What are the performance characteristics? Is there a limit to the number of observables before performance suffers? There is also the question of routing and history. What is the best way to use observables in a single-page app along with routing and history (i.e working back button)?
Performance characteristics are that this increases expsense with the size of your data where as just re-rendering increases expense with the size of your UI. It's actually much more common to have lots of data but only render a small amount of it, so re-rendering is generally cheaper. The size and complexity of UIs have a natural limit because of screen size and usability, but the amount of data you use to generate…
Just scan through my blog https://www.mendix.com/tech-blog/making-react-reactive-pursu... to see how naively fully re-rendering your application upon each change makes your application an order of magnitude(!) slower.
Data size isn't usually an issue for MobX. The reason for that is that it will automatically suspend all derivations which are not actively in use somewhere (in other words, not visible currently in the screen). We have full blown visual editors that have hunderd thousands observables in memory. Nonetheless they are fast enough to perform drag and drop actions using observables, where not only the dragged item is being moved, but also all the connectors connected to it, as they observe the item being dragged.