RxSwiftCommunity / Action

Abstracts actions to be performed in RxSwift.
MIT License
876 stars 150 forks source link

Cleanup public API #120

Open mosamer opened 6 years ago

mosamer commented 6 years ago

Currently Action might be exposing more properties than needed. Optimally, it should look something like

                                    Action<Input, Element>
                      +----------------------------------------------+
                      |         enabledIf: Observable<Bool>,         |
       inputs ------->| workFactory: (Input) -> Observable<Elemenet> |------> elements 
(AnyObserver<Input>)  |                                              | (Observable<Element>)
                      +------------------------------+---------------+
                                                     |
                                                     |
                                                     |
                                                     +------> errors: Observable<Error>
                                                     |
                                                     +------> isExecuting: Observable<Bool>
                                                     |
                                                     +------> isEnabled: Observable<Bool>

Thus, following changes to be applied;

Some questions open for discussion;

ashfurrow commented 6 years ago

Cool, this sounds like a good thing to discuss. I won't have to time consider until the weekend, but others should feel free to chime in 👍

bobgodwinx commented 6 years ago

@ashfurrow we you agree we can mark this as approved ?

ashfurrow commented 6 years ago

I like all of these suggestions, especially the deprecation of the existing APIs instead of a replacement. Let's move forward with this, keeping in mind that we still welcome feedback from @RxSwiftCommunity/contributors on these changes 😃

freak4pc commented 6 years ago

+1 for mind-blowing ASCII chart :shipit:

freak4pc commented 6 years ago

BTW the InputSubject strategy was so you have non-terminating inputs. How do you solve this without it ?

bobgodwinx commented 6 years ago

@freak4pc valid point there. Maybe for now we leave that aspect and handle it later on. Because of the Non-terminating inputs I've thought of using ReplaySubject or BehaviorSubject but it doesn't make sense and even though you go with the share I am still not convinced because under the hood share are subjects. So for now I would suggest we keep the InputSubject

beeth0ven commented 6 years ago

Hi, there~ Is it the situation what PublishRelay design for:

PublishRelay is a wrapper for PublishSubject.

Unlike PublishSubject it can't terminate with error or completed.

Correct me if I'm wrong 👽

PR: Publisher - wrapper for PublishSubject that cannot error

beeth0ven commented 6 years ago

Sorry, I'm wrong 😔. This PR answer my question:

Binding of any observable that is finite or errors out is wrong IMHO, but right now we don't have compile time guarantees regarding those properties on Observable.

mosamer commented 6 years ago

@bobgodwinx @ashfurrow Deprecating renamed properties makes sense, but let’s keep in mind this cleanup is going to introduce breaking changes anyway. It’s also planned as part of a -sort of LTS- release so may be better to drop them now to avoid any future code churns. My suggestion here will be a Declaration Attribute that;

As for inputs changes, the rational behind moving from SubjectType to ObserverType is an assumption that users should not need (or even be able) to do something like; myAction.inputs.subscribe(onNext: { /* do something with the input */ })

so this dropping of Observability also should eliminates PublishRelay as an option @beeth0ven

@freak4pc as for non-terminating strategy, IMO the simplest solution is an AnyObserver that simply ignore non-next events :) a Binder might be an alternative, but I think it might overcomplicate it unnecessarily.

Thanks all for your valuable feedback, I'd also appreciate your input on executionObservables and errors as well. If all is good I might be able to create a PR soon.

freak4pc commented 6 years ago

Thanks for the feedback @mosamer , Some great points here.

may be better to drop them now to avoid any future code churns

I agree with that. It's gonna be a major release probably as far as this codebase goes so I don't think we're risking making some deprecations as long as it doesn't require massive code-changes.

an assumption that users should not need (or even be able) to do something like

Agreed as well. We wouldn't want people to subscribe to the inputs, but we could just as well make InputSubject fatalError on a non-authorized subscription possibly (since it's our own implementation and not tied to RxSwift core).

