bufferapp / clean-architecture-components-boilerplate

A fork of our clean architecture boilerplate, this time using the Android Architecture Components
MIT License
1.28k stars 178 forks source link

Indirect dependencies #11

Open Dwite opened 6 years ago

Dwite commented 6 years ago

Hello @hitherejoe ,

I have a question about dependencies. Currently, Remote module depends on Data, and Data module depends on Domain and because of that If we want to get information from Remote with Models that actually should be only in Remote we have to create a duplication of that model at each layer.

Example: We have Remote module for the API that has method getRepositoryByPlatform(platform: Platform) and our Platform is simple Enum class enum class Platform { IOS, ANDROID } without duplication Platform class would be in Domain layer. But in this case if we need to specify @SerializedName for example, we would need to add Gson dependency to Domain layer, that looks incorrect from my point of view. And because of that creating Platform representation model at each layer looks like an overhead to me.

So the question is how do you handle such cases?

erluxman commented 6 years ago

I think this all about tradeoffs. The model duplication being done in this repo is not just because architecture restricts us from using certain Framework APIs or other logically separated APIs. It is also because a single module can treated as independent entity in some level. For example the person responsible for domain changes the "Platform" file and breaks the other modules in every place they use that Platform Enum. Rather than that Using the convention in this repo, it will only break the mapper function which can be fixed easily and specially at a single place in a single module rather than countless places where the "Platform" enums are being used. This will give more confidence to a programmer responsible for a module to bring changes. This makes the code less explosive even when it explodes when someone touches it. This is my understanding on this thing.

Dwite commented 6 years ago

@erluxman , in this case, Remote->Data mapper is inside Remote repo, and that looks a bit strange

I mean the question is not in that each layer has own model, but how layers depend on each other

UI->Presentation->Domain<-Data<-Remote

erluxman commented 6 years ago

Yeah this has been one of my question too. I had made a issue in its original repo (not android architecture one). That confuses me too but the principle in itself is justifiable. I am also looking at the project and see if I can do something to make it more clear and concise.

Dwite commented 6 years ago

@erluxman well, it looks a bit strange that we do a separate "independent" modules, that actually have 1:1 dependency to business logic, and if we would like to reuse "Remote" layer, it will have to add new Mapper for new "Data" layer, instead of "Data" writing mapper by itself and "Remote" being easily pluggable unit

hitherejoe commented 6 years ago

Hey @Dwite & @erluxman - the BufferooRemoteDataStore.kt in the data layer is not actually the implementation of the remote source, but more of an abstraction of this logic out of the BufferooDataRepository.kt class. This Remote source is just an example of a way to organise things, it is not necessarily needed to follow clean architecture, for example, you could communicate with the remote layer via the interface directly from the BufferooDataRepository. The Remote->Data mapper is inside of the Remote layer because of the directions in which the dependencies point - whilst this written out may look different from the clean architecture onion diagram, you can still separate these modules out into the diagram and it would represent a clean approach. IN my view, data should not know about the source modules (remote and cache) but instead, they should be injected in - which is how we have done it in this project. I feel this keeps the data layer unknown to outer sources. But with any projects, it is up to you how you structure things (whatever works best for you and your team :) )

Remote is still an easily pluggable unit at this point, the data layer only has an interface which is used by the remote layer - the data layer does not depend on the remote layer in any way.