Open ghost opened 8 years ago
This is an edge case, of course if you do not wanna depend on any framework you have to write your own version of RxJava. The reason why I used RxJava is explained in this other article: http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/
Basically I'm using a reactive approach and unfortunately there is not any other way, since on Android we are still tight to Java 7. On the other hand, Java itself is also a framework 😄 .
Just curious, how would you address this then?
@android10 How Java 8 would help here?
Java 8 has its own stream api, though I don't think it becomes available on Android anytime soon
What about https://github.com/google/agera?
@farmazon3000 this is out of scope of this discussion actually. You might be able to use either one or the other or even both.
Couple of days ago, I aso came up with this concern. It is good to see somebody else is also having this question, it seems I am not alone. @andrewjohnson90
RXJave is a tool here to do asynchronous processing in the back ground and feed UI with the results. From Uncle Bob's point of view, a good architecture should be able to change whatever tools it uses, so long as the tools obey certain contract. So, in principle, we should be able to replace it with some other implementations. But in the current state, the UseCase class depends not on abstraction but on RXjava.
Although I currently have no idea how this could be improved, the issue feels complicated to solve...
I'm trying to implement this pattern in my apps. I also have this concern. It seems either we stick with RxJava at UseCase level or use RxJava to wrap the UseCase execution.
Before trying this pattern i have something like this in the Presenter, which wrap the use case in RxJava:
private fun getUserListObservable(): Observable<List<User>>? {
return Observable.create<List<User>> {
subscriber ->
val userDataSource = UserDataNetworkSource(connectionManager)
val userRepository = UserRepositoryImpl(userDataSource)
val interactor = GetUserListInteractor(userRepository)
val result = interactor.execute(/*some args*/)
subscriber.onNext(result)
}
}
Hi, in my opinion, and after taking another look into the architecture structure, I don't think the domain layer is really coupled to RxJava. You can override the UseCase implementation anytime, and it shouldn't affect to your business logic or either the architecture itself.
The only thing is, whenever you change rx to another framework, you must change references too everywhere, and that makes it coupled yes, but the architecture does not require specifically you have to implement RxJava, that is what I mean. It is not mandatory to use RxJava. Like @android10 said, in some way, you can change your background executions with your own framework, or what you desire, but that will force you to change it as well in all the architecture structure.
Anyway, Agera is a set of reactive utilities, it is new, in terms of it doesn't have much questions in Stackoverflow for now, and it was a library developed for a specific project in google by their own developers, as they say.
Amend me if I'm wrong please.
Can we introduce a delivery interface in the UseCase as another layer to deliver the result to other layer? If the user want to use Rx then just create something like RxDelivery or if the user want callback style then create callback CallbackDelivery. Do we have pattern like this available, what is the pattern name? My imaginary classes.
interface Delivery<T> {
void deliver(T result)
}
class RxDelivery implements Delivery<List<User>> {
void deliver(List<User> results) {
subject.onNext(results)
}
}
class CallbackDelivery implements Delivery<List<User>> {
void deliver(List<User> results) {
callback.onSuccess(results)
}
}
class GetGithubUsersUseCase(Delivery resultDelivery) {
void execute() {
resultDelivery.deliver(getGithubUsers());
}
}
In my opinion, we are doing a lot of over engineering here and by introducing another level of abstraction the code will become unreadable.
The main reason why I stick to RxJava is because it simplifies the way I'm retrieving and showing data and makes asynchronous calls way easier.
Also, to clear this up, I tried to be proactive. Theoretical models sound good on paper, like Clean Architecture approach, but when it comes to reality, things get more complicated, like in this case. That is why I consider we need to be strict but at the same time flexible enough and establish our boundaries to go for other alternatives too.
On Android a pure Clean Architecture model using functional or reactive programming would not work, unless you write all the RxJava code yourself or you create wrappers all over the place, which, again bring up a lot of complexity.
My two cents.
For the record, the first version of this repo did not include any dependency to any framework. You can find it here: https://github.com/android10/Android-CleanArchitecture/releases
In both articles I give more information why in the end I made all these decisions: http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/ http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/
Also I found it very hard to scale specially when you have big teams and many contributors.
I hope that helps.
Hi, I've done some experiments with RxJava2 and the base http://reactivestreams.org/ standard interfaces (which the new RxJava2 is based in collaboration with other new reactive composition frameworks). The experiment was intended to check if the domain dependency could be reduced to just dependency on ReactiveStreams. Unfortunately the ReactiveStreams foundation classes are just 4 very core interfaces which do not include any notion of composition, schedulers, operators. We can't compose different UseCases inside domain, we can't use Rx operators. So I concluded it's not worth to reduce the RxJava dependency at this time. Maybe if the ReactiveStreams standard grows up in future. My 2 cents.
Hi, here I am again, this time with a different concern. Citing Uncle Bob's explanation of Use Cases:
Your use cases depend on RxJava framework. I have to provide a Subscriber implementation in order to obtain List or a single User. I expect that a UseCase hides the implementation logic from the outside. To me, a UseCase is Given an id, Return a User.
Your case is Given an id and a Subscriber implementation return a User. What if at some point I don't want to use RxJava anymore? My UseCase shouldn't change! I have an id and I want a User back, but it still requires something depending on an external framework, meaning that I have to reimplement my UseCase even though nothing has changed, except for the framework it uses to accomplish the job.
Thank you @android10