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 data layer has a dependency on the domain layer? #136

Open
ghost opened this issue Mar 31, 2016 · 24 comments
Open

Why data layer has a dependency on the domain layer? #136

ghost opened this issue Mar 31, 2016 · 24 comments

Comments

@ghost
Copy link

ghost commented Mar 31, 2016

As stated in Clean Architecture, dependencies should point only inwards. This separates layers in a way that they could be interchangeable easily and also decoupled (right?).
In your case, you decided to create 3 layers which have this dependency relationship:

presentation ---> domain ---> data

You use DI for some good reasons (still decoupling, dependency inversion ecc).
However from your build.gradle files, it seems that data has a dependency on domain, while domain doesn't have anything. The dependency is in this way:

presentation ---> domain <--- data

Could you explain me why? Is there something I'm missing?

@amatkivskiy
Copy link

That's because data layer is implementation of use cases. Domain layer tells what to do and data layer tells how to do.

@lenguyenthanh
Copy link

Yep, because Domain is the most inner layer in this architecture. I'd suggest that you should read those articles again ;)

@ghost
Copy link
Author

ghost commented Apr 1, 2016

@lenguyenthanh I think you're confusing the schemes. It's true that in Clean Architecture representation by Martin, Domain Logic is represented as the most inner layer (the "Entities" circle).
In Fernando representation, the Domain layer is intended as the middle layer which implements the Use Cases. The Data layer, in his case, it's the one containing the entities, though the most innner layer.

So, I repeat, this data layer shouldn't have any type of dependency and shouldn't know anything about the outer Domain layer, am I right @android10?

@amatkivskiy It seems that the UserRepository interface is declared in the Domain module and implemented in the Data module. I understand this choice as this is the way to implement the Dependency Inversion Principle. In this way, the Data module (inner) is dependent on Domain module (outer) so whenever you want to swap the Data module you are able to do it, just replace the implementation and respect the contract. However this thing is confusing me... Are the arrows going inwards telling me "whatever is outer shoudln't know anything inner" or "inner shouldn't depend on outer"?

Citing this:

Dependency Rule: source code dependencies can only point inwards and nothing in an inner circle can know anything at all about something in an outer circle.

It tells me that data layer shouldn't know anything about domain layer, but it must know the UserRepository contract which is part of the domain. Confused.

@android10
Copy link
Owner

@andrewjohnson90

The Data layer, in his case, it's the one containing the entities, though the most inner layer.

That is wrong, data layer contains data entities and this layer is an implementation detail, it is just your data source and belongs to one of the outer circles.
Domain layer is where you solve your problems and you logic sits. It is the most inner circle on the graph.

@ghost
Copy link
Author

ghost commented Apr 1, 2016

@android10 Maybe I'm confusing naming with your example? Being an implementation detail, shouldn't Data be the inner circle? I see logic in Data, not in Domain. You say: Domain contains business rules, Data contains Repository implementation logic, though Domain shouldn't know how data is retrieved and this should be the outer circle.

I'm really sorry if I'm confusing stuff, but I want to understand this properly!
I see it like this:
clean_architecture_android

But you're telling me it's like this?
clean_architecture_android_1

@Trikke
Copy link

Trikke commented Apr 6, 2016

Hi @andrewjohnson90,

i'll join the discussion here, hopefully i'm not to late to this party. I'll do my best to shed some light on this matter as i too had to wrap my head around the concept.

First off, i think the schematics might be a bit confusing as they actually show different things. The one you are citing shows how data flow through the layers, not dependencies or relation of the layers between themselves.

flow of data

The layers themselves and the relation between them are more onion-shaped. The image below shows how the architecture itself is layered (this is not the same as how this repo implements that layering). The architecture is structured as an onion because each layer depends on the layer below itself. (again, this is the actual architecture and it's layers, not the layers from @android10). As you probably already know, the 2 innermost layers are your core business code. Then comes a layer on how to access that data and rules and this is wrapped by external systems.

cc53f294-fbe8-11e5-864e-c87c68d19ed5

I have annotated in horrible red on how @android10 structured his layers on top of this architecture. His Domain layer contains his core business logic and rules. This includes interfaces on how Data is accessed from a Repository. If there were other Services to external apis, these interfaces would be here as well. Remember this layer actually describes the app's inner workings. The Presentation and Data Layer sit on top of this as seen in the onion, so this is why the Data layer depends on the Domain layer.

So the thing to take away from this is that how the architecture is layered and how an example repo like this is layered can look different. I could add (and have) add an Infrastructure Layer, which would handle all interfacing with systems on the device. This layer would be part of the outmost blue layer in the onion architecture. But in my actual project, this layer would also depend on the Domain layer, as shown by the Dependency arrows in the onion. The Domain layer holds the interfaces of the Infrastructure layer, because that is business logic. The actual implementation is of no matter for the Domain, so that ends up in the Infrastructure layer.
If we could theoretically port the app to iOS, i wouldn't touch my Domain layer. I'd just change the actual implementation in the Infrastructure layer because the systems we want to talk to are different on iOS.

@ghost
Copy link
Author

ghost commented Apr 6, 2016

@Trikke Thank you so much for your reply and patience to write this answer and explanation.

I'm still a little bit confused, I don't know if it's me or if some time is needed to get this concept completely.

So, based on your schemes, you're telling me that @android10 architecture is based on "2 onion layers"? He has data and presentation on the same outer layer and domain as an inner layer.
I still don't get why this decision, and why DB (that should be the most inner one imo) is placed in the most outer circle.

As I understood it from Uncle Bob (probably wrong) is that the most deep we go, the most there's implementation logic that can be swapped. A direct dependence to the DB on the same outer layer (where there's UI as well) doesn't make sense to me. Could you please tell me where to read this matter briefly thoroughly or direct me to the right way?

