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

UserDataRepository breaks dependecy rules #65

Open rohliq opened 8 years ago

rohliq commented 8 years ago

Hi,

didn't UserDataRepository breaks dependency rules? Class is from data layer but implements userrepository interface which is from domain layer.

thanks rohliq

Trikke commented 8 years ago

No it is correct. The implementation of the interface resides in the data layer, so that is correct. Because of the inwards dependency rule, a use case from the domain layer can know a UserDataRepository exists through an interface, but can not know (or shouldn't even care) what the concrete implementation is of that UserDataRepository ( be it disk, memory or network ). So the domain defines that a UserDataRepository exists, but it cannot know of the data layer and its implementation.

The reason you think it breaks dependency is because of the flow of control. Look at the following diagram

Image of Onion Structure And this is the accompanying quote by Uncle Bob about crossing those boundaries

At the lower right of the diagram is an example of how we cross the circle boundaries. It shows the Controllers and Presenters communicating with the Use Cases in the next layer. Note the flow of control. It begins in the controller, moves through the use case, and then winds up executing in the presenter. Note also the source code dependencies. Each one of them points inwards towards the use cases.

We usually resolve this apparent contradiction by using the Dependency Inversion Principle. In a language like Java, for example, we would arrange interfaces and inheritance relationships such that the source code dependencies oppose the flow of control at just the right points across the boundary.

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.

The same technique is used to cross all the boundaries in the architectures. We take advantage of dynamic polymorphism to create source code dependencies that oppose the flow of control so that we can conform to The Dependency Rule no matter what direction the flow of control is going in.

I hope this explains things for you.

android10 commented 8 years ago

@Trikke Kudos for such a great explanation!

Trikke commented 8 years ago

@android10 happy to help here. You got me interested in proper architecture on android and i've been digging deeper ever since. Seems natural to help a bit with all the questions!

android10 commented 8 years ago

@Trikke good to hear! I really appreciate your help buddy. Sometimes it gets hard to answer all the question and an extra couple of eyes/hands are super useful :)

rohliq commented 8 years ago

thanks guys

2015-11-12 13:37 GMT+01:00 Fernando Cejas notifications@github.com:

@Trikke https://github.com/Trikke good to hear! I really appreciate your help buddy. Sometimes it gets hard to answer all the question and an extra couple of eyes/hands are super useful :)

— Reply to this email directly or view it on GitHub https://github.com/android10/Android-CleanArchitecture/issues/65#issuecomment-156093332 .

ildar2 commented 8 years ago

UseCase output port Interface should be placed in the same UseCase layer, according to the diagram. But the question was about data layer output Interface (UserRepository) being placed in UseCase, which is domain layer.

No name in an outer circle can be mentioned by an inner circle.

But the name 'UserRepository' of outside circle (domain) is mentioned by data - the inner circle. This is imo indeed a case of breaking dependency rule

android10 commented 8 years ago

@ildar2 data is not the inner circle. it does not solve your problem (only provides data), domain layer does and it is where your logic sits. There is no dependency rule break up. :smile: