Skip to content
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

Optimistic updates #7

Open
acdlite opened this issue Jul 3, 2015 · 33 comments
Open

Optimistic updates #7

acdlite opened this issue Jul 3, 2015 · 33 comments

Comments

@acdlite
Copy link
Contributor

acdlite commented Jul 3, 2015

Opening this issue to track discuss whether FSA should address optimistic updates. If it does, I think it should be as an extension of the core spec.

@tappleby
Copy link

tappleby commented Jul 5, 2015

I dont think the spec should specifically address optimistic updates but being able to express a sequence of actions would allow for someone to implement optimistic updates.

Actions:

[
  { type: 'SAVE_FOO', payload: { fooId: 42, name: 'Foo' }, meta: { id: 'abc1', sequence: 'begin' } },
  { type: 'SAVE_FOO', payload: { fooId: 42, name: 'Foo' }, meta: { id: 'abc1', sequence: 'complete' } },
]

Store or Reducer:

if (action.type == 'SAVE_FOO') {
  switch (action.meta.sequence) {
    case 'begin':
      // Store pending value using action.payload.fooId
      // Possibly keep track of request using action.meta.id
      break;
    case 'complete':
      if (isError(action)) {
        // Remove pending value, store error letting user know what occurred.
      } else {
        // Remove and merge pending value.
      }
      break;
  }
}

A user may want a sequence of more then 2 actions, if we borrow slightly from Observable terminology I could see the following values for sequence: begin|next|complete. An optional sequenceOrder could be useful as well.

Not sure if this causes any issues but for an action creator that performs some client side validation it might be possible for a complete sequence to be fired without having a matching begin.

@acdlite
Copy link
Contributor Author

acdlite commented Jul 16, 2015

I like the sequence idea. Here's how I'd implement it:

{
  type,
  payload,
  meta,
  sequence: {
    type: 'start', // or 'next', or 'return'
    id: 123 // same for every action in the sequence
  }
}

I'm going to try this out in redux-promise and redux-actions to see how well it works.

@clearjs
Copy link

clearjs commented Jul 16, 2015

@acdlite It might be useful to have some sequentially increasing number for sequence ordering information. E.g., if progress of 67% arrives after 70%, it would be possible to ignore it.

EDIT: that would be more relevant for Rx, or wherever we need sequence.type === 'next', not for optimistic updates.

@tappleby
Copy link

@acdlite I like the top level sequence as an object, not a huge fan of return, would prefer end or complete.

@clearjs the sequence order would be useful, I could see it living in meta or sequence. Do you think this is something the spec needs to define?

@clearjs
Copy link

clearjs commented Jul 17, 2015

@tappleby It depends. Perhaps, after more use cases are addressed this will be clear.

Generally speaking, the concept of sequence implies ordering. My point was to bring this into discussion, not to suggest any specifics.

If I had to make a decision, I'd introduce ordering information and make it a field of sequence.

@cesarandreu
Copy link

This sounds like a great idea.

With respect to ordering information, I think picking something and sticking with it would keep people from falling into the bikeshedding trap, so I think it'd be good to include in the sequence field.

Now for a little bikeshedding, why not use done to signal that it finished? Then it would match Iterators. Taking it one step further, why not try to match iterators more closely?

{
  type: 'FOO',
  payload: { foo: true }
  sequence: {
    id: 123,
    done: false,
    value: 'start'
  }
}

@valscion
Copy link

I like the idea of matching the spec with Iterators 👍 This would also allow you to specify the sequence.value in any way you choose to. In some cases, the value could be an object with a progress key if the user so chooses, or it could just be a plain scalar value if custom objects seem overkill.

It might be too much to try to fit the form of sequence.value to cover all the possible use cases. That could be left for the application domain to handle so that FSA would only be concerned about the sequence.id and sequence.done values. What do you think?

