Open CROSP opened 8 years ago
See the following discussions on similar matters:
https://github.com/android10/Android-CleanArchitecture/issues/127 https://github.com/android10/Android-CleanArchitecture/issues/115 https://github.com/android10/Android-CleanArchitecture/issues/47
@Trikke thank you for answer I have already read this posts. I feel that your Infrastructure layer is the same idea as mine.
Anyway in any specific platform we have UI framework and CORE framework, so anyway we will have two layers dependent on specific platform. Maybe it is worth to create separate layer which will be responsible for all stuff like GCM
notifications, Location
... It will be referenced by domain layer
as repository data
layer is being referenced by domain layer
now.
We will have separate layer for data
and separate layer for lets say device specific data
provided by services.
In case of Android
and iOS
it is location, notifications, camera photos, music player ...
What do you think about this.
P.S. Please write me a letter crospdevel@gmail.com
Well, you are getting the hang of the general idea of it! A few remarks :
On any specific platform (iOS,Android,Windows,..) you'll always be stuck with a framework that interfaces with everything on the platform, from UI to Networking to Data Access. The point of an architecture is that we create an idea that works for al those platforms with minimal effort. Because all that stuff like location, gcm, ... doesn't have anything to do with data that is important in your app, it doesn't belong in the Data layer but needs a seperate layer. A lot of people make the mistake of just copying this example repo and start putting everything in the Data layer. Only put data in the Data layer that is important to your app
So, like you said, an Infrastructure layer to handle platform services and reside on the same "level" as the Data layer, seen below.
You can even see that the above image contains "external services" and "devices" on that outer level, which is what you are talking about.
@Trikke thank you for complete answer. I got an idea. One more thing I am interested in.
My application handles user session. I have Session Manager
which is responsible for maintaining user session through app lifecycle. All my managers are stored in ApplicationContext
, and injected with the help of Dagger
, better than global variables, but still a lot of separate layers are mixed in one place. When any REST
request is made I access context (Application) and get SessionManager
and custom interceptor access current session and gets token and other credentials required for REST
call.
So my question is, how Session
, UserAuthorization
should be handled correctly in terms of Clean Architecture
approach. I think data layer should not be responsible for that, I feel need of new layer like SecurityLayer
, but in such case it will become Layer apocalypse
soon. On the other hand this is a sort of use case
like AuthenticateUserUseCase
or GetUserCredentialsUseCase
.
What do you think about this ?
Thanks.
Well, the first question should always be, do i really need a context here and why? Since i don't know how your SessionManager works, i can only guess. So the first thing to do is see if you can modify your Managers to work without.
You shouldn't be creating layers for any type of generalised action. Stuff like Security is actually a cross-cutting concern. This means that it is a topic that doesn't belong in a specific layer.
So your Session logic and Authorization logic belongs in many layers. For example :
The hard part for you seems to be that Authorization seems tightly coupled with your REST service. So it would seem logical to have the Session Manager (preferably without a Context) in the same layer as your REST service. This can be data, or infrastructure.
Thanks a lot man. You are really good at architecture.
Sorry I haven't described better my SessionManager
.
Btw, this picture doesn't corresponds to clean architecture
described and used in this repository. Business logic is the core of all system, but on the picture is default 3-layered architecture. Am I right ?
I think that SessionManager
should belong to DataLayer
, as far as I really don't care about tokens, passwords and other stuff in UI
, I mean that this is just simple Use Case
to Auth user or to Logout.
And in case of session, I think the following way will suit good enough for clean architecture approach.
DataLayer
or Infrastructure
layer. Infrastructure because we need to read saved credentials from SharedPreferences
and this is platform specific storage. But on the other hand all databases are platform specific, and in general Java sockets are platform specific, Java is also platform. So I have question is it okay if Data
layer knows about platform specific stuff ? Use case/Business
layer. For example AuthUserUseCase
, LogoutUserUseCase
, these use cases are essential part of all application, this is core, but on the other hand I don't care what specific security mechanism is used, so I can swap it easily. UI
layer will just request auth, logout according to user actions. Furthermore Infrastructure
layer also can request to clear preferences when app was closed (Application class instances was destroyed). Consider that UI , Data and Infrastructure layer will be on the same layer (ring outermost) based on this architecture. And in the middle will be Use Case layer
or Business
.
Data flow will be following. UI (AuthRequest) ---> UseCase (AuthUserUseCase) ---> Data(ValidateCredentials) or Infrastructure (Application context is going to be destroyed) ---> UseCase (LogoutUser) ---> DataLayer( Clear Preferences, close connections, files ..).
One thing I am worrying about is that there are three layers dependent on platform (UI, Infrastructure, Data) is it okay ?
I would be grateful for your thoughts.
Yeah, that's true, it's a more traditional diagram, i was just using it to show that there is also stuff that applies to all "layers". Things like Security isn't something you can just put in one layer and keep it there. It's going to be present in all "layers".
In general, your idea of data flow seems correct, so stick with that. From an architectural standpoint, keep the following in mind :
On the point of "depending on a platform": you'll always be writing platform specific code. Doesn't matter if it is Java, Android, or iOS. The choice of platform depends on which machines you'll want to run your app. So now you're writing an Android specific app, so it must know about the Android platform. You can only abstract so much before it becomes ridiculous :)
@Trikke thanks again. It's pleasure for me to discuss such topic with you.
So in general Business layer
operates with interfaces only.
Another example I think can be on the Business
layer is collecting appropriate view (representation of data), fro instance instead of combining multiple data entities Company and Company Group, business layer will return CompanyView (where all required fields will be set) and Presentation
layer will simply display data without doing business logic.
Rule of thumb Business
layer is core and it should be like cross-platform, all you need to do on new platform is to implement required interfaces. But Business
layer will be the same.
Business
layer is just coordinator.
I agree that Security will be present in each layer but represented differently (login screen, request, encrypting) , am I right ?
No problem, i'm happy to help people curious to learn :)
So yes, the business/domain layer is the core of your app. It's also the central part of the diagram of Clean Architecture. The domain layer operates with interfaces to connect to the outer layers. But it can also have concrete implementations for it's business logic. Like your example, you can have a concrete Factory that takes 2 data entities and create a new one to be passed to Presentation. So don't think that the domain layer only exists of Use Cases.
Here's an extract about this
As you move inwards the level of abstraction increases. The outermost circle is low level concrete detail. As you move inwards the software grows more abstract, and encapsulates higher level policies. The inner most circle is the most general.
Rule of thumb is that if i ask you to see what your app does, you only need to show the domain layer to me. If i wanted to then see how you are doing everything around that, i'd need the rest of the layers.
And yes, Security is something that is represented differently in each layer, but is present in all. This is why it's a cross cutting concern.
Please keep up on reading on these matters, even other stuff then Clean Architecture, there's always something to be learned.
@Trikke thanks again, this is really good stuff to dive deep into. I always like more architectural approaches rather than feature-driven. I am going to refactor my application completely according to Clean architecture
principles and I will share results.
Maybe you can suggest some references to read more about this ? I think this would be useful for everyone interested in this topic.
@CROSP : Anything from Uncle Bob (like his articles 1, 2). There's also a few youtube videos from talks of his.
@Trikke Thanks, I have already seen them. If I found something interesting I will share. But in general Uncle Bob architecture is great, and can be applied not only for building Android Apps, but I think whole software system.
@Trikke Kudos man for all the light shaded on this and other discussions.
Just something else to keep in mind when it comes to dealing with android components:
I do not want my domain logic to know anything about any strong dependency with the framework.
@android10 thank you for answer. Do you mean that we should use wrappers around framework components anyway.
Let's consider our outer ring will include one more layer suggested by @Trikke - Infrastructure
It will include some specific features like GPS
, Proximity Sensors
, Compass
or whatever, furthermore it can be as you mention UI Thread
, but this is more specific to internals and related to most of today platforms with GUI.
As suggested in Uncle Bob's book Clean Code
to use my own wrappers around APIs
that makes it easier to test, migrate and maintain.
But I have one question is it ok if Domain Logic
will talk to this Infrastructure layer
directly through wrappers only ? Or it requires some more abstraction in order to avoid tight coupling
For example I have interface that should be implemented on outer Infrastructure
layer - GeolocationProvider
.
So in my Business/Domain/Use Case layer
I will have something like this GetCurrentLocationUseCase
that can be called by Presenter layer
for instance and this call should be redirected again to outer layer Infrastructure
through GeolocationProvider
interface.
Am I right ?
Or it would be better to initiate communication between DataLayer
and Infrastructure Layer
directly and only ask Data Layer
when geolocation is required an it will return latest location ?
Please share your thoughts.
I have just realized that I am still confused a little bit about diagram.
To make everything clear completely, I will show flow on a diagram.
As I understand the Data Layer
is the outermost ring, so our Domain Layer
accesses the layer above it. So what about Dependency Rule
? Where I am wrong ? In case of Data Layer
is below Domain Layer
this is the same well-known N-tier
architecture.
So in my Business/Domain/Use Case layer I will have something like this GetCurrentLocationUseCase that can be called by Presenter layer for instance and this call should be redirected again to outer layer Infrastructure through GeolocationProvider interface.
Am I right ?
Or it would be better to initiate communication between DataLayer and Infrastructure Layer directly and only ask Data Layer when geolocation is required an it will return latest location ?
You were right with your first suggestion. The Data Layer is just for storing data that is central to your app. It's on the same "level" in Clean architecture as the Infrastructure Layer, so you don't call it through the Data Layer.
@Trikke thanks again for your response. what about previous picture, does that make any sense ? Or this is not right ?
Seems about right.
The same discussion went on in here, i hope you'll find some more useful info in there.
@Trikke thanks, again, I am still finding a lot of new to learn about this architecture. I have just realised one important thing, with the help of your explanation from adjacent topic you provided.
Our core business logic is like an engine in auto or cpu in computer. Not very good comparison, but I will try to explain. If we take CPU with ARM, to have such device there are some interfaces, schematics that should be implemented in order to run ARM CPU. Every CPU has specific buses, max memory available memory amount and some other rules down to motherboard material, socket. The CPU is core of a computer, in order to use CPU we have to implement some essential interfaces. so CPU defines some rules (interfaces) and others should implement and conform to this rules.
The same in this architecture to use app logic, you have to implement a bunch of interfaces and operate only through interfaces on the business layer and real implementation can be injected through dependency injection tools and you can swap them left and right.
One weird thing for me and I can guess for other developers is dependency rule. It seems according to the @android10 articles pretty the same as 3-layered architecture
.
Lower layer should know nothing about upper layer. UI-> Business Rules (Controller) -> Database
And in our case it seems for me that business layer
knows everything about upper layers.
For instance, I need to get all users information
UI->Presenter->Business/Domain->Data Layer -> Result back to Business layer -> Result back to Presenter -> Update UI
Here is the question, what about dependency rule it seems that core Business Layer knows about, not really knows about specific implementations, but it provides interfaces for others to implement.Please explain this question. Thanks
I have just played a little bit with @android10 project and logged data flow to make it more clear.
Here is my forked repo with log statements https://github.com/CROSP/Android-CleanArchitecture
And the most interesting part is log output
D/CLEAN_ARCHITECTURE: 1. I am View in UI outer layer. User has just clicked on load data button
D/CLEAN_ARCHITECTURE: 2. I am UserList Presenter in Presenter layer (second) . I got the request to load user data
I/System.out: 3. I am GetUserList use case in Domain Layer. I am trying to get some data from data layer
I/System.out: 4. I am users repository in Data Layer. I know where to get user list and you should not care about this
I/System.out: 5. I am GetUserList use case in Domain Layer. I have just got observable (data) from data layer
D/CLEAN_ARCHITECTURE: 6. I am UserList Presenter in Presenter layer (second) . I have just got user data from domain layer
D/CLEAN_ARCHITECTURE: 7. I am UserListFragment Presenter in UI (outer layer) . I am rendering user list
So it seems that it is true about violating Dependency rule
lower layers know about higher layers.
Please share your thoughts and explanation
Hey @CROSP , it seems you're confusing the flow of data with dependencies. In the linked discussion above there was already an explanation about this. See this post and then this other post for the entire explanation. The amount of love those post got seem to indicate they explained this issue well.
@Trikke , thanks, exactly, I have just looked more precisely to the dependencies and it seems that I got it.
Dependency rule is still here and applied correctly.
Data depends on domain, because we have declared interfaces for the Repositories here.
Presentation depends on domain and data.
Here is one more question, Uncle Bob didn't mention anything about same-layer dependencies
, I mean does this make any sense when there are dependencies between components on the same layer ?
In case of this repo, it mostly used in dagger dependency component.
But will it be ok if I swap data layer implementation with completely different, that only implements interfaces from domain layer ? I think no.
I feel like it should be another layer or something else that coordinates and satisfies all dependencies inside the project, like Wireframe
in VIPER
architecture on iOS.
Also in case of this repo, it seems that presentation layer does too much.
What do you think about that ?
@Trikke I followed your Infrastructure idea. I put AlarmManager, Log, Receiver, Service, AudioManager etc to the Infrastructure layer. Is this OK? https://github.com/enuoCM/DE-MVP-Clean/tree/master/app/src/main/java/com/xixicm/de/infrastructure
Hi, I am trying to migrate to
Clean Architecture
.I have application which is made in standard way, I tried to decouple, but still a lot of stuff happens in
Activities
andFragments
.Example is quite simple, mostly applications are much more complex so it is much harder to decouple all highly coupled components inside application.
I have just faced with one problem is Managers and Services that requires
ApplicationContext
orActivityContext
.For example I have
LocationManager
which is responsible for getting location, but it requires context, at least to getService
and to listen to lifecycle ofActivity
.I think this manager could go to
Data
layer, but this is undesirable dependency.I really don't want to put this login into presentation layer. I firmly believe that
Presentation
layer should be just UI and ONLY UI nothing more, unfortunatelyAndroid SDK
is build in a way that we haveGod Object
-Activity
but I still wanna to get rid of anything except use cases inPresentation
layer.I see some ways how this can be solved :
Service
orLifecycle
layer and make it tight to context lifecycle, also in order to keep things abstract interface with common lifecycle methods can be created (onCreate
,onDestroy
...) and injected via dependency injection tool like our belovedDagger 2
Android
dependency to some layer. Presentation layer is already coupled toAndroid Context
, but again UI should be UI nothing more, consume, update, and request data throughUse cases
from domain layer.Furthermore one important thing to note that
LocationManager
is great example of publisher/subscriber pattern so it can be easily adopted toRxJava
.All things considered, I would be grateful for any thoughts, advice on this problem.