android10 / Android-CleanArchitecture

This is a sample app that is part of a series of blog posts I have written about how to architect an android application using Uncle Bob's clean architecture approach.
Apache License 2.0
15.51k stars 3.32k forks source link

Breaking dependency rule: Data layer is dependent on Domain layer? #245

Closed qasimvibrent closed 7 years ago

qasimvibrent commented 7 years ago

Apologies if this has been previously asked.

I'm following the articles and the samples - the dependency rule states you can only point inwards.

In the sample, the data layer repository is implementing the domain layer repo interface. Isn't this breaking the rule? I've tried to understand why this is acceptable but to no avail,

Can someone fill me in ?

juanagu commented 7 years ago

Hi @qasimvibrent implementation is not dependency. DI: is a technique whereby one object supplies the dependencies of another object.

Dependency in this project: https://github.com/android10/Android-CleanArchitecture#architectural-reactive-approach

qasimvibrent commented 7 years ago

@juanagu I know what DI is, what I mean is that the dependency rule states an inner layer should not know anything about the outer layer. In this example we have the data layer repository implementing the interface inside the domain layer, which is the layer outside it. This means the data layer knows something about the domain layer, despite the rule stating not to do that.

Hence I am asking what was the thought process there.

juanagu commented 7 years ago

You're right @qasimvibrent , I think the correct location of IRespository would be in DL.

mohamad-amin commented 7 years ago

Then how would you use these repositories in domain layer? The idea is the domain layer should be a java module I think and not an android module; meaning that it can't access those repositories in the data-layer.

qasimvibrent commented 7 years ago

@mohamad-amin I'm not questioning that, I just don't get why the interface is in the domain layer breaking the dependency rule. According to the rule, I guess I would have assumed that the repository interface would remain within the data layer, so when the repository implements it as an interface, it doesn't break the rule. And since the outer layers can know about the inner layers, then the domain layer can happily use/interface with the data layer as expected.

sina- commented 7 years ago

@qasimvibrent I think you assume DL is inner to Domain, which is not the case. Domain is the most inner class: https://github.com/android10/Sample-Data/blob/master/Android-CleanArchitecture/clean_architecture.png

qasimvibrent commented 7 years ago

@sina- No, Domain is not the inner layer, Data is the inner layer, domain is the outer layer and presentation before that. For example, if domain was the most inner, then you are saying Repository classed would have UseCases within them which isn't the aligned approach with MVP-Clean.

That diagram you mentioned just says "Domain logic" which is different. See this: https://github.com/android10/Sample-Data/blob/master/Android-CleanArchitecture/clean_architecture_layers_details.png The flow works inwards, Data Layer (repos etc) being the last and final. And see this: https://github.com/android10/Sample-Data/blob/master/Android-CleanArchitecture/clean_architecture_layers.png The data layer is the last step, innermost layer.

In my question above, the Repository is implementing an interface that is "above it"( inside the domain layer). And this means that the Repository has a dependency on the domain, which again, breaks the rule.

So I am asking if @android10 can fill me in as to if this is just a one off, or if there is a reason too this.

android10 commented 7 years ago

The domain layer is the inner circle (logic). Repositories interfaces sit on this layer, implementations of this interfaces are in the data layer. It is that simple: you need a way to communicate between layers, that is why you need interfaces.

qasimvibrent commented 7 years ago

The domain layer is the inner circle (logic).

But shouldn't the data layer sit inner to the domain? Because saying the domain layer is the inner logic gives the impression that the domain and the data layer sits on the same pane, which imo it shouldn't according to clean mvp and for testability reasons. (I'm no expert so feel free to correct me!)

Repositories interfaces sit on this layer, implementations of this interfaces are in the data layer.

@android10 I understand its that simple and am not trying to complicate anything - just trying to understand if you are making this decision on your own preference or there is a design reasoning behind this.

The data layer implements interface within the domain layer. Doesn't that break the inwards dependency rule ? Why could you not just have the interface in question reside with the implementation in the data layer.

Uncle Bob's article states:

For example, consider that the use case needs to call the presenter. However, this call must not be direct because that would violate The Dependency Rule: No name in an outer circle can be mentioned by an inner circle. So we have the use case call an interface (Shown here as Use Case Output Port) in the inner circle, and have the presenter in the outer circle implement it. https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

Having the repo class even implement the domain interface, and references its name, is in exact contradiction to the above ( assuming you are not grouping domain and data on the same layer).

kevin-barrientos commented 7 years ago

Domain layer is the must inner layer in any architecture. Data layer is a detail and therefore it should be abstracted from the domain layer. That is why for the domain layer you just define an interface so anybody can implement it as it pleases in the data layer.

qasimvibrent commented 7 years ago

@kevin-barrientos Please read the post above. I know that domain and data layer need to be abstracted from each other. I understand why we need and what the interface's purpose is. Again its more about separation, and why the data layer is implementing an interface outside its layer.

@android10 did you understand my concern in the earlier post or am I misunderstanding ?

android10 commented 7 years ago

First, the circles graphic is ONLY an idea, you can have as many circles as you would like.

The data layer is an implementation detail, that is why it is senseless to move Repository interfaces over there. Otherwise you will break the dependency rule.

What REALLY solves your problem is you DOMAIN (logic). That is why you rely on contracts (interfaces) in order to accomplish this. The rest of the layers have the implementations for this contracts.

kevin-barrientos commented 7 years ago

@qasimvibrent I've read that post. I think you are misunderstanding the dependency rule.

Domain layer must not know how the others layers implement the details but it must have some way to comunicate with them. How else would you communicate both layers without at least one knowing something about the other?

Since Domain layer is the must inner layer it cannot know nothing about data layer but there is no problem with Data layer knowing what it should implement from the domain layer.

Here is an Uncle Bob's video about SOLID principles where he describes the Dependency Inversion Principle and diferences between the dependencies in compile time vs the dependencies in run time. I recomend to see the whole video to get the best of it.

In other words, the repository interface is defined in the domain layer so it can depend on it within its on domains. If the repository interface is implemented in the data layer and referenced from the domain layer then you will be breaking the dependency rule.

qasimvibrent commented 7 years ago

@kevin-barrientos Thank you, I understand and have watched that video some time before, but it was the last part after you edited is what I was needing clarification on. @android10 So my understanding is wrong here. My argument has been based the article that data layer is an inner layer to the domain layer - in which the above that I am stating would break the dependency rule.

Since this is incorrect, it now makes sense as to why it would break the rule because you are stating that the data layer is an outer layer of the domain? - can you clarify this or what layers is within where. I know you both have mentioned that the domain is the most inner layer - but it hasn't been clearly identified where the data layer exists. Within the diagrams and description, there's an insinuation that data layer exists within. Thank you.

kevin-barrientos commented 7 years ago

Well it depends on your solution but for this specific diagram the Data Layer is at the Frameworks & Drivers level. You can see ti even has a DB reference in it.

image

qasimvibrent commented 7 years ago

@kevin-barrientos @android10 I see that - Thanks folks. This was useful 👍