@Trikke
Copy link

Trikke commented Apr 6, 2016

@andrewjohnson90 i'm glad you read all that and have an open mind 😄

I'm guessing the point that you are struggling the most with is that there is a difference between the actual architectural diagram proposed by Uncle Bob and the implementation of that architecture into a project. Both have layers and dependencies, but the concepts are different.
The architecture is the idea. It has layers an dependencies, that shows how an application should be structured. If you strip out all the code of the repo and look how everything is connected and talks to each other, you can tell it follows this idea.
Now we know how we want to structure this, but the actual implementation of that idea will be dependent on a lot of factors. The platform (web,Android,iOS), the language (Java, PHP, Perl) and even the available tools influence what we actually create to reflect the idea. And this repo shows one way of actually implementing it, in a way @android10 felt like setting it up while still adhering to the architectural idea.

I think another issue is thinking that the DB is important and should be in the inner circle. This is a good read on Software Architecture by Uncle Bob. A quick quote on the DB (but please do read it entirely):

The database is merely an IO device. It happens to provide some useful tools for sorting, querying, and reporting but those are ancillary to the system architecture.

Ancillary? That's crazy.

Yes, ancillary. The business rules of your system may be able to make use of some of those tools; but those tools aren't intrinsic to those business rules. If you had to, you could replace those tools with different tools; but your business rules would still be the same.

An implementation always depends on an interface

The DB doesn't belong in the inner layer because it is not important to our Business. How we store data doesn't matter. It could be Sql, a text file or on Amazon S3. But from the architectural standpoint, it shouldn't matter, we don't care how we store data. So that is why it belongs on the very edge of the architecture. The Parse shutdown from a while ago showed a lot of people that if you depend very heavily on a data system (that is external to you) and it's part of the very core of your app, you're going to have a hard time adapting another one if you need to switch.
So our Domain contains the interfaces to the data, on how we store and access data. These are the business rules. But the actual implementation is not important to our business. If your DB is in the outmost onion layer then it is easier to swap out with something else.

Another thing with these diagrams and ideas is that sometimes people talk about "the deeper you go", or "the more outwards in the structure" and it becomes hard for anyone new to follow about which "direction" they are talking about because sometimes they mean the same thing. God knows i had (and still have) issues when following a talk and people start talking in "directions".
Looking it from the onion layer perspective, Uncle Bob would mean the more outwards you go, the more implementation logic can be swapped. So stuff on the outer layers is more prone to change then the inner layers. Your inner layers tell you how your app works, so they change less, only when the rules changes. But the outer layers could change more. External api's change, data access changes, network interfacing changes, new versions of Android that do things differently, ...

I'm just rambling a bit here, so please do ask questions, always.

@ghost
Copy link
Author

ghost commented Apr 6, 2016

@Trikke you opened my mind. I didn't get it at all then. I will write here in case we want to discuss further, but I want to thank you and for this.
As you pointed out, I have the same issues understading terms like "directions, inwards and outwards, deeper you go" ecc ecc.

I compared this layering system to a top-to-bottom implementation. Take Java language, from a high level language to the bytecode, to the JVM, to assembler, to kernel, to machine hardware etc etc... the deeper the more specific. But it's not like that.
Repository implementation (data) is specific, so i thought it should have been "under" the domain layer.

I'm going to read another 10 times those articles, trying to stick them in my mind. Thanks again.

@Trikke
Copy link

Trikke commented Apr 6, 2016

I'm glad to help! it's good that you keep an open mind and are willing to learn and improve on these not-so-easy-to-understand concepts.
Please do keep reading up software architecture and patterns. It's not only important on what we code but on how we structure it.

The helpdesk is always open 😅

@ghost
Copy link
Author

ghost commented Apr 6, 2016

@android10 @Trikke maybe a suggestion to write a new blog post from this discussion? :)

@android10
Copy link
Owner

@andrewjohnson90 you wanna write one maybe? 😄

@binhbt
Copy link

binhbt commented Apr 8, 2016

  1. Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.
    http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
    I think domain = business rules 👯

@liangyx
Copy link

liangyx commented Apr 12, 2016

I have the same confusion as @andrewjohnson90. And the discussion here helps me a lot. Thank you very much :-)

@FrankNT
Copy link

FrankNT commented Aug 19, 2016

Inside data layer, UserEntityDataMapper transforms from UserEntity to User (com.fernandocejas.android10.sample.domain.User).
I don't think it's right. Because data layer should not know about domain layer.
UserEntityDataMapper should belong to domain layer and domain layer can understand UserEntity.
Beside, in my opinion, you should not use RxJava because it goes through 3 layers. Before using it, let's think how to remove it by other tools. Is it possible when your project is escalated?
You also should not use Dagger 2, because it makes things hard to understand. Dagger 2 is amazing tool for developers but it's not suitable for a demonstration like this. A clear architect with simple stuffs will be better.

@Trikke
Copy link

Trikke commented Aug 19, 2016

Inside data layer, UserEntityDataMapper transforms from UserEntity to User (com.fernandocejas.android10.sample.domain.User).
I don't think it's right. Because data layer should not know about domain layer.
UserEntityDataMapper should belong to domain layer and domain layer can understand UserEntity.

Please read up on the subject. In the posts above, the dependencies and layers are explained.

Beside, in my opinion, you should not use RxJava because it goes through 3 layers. Before using it, let's think how to remove it by other tools. Is it possible when your project is escalated?

There's no problem with using tooling libraries to control data through all layers. A logging framework for instance would be the same. It too, would be available across all layers to log stuff. These things are just Cross-cutting concerns.

You also should not use Dagger 2, because it makes things hard to understand. Dagger 2 is amazing tool for developers but it's not suitable for a demonstration like this. A clear architect with simple stuffs will be better.

You'd just be hand writing your dependencies, there's no added benefit. Dagger isn't all that hard to understand, it's a very easy example on Dependency Injection. Even then, you should learn from examples. This shouldn't be a repo that you can just copy and start building your own app upon. That'd be crazy.

@android10
Copy link
Owner

@Trikke you saved me a lot of words. Thanks! Amén!

@kind-serge
Copy link

kind-serge commented May 25, 2018

Probably a wrong place to discuss the architecture principle itself, but seems like this is the best thread on the entire internet about fundamental flaw of the onion architecture diagram pointed out by @ghost, which causes so much confusion about the data layer.

Let's start with simple case. As an end-user using Web and any UI, I interact with the application, and my expectation that it works by accessing a DB (that's where application data is stored). But how does it work if the architecture does not allow those layers to communicate? (I know what you are thinking, but bear with me).
onion-where-is-db

Now, here is the trick:
onion-dependency-injection
Clever, right? No. The basic misconception here that this describes an Abstraction Pattern with heavy reliance on Dependency Inversion Principle, but that is an implementation detail of a software design. That pattern and principle don't magically create a layer of an architecture, because a repository is the same component which stays in the same layer, regardless if it has an abstraction or not. Whatever you do, you will never be able to implement a repository without direct or indirect (abstract) dependency on a data layer in a reasonable manner.

I'm not trying to argue the approach here, Onion is great indeed! The only problem is that the original diagram tries to combine the architecture and design together - and that's the it's biggest problem what creates so much confusion. Once you remove the infrastructure from the diagram, it's going to be priceless, and if you need to have an understanding where the data layer is - you need a second design diagram showing important implementation aspects. Or perhaps you can fit the data layer in a 3rd dimension on top of the domain layer of a 2d diagram.


Update
Decided to write about it in details: Stem in Onion Architecture or Fallacy of Data Layer

@mefilt
Copy link

mefilt commented Jul 19, 2018

Why are the UseCase interfaces stored in the Domain layer, not in the Presentation Layer?

@android10
Copy link
Owner

@mefilt why would they be part of the presentation if they are not dealing with any UI? :)

@sanogueralorenzo
Copy link

sanogueralorenzo commented Jul 26, 2018

Thanks a lot for this issue, old but gold. I shared this multiple times with people who were confusing data flow & dependency rules.

I wrote a medium about it, any feedback is welcome!

https://proandroiddev.com/clean-architecture-data-flow-dependency-rule-615ffdd79e29

@Oziomajnr
Copy link

I think this diagram from the article above best illustrate the structure of clean architecture that has been implemented in this repo, I was confused too when comparing it with the Bob's model.
image

@oppo404155
Copy link

oppo404155 commented Feb 19, 2022

@mefilt
It's clear that domain layer is the most inner layer and it shouldn't know any thing about outter layers . But the domain need to call data layer for telling it about the information that usecases need so somehow there should be a way to cross boundaries without having any reference from outter layers in domain leyar .here dependency inversion comes with the solution . By making an interfaces inside domain (most abstract) and make it's implementation in data layer and this is the way by which domain layer can interact with data layer

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