EDIT: P.S. This issue being open is currently the only thing stopping us from using FSA in our application. Some way of resolving this would help us tremendously so that we wouldn't have to invent our own ways of doing optimistic updates.

@tappleby
Copy link

tappleby commented Aug 8, 2015

Matching the Iterators spec is an interesting idea. Part of me does like the idea of being able to identify the start of a sequence without having to track previous sequence ids; this isnt possible using just done alone. Perhaps this isnt a common use case?

@tappleby
Copy link

@acdlite how do you feel about the following:

{
  type,
  payload,
  meta,
  sequence: {
    type: 'start', // or 'next', or 'done'
    id: 123, // same for every action in the sequence
    value: { progress: 0 } // Optional value 
  }
}

I feel using done instead of return better describes whats happening and is less likely to be confused with the return keyword.

I am still not sure if value is necessary, optional data like this could be stored in meta.

@valscion
Copy link

I am still not sure if value is necessary, optional data like this could be stored in meta.

That would actually be reasonable. If at some point FSA wants to change to add a more thought-out sequence.value, it would not conflict with ones before.

@johanneslumpe
Copy link

I agree with @tappleby that return feels weird in this context. done seems more appropriate here. 👍

@chibicode
Copy link

I like @tappleby's comment: #7 (comment)

Also, for someone like me who didn't know about the iterator protocol, here's the link:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol

@gabrielgiussi
Copy link

Could someone explain a little more how will be used the iterator approach? What would be the benefits?
The actions would need to have an [Symbol.iterator], don't they?

@hiddentao
Copy link

+1 for @tappleby's suggestion.

@dlmanning
Copy link

Hey, random bystander here. Is there consensus about this yet? I'd like to incorporate it into an app we're about to start and basing off FSA's :)

Anything that needs doing, experimenting with, or whatever? Happy to help.

@esamattis
Copy link

BTW redux-optimist is an interesting approach https://github.com/ForbesLindesay/redux-optimist/

@timdorr
Copy link

timdorr commented Sep 17, 2015

@epeli That's actually very close to what Andrew is doing in redux-promise's sequence branch

@eldh
Copy link

eldh commented Sep 20, 2015

fwiw I made a small todo app using the sequence branch while trying to learn redux and I find it to be pretty nice. https://github.com/eldh/todo

@gsklee
Copy link

gsklee commented Sep 24, 2015

Have no time to look closely yet but this might be of interest:
https://github.com/pburtchaell/redux-promise-middleware

@gpbl
Copy link

gpbl commented Sep 29, 2015

I could test the redux-promise "sequence" branch and it worked very well for optimistic updates. I'd love to see this idea implemented into FSA.

@rgrwkmn
Copy link

rgrwkmn commented Sep 29, 2015

I think the proposed sequence solution makes actions less readable. Actions that are part of the same sequence (and not part of start or done sequence type) seem more like a stream of progress information, with the most import information hidden away in the sequence key and the payload being unimportant.

@valscion
Copy link

I think the proposed sequence solution

There has been many proposed solutions in this issue @rgrwkmn. Which one do you mean?

@rgrwkmn
Copy link

rgrwkmn commented Sep 30, 2015

I'm referring to @tappleby's comment.

As I worked through my own use case example and did some more reading, I've concluded that my criticisms are moot, but since I haven't seen them specifically addressed I'll list them here. Hope this helps:

Actions having sub-actions hidden in the sequence type is less readable. It seems that none of the proposals preclude using different action types, though, so this is a moot point.

The discussion may be missing a distinction between optimistic updates (a standard that could be defined) and other multi-action processes (which could be anything). Semantically, sequence suggests it can cover any multistep process. A use case relevant to my industry would be deploying a virtual machine. I've described a potential list of rough actions in this gist. This point is also moot because I can see how using sequence with type and id can cover this use case, while I can still use different action types and have the relevant data in the action's payload.

@valscion
Copy link

valscion commented Oct 1, 2015

Yeah so @rgrwkmn for your use case, the only thing that the sequence value MUST contain is type and id. The rest can be inside payload or meta, right?

So the spec would look like this:

{
  type,
  payload,
  meta,
  sequence: {
    type: 'start', // or 'next', or 'done'
    id: 123, // same for every action in the sequence
  }
}

Which in turn looks very similar to @acdlite comment, only the last value of type would be done instead of return. I have no strong feelings about that, though.

So @acdlite, have you tried your initial spec further? I think we're revolving back around to it, so it seems like a good way to go forward. The spec could always later be amended to include more values, should that be necessary, but at least we could go forward with what you've said.

@rgrwkmn
Copy link

rgrwkmn commented Oct 1, 2015

@valscion 👍

@valscion
Copy link

valscion commented Oct 2, 2015

@acdlite, would you accept a PR implementing the spec I described? Or the spec you have described? What needs to be done would be adding the sequence key and it's valid keys check to the isFSA function + amend the README to note optimistic updates, too.

@lukewestby
Copy link

@acdlite should updating the spec here precede finalizing https://github.com/acdlite/redux-actions/tree/sequence ?

@tappleby
Copy link

I actually have a pending PR for the sequence branch based on discussions in this issue - redux-utilities/redux-actions#22

@lukewestby
Copy link

@tappleby awesome! IMO it looks good to go. Let me rephrase my question more clearly: since redux-actions and many other libraries are intended to be FSA compliant, should we make an effort to see the sequence standard all-the-way through into the spec before implementing it in compliant libraries, or take more of a "draft" approach and implement what we have here to see if it works well before adding it into the standard?

@DawidLoubser
Copy link

My opinion is that FSA should remain a standard for the data structure for the action only. I think that optimistic updates are best handled at the higher level.

Microcosm has a particularly elegant implementation, where action creators can return ES6 generator functions, which the middleware will continually pull from - facilitating optimistic, or multiple, dispatch from one action.

Anyway, I think that precisely because multiple ways exist to solve the optimistic update problem, it's better not to bake on view onto this into the FSA data structure 'standard'.

@iest
Copy link

iest commented Nov 18, 2015

What's happening with this? Would love to know if I should wait for this stuff to land, or if I should do a custom implementation...

@kpaxqin
Copy link

kpaxqin commented Dec 5, 2015

@DawidLoubser
+1

I think we should just keep FSA the simplest standard and move the async stuffs (include optimistic update) to the actionCreators .
And in my opinion, the only things reducer should care about are payload and type, add other attribute on action will making things complex.

Here is my example, a todo list with optimistic update : https://github.com/kpaxqin/redux_example/tree/todomvc

The redux-promise-thunk use thunk to dispatch action in each phase of async promise, and in TodoActions we can use createPromiseThunk directly or compose with another thunk

This is just a demo, but I think it can show the possibility of composing logics in action creator, instead of putting extra things in action object and handle them in reducer.

@acdlite @lukewestby

@rdsubhas
Copy link

rdsubhas commented Jan 6, 2016

👎 for sub-actions inside actions. Having a sequence object with a status inside it would lead to nested switch/case in reducers. The beauty of FSA is its easy to use it with or without redux-actions, and that ease should be maintained. I really believe sub-actions should have different action types altogether.

👎 for mixing Async/Promises with Sequence/Generator/Iterator. Those two are different problems. NodeJS made a hacky example of using generators to solve async, but that need not be taken as a standard. We should be looking at async/promise and sequencing as separate issues. Async should be handled separately like how ES7 introduced async/await.

👍 for keeping FSA simple. As with any standardization process, having this issue in FSA is delaying a trivial but most-hit-upon problem. Request to move the Async/Promise discussion to redux-promise to let things continue forward, and maybe discuss only sequences in the context of FSA.

Request to unstandardize this discussion, and move downstream. Atleast for the Async/Promise handling part.

@acdlite @lukewestby @DawidLoubser @kpaxqin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests