New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adopt a Flux-like approach to let information flow through an application #364
Comments
I'm missing one element: Mutations. See here: https://vuex.vuejs.org/en/mutations.html Specifically the relationship to Actions and the store is very important and should not be skimmed over. |
Thanks, updated the description. |
Some more observations about "mutations" ... Setting properties on the current By letting go of this settable-properties-approach, and thinking in mutations, changes to a model/store can be made atomic by always applying the change in JS first, and then syncing with Py. Technically, there is a brief moment when the states in Py and JS are not the same, but this state is Python being behind JS, not conflicting with it. edit: also important: a mutation can set multiple values in one "commit", e.g. append a todo item and increase the counter. |
Something that also came to mind: for some application state you should be able to specify if it is server or client state only, to disable syncing. For example, a Sign In action that retrieves an authorization token for an external API should be able to commit that token to the store for later use in queries; but that token belongs to the user, and should never be synced to the server. That would be a serious security risk. I'm wondering if that should be specified per property or per store though. In reply to your further thoughts about mutations:
Is that feasible though? Can't the server react to state changes and commit mutations as well? |
That crossed my mind as well. Another use-case is when the client modifies a state very fast (e.g. during mouse interaction). One idea for this case could be to temporarily shut down syncing of the store, and when turning it back on, the store has remembered (a squashed version) of all changes and syncs that with Py. For other cases (like the one you mentioned) I'd say we have stores that don't sync at all. Perhaps they should be JS-only; I'd not want to put sensitive data in a store that is capable of sending data to the server, and only prevented to do so by a flag :)
The problem with that is that if server and client commit a mutation to the same property, then both sides of the store will have conflicting states. Plus you need a mechanism to resolve the conflict eventually, which comes down to always roundtrip from Python to JS (or vice verse), which can cause "flickering". All this can be resolved by only committing mutations in JS, at the cost of not being able to apply a direct change from the server. I can imagine that the server can "submit" mutations that are first communicated to JS and then applied, but I think you'd call these "actions". edit: Thinking of this more, the server could apply mutations to store attributes as long as these attributes are not mutated from JS. So it could be determined per attribute/store which side does the mutations. |
I totally agree and like the idea. I'm just wondering what would be left to do for the server at this point. If it won't react to state changes, what else will it do at runtime? |
The server can still react to state changes, it's just that the state can't be mutated directly; any change submitted by the server will first be applied in JS and then synced back to Py. How this will work exactly I don't know yet, perhaps by dispatching a new action for which there is a handler at the JS side. I am working on a sorts of prototype, based on the existing |
I found this an interesting article: http://www.christianalfoni.com/articles/2015_08_02_Why-we-are-doing-MVC-and-FLUX-wrong It explains how classic MVC used to be a good model when the model represented the state of the server. When we moved everything to the front-end, some separations were removed, leading to a tighter coupling between model and view, making it harder to scale. The purpose of tools like Flux is to introduce a decoupling, by queuing actions and handling them after the views are done. It is somewhat critical on Flux though, not sure yet what to think of that. edit: it does make clear to me, that there are different kinds of MVC, MVC is not what it used to be, and Flux/Veux et. al. can easily be considered just another flavor of MVC. |
There is some strong commentary in that article. You can tell that Vuex incorporated some of that feedback in its design, when comparing it to Flux. I'm starting to feel that this issue's main change to flexx would be to separate view components from models. |
I can't say I follow this too closely, I've not gotten too much into the guts of Flexx or other frameworks to understand the pros/cons. That said there appear to be two components that should help drive your decision. Looking at your description and looking through the conversation history it seems like the proposed model has clear advantages and minor disadvantages. If your goal is to create the best framework possible, given the alpha state of the software, it seems like the "right" decision would be to adopt and implement the improved model. If you don't do it now then you'll likely never get the chance. Those users consuming your alpha software are capable enough to deal with a major architectural change and if the stated advantages are as you've described, they will be grateful for the changes in the long run. |
Additionally here is the bottom of the page from the intro to Veux that I found salient:
I think if Flexx could incorporate a Flux model without forcing the use of a Flux model that might be the optimal solution. If Flexx forced a Flux model without added complexity for simple applications that might also be optimal. |
@JohnLunzer I agree; good to hear at least one user would not mind a change like this :) I've been thinking a lot about how Flexx could like like when ideas like this are included. It's hard though. We also have the Python-JS connection/separation to take into account. I agree with @Korijn that making |
In react/vue widgets have their own observable state. It's when your application grows that the store becomes useful and you can add it to the mix. That makes it less confusing. |
A quick message to let ppl subscribed to this issue know that I am still working on this (every day). I'm working on a proposal of changes and documentation for the newly proposed |
A proposal is waiting for reactions at #367 |
I like the example shopping cart. What would the widgets look like to display the products and the cart? I'm also wondering why the store is |
Depends on how you'd render them, but they'd react to the store's
It does not have to be. It's up to the user to design the hierarchy of models in an appropriate way. I updated the shopping cart example to have a widget as the root model, which has a |
Can you show what that would look like? It's really important to me that that becomes simple. :) |
added |
@almarklein offtopic, but: |
Not yet. We could think of a gitter channel ... |
@almarklein yes please! it's very easy to setup and maintain |
This is a proposal for some pretty profound changes to how building apps with Flexx works. Though Flexx is still marked alpha, there are people using Flexx already, and they'd need to make some serious changes if we go this route. We thus have to think carefully whether the proposed changes are worth it.
Background
We've found Flexx to be working pretty well, even for larger applications, though the complexity of an app increases too, and we've found that newcomers to our app have trouble understanding the data-flows etc. I feel that #359 is a symptom of this, and that there is a deeper cause.
Flexx uses events. A lot. Everything is tied together using events. This is the case for both user input (mouse and key events) and property changes. The system works very nice (if I may say so myself), but a problem is that information flows all over the place, which makes it difficult to reason about the state of the application.
Flux and friends
At Facebook they had similar problems with their classic MCV approach; it scales badly because its hard to predict the state of an application based on stuff that happens in the app. Their core insight was that if information flows in one direction, an app becomes much more predictable. Here is a video that explains it very clearly (thanks @Korijn) and a comic.
At Facebook they came up with a pattern (and framework) that they call Flux. The same pattern has been used in different places, in different variants, e.g. Redux and Veux. The core principal is that information flows like this:
The store(s) represent the state of the application. The views listen to changes in the state and update the UI accordingly. Views (and other parts of an app) can create actions (kind of events) that are handled by the store and eventually give rise to changes in the state.
An important concept is that any actions that are dispatched (e.g. from views) are only handled after the view is done processing stuff. That's why we can legitimate saying that data flows in one direction, even though we see an arrow going to the left. Also important is that updates to the store are atomic, "commiting mutations" in Veux-terminology. The store handles actions, and then either applies mutations, or it may e.g. call out to an API, schedule some work, and eventually (asynchronously) apply mutations. Or both. This page explains it in more detail.
The state in the store is a higher-level representation of the application state; instead of having a label for which its text property represents the username, the app would have a "username" entry in the store, and a view would be responsible for showing it.
Adopting this pattern in Flexx
My initial feeling is that with this model, Flexx can look like this:
Where a store is a bit like our current
app.Model
, having properties that are synchronised between Python and JS. Properties are not set directly, but via actions that can come either from JS or Python. The views/widgets live completely in JS (they have no representation in Python).Advantages
be awesome during developing and debugging.
Disadvantages
I'll make another post to give an idea of how the code would look like. This is something that I need to work on some more, and which I want to compare against current examples and apps.
The text was updated successfully, but these errors were encountered: