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

Why the domain layer is tigthly coupled to a framework dependency (RxJava) ? #143

Open
ghost opened this issue Apr 26, 2016 · 12 comments
Open

Comments

@ghost
Copy link

ghost commented Apr 26, 2016

Hi, here I am again, this time with a different concern.
Citing Uncle Bob's explanation of Use Cases:

We also do not expect this layer (USE CASES) to be affected by changes to externalities such as the database, the UI, or any of the common frameworks. This layer is isolated from such concerns.

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

@ghost ghost changed the title Why the domain layer is tighly coupled to a framework dependency? Why the domain layer is tigthly coupled to a framework dependency? Apr 26, 2016
@ghost ghost changed the title Why the domain layer is tigthly coupled to a framework dependency? Why the domain layer is tigthly coupled to a framework dependency (RxJava) ? Apr 26, 2016
@android10
Copy link
Owner

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?

@ghost
Copy link
Author

ghost commented Apr 27, 2016

@android10 How Java 8 would help here?

@yshrsmz
Copy link

yshrsmz commented Apr 27, 2016

Java 8 has its own stream api, though I don't think it becomes available on Android anytime soon

@farmazon3000
Copy link

What about https://github.com/google/agera?

@android10
Copy link
Owner

@farmazon3000 this is out of scope of this discussion actually. You might be able to use either one or the other or even both.

@nanyi5452
Copy link

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...

@rshah
Copy link

rshah commented May 10, 2016

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)
        }
    }

@FranRiadigos
Copy link

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.

@rshah
Copy link

rshah commented May 12, 2016

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());
     }
}

@android10
Copy link
Owner

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.

@android10
Copy link
Owner

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.

@sevar83
Copy link

sevar83 commented Oct 6, 2016

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.

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

No branches or pull requests

7 participants