I'm not sure if a AnyObserver would help solve the non-terminating issue, but it's also a good possibility.

bobgodwinx commented 6 years ago

ok guys let's agree on one thing here. We don't know how people are using Action in their daily work and removing InputSubject might cause some anger. So my advice is to keep it for now and it's working perfectly. I will mark it as approved and just like @ashfurrow said we can always review it

freak4pc commented 6 years ago

I know @fpillet is very busy but he's one of the more prominent users of Action (and wrote the chapter on it in the book IIRC), so if he'll have a minute to review this changes I would feel much better with just moving forward with this knowing a "hardcore" user of it feels comfortable making these changes for his use cases.

mosamer commented 6 years ago

I went throw Action's chapter on RxSwift cookbook and did not find anything contradicting these assumption. However, I'd prefer waiting for @fpillet input on the discussion whenever he finds time for it, no rushing.

ashfurrow commented 6 years ago

Good thinking @mosamer – I did the tech review for the book and I agree nothing about these changes would affect it. But that chapter is an introduction to Action, and I think the changes we're proposing are really things power-users are going to be using, and I want any disruption to their work to be minimized.

I would suggest we do the following:

Are there any goals I'm missing? We could also move this to a Google Hangout or Skype call to discuss further.

fpillet commented 6 years ago

Hey guys, sorry to chime in so late. Been held back by insane workloads.

Okay so I looked at my usages on Action. As was mentioned, I'm a pretty heavy user, in all kinds of scenarios:

Now a couple things to consider. Action doesn't look very complicated but any change in its structure will impact its behavior. I remember fixing some particularly tricky issues in execute which was not always producing the expected result. The internal machinery is tricky to get right too, so my advice would be to be veeeeery careful when changing anything :)

dangthaison91 commented 6 years ago

@mosamer Hi, I'm using Action with MVVM pretty much as @fpillet. One of the most important change will break my Pagination API is that inputs is AnyObsever so it cannot be observed it anymore. You can find usage in this PR #37 by @ishkawa.

freak4pc commented 6 years ago

Uhm this makes it a bit hairier to get rid of an Observable-style inputs.

The "conceptual" problem I have here is that an input isn't something you're supposed to be able to read at all (except for inside the class responsible for handling the inputs, in the case Action itself).

I don't have enough time to dive into the PR you mentioned but I'm sure there's a better way to deal with it possibly.

Any ways now that there seems to be a plausible use-case for having inputs as AnyObserver, I think we will have to keep it or very slowly deprecate it (with a proper replacement if there is one). Even though as I said earlier, I don't conceptually think subscribing to inputs make sense, seems like there are people counting on that side-effect.

dangthaison91 commented 6 years ago

In some case, my Action failed and I want to get error paired with input value for display or revert local database/cache.

        invitationSettingAction
            .errors
            .withLatestFrom(invitationSettingAction.inputs) { $1 }.not()
            .subscribeNext { [unowned self] in self.updateInvitationSettingInRealm(status: $0) }
            .disposed(by: disposeBag)

Actually, we can have another Observable (inputObservable) then bind it to inputs so we can subscribe that Observable too. But It will have a problem if my inputsObservable is not paused emitting while executing.

Another approach is exposing an inputsObservable in PR #127 but I think it will conflict with this issues' subject is Cleanup API.

mosamer commented 6 years ago

@dangthaison91 Thanks for the insight, I will try to have a deeper look on the mentioned PR and the github repo for RxPagination before proceeding. I'm bit busy right now but hopefully will get back to you soon :)

mosamer commented 6 years ago

Hi @dangthaison91, after going through the mentioned PR #37 I can say migrating inputs to AnyObserver will still preserve the intended behaviour of triggering action by an arbitrary observable. As an ObserverType, you should still be able to bind to it.

Of course this migration will come with the following features broken;

IMHO, I believe these features were byproducts and may lead to anti-patterns and we should continue with this approach of replacing subject with observer.