I'm trying to find a way around the integration of Google and Facebook login for an Android application using the Clean Architecture.
My application has 3 Android Studio modules :
- presentation : contains the Interface Adapter layer of the Clean Architecture (Presenters), along with all my UI (Activity, Fragment, Custom Views) (part of the Framework and Driver layer)
- domain : This is the Use Case layer of the Clean Architecture. It contains the business models, Use Cases, and repository interfaces
- data : This contains all the Driver and Framework classes, the libraries (retrofit, databases, etc) and repository implementations
I would like to isolate the login specific SDKs in my data layer (which is a separate module in Android Studio).
The issue I have for this particular use case (Google login for example) is that the SDK need to talk directly to my Activity (presentation layer). Once I have built a specific object, I need to call startActivityForResult from an Activity, and I receive a callback in the onActivityResult method of my launching activity, containing the login informations.
These 2 things make an obligation to :
- either keep the Google/Facebook SDK dependencies in the presentation layer. BUT this violates the clean architecture principle, I would like to keep these dependencies in my data layer
- or add a call which will go through all my layers (presentation, domain and data) to give back the login informations from the onActivityResult method. BUT this means that I would modify my domain contract because of a particular login SDK
None of this seems OK. Do you know a proper way to handle this use case ?
-
Your names are throwing me off. Clean Architecture has an interface adapter layer that has presenters in it. But it doesn't have domain or data layers. Onion architecture doesn't fit all your names either, though it does have a domain. The closest fit is 3 tier which has presentation and data but not domain. Are you looking to follow one of these or are you making your own?candied_orange– candied_orange02/26/2018 12:38:29Commented Feb 26, 2018 at 12:38
-
My names are confusing. Here is a clarification about my 3 differents modules : - presentation : it corresponds to the interface adapter layer - domain : it corresponds to the use case layer of the onion architecture - data : it corresponds to the first level of the onion architecture, where all the framework dependencies belongRafi Panoyan– Rafi Panoyan02/26/2018 12:43:38Commented Feb 26, 2018 at 12:43
-
If you want us to follow your post with Clean Architecture in mind please edit the post to use it's terms. Don't explain discrepancies away in a comment.candied_orange– candied_orange02/26/2018 12:48:03Commented Feb 26, 2018 at 12:48
-
it's edited. If you need other clarifications to understand the architecture issue I'm facing, feel free to askRafi Panoyan– Rafi Panoyan02/26/2018 12:51:29Commented Feb 26, 2018 at 12:51
1 Answer 1
If I understand you right, you're mapping your modules onto clean architecture like so:
( Data ( Presentation ( Domain ( ) ) ) )
That's fine. Names are a little different than I expected but it can work.
I would like to isolate the login specific SDKs in my data layer (which is a separate module in Android Studio).
That's a good instinct right there. Knowledge of which specific login SDK you are using should not be allowed to spread. Keep it in one place.
The issue I have for this particular use case (Google login for example) is that the SDK need to talk directly to my Activity (presentation layer). Once I have built a specific object, I need to call startActivityForResult from an Activity, and I receive a callback in the onActivityResult method of my launching activity, containing the login informations.
These 2 things make an obligation to :
either keep the Google/Facebook SDK dependencies in the presentation layer. BUT this violates the clean architecture principle, I would like to keep these dependencies in my data layer
Clean Architecture is not a principle but yes, this would be bad.
or add a call which will go through all my layers (presentation, domain and data) to give back the login informations from the onActivityResult method. BUT this means that I would modify my domain contract because of a particular login SDK
Remember it's knowledge of which specific SDK that we're using that we wish to isolate. The idea of logging in is definitely something that cuts through the layers. As you descend the layers knowledge about the details about the login should be being stripped away. So google's login SDK can live in your Data
layer but Presentation
should just be thinking of this as a login to present in some language/API that the SDK speaks. That is your Output Port
here. Domain
should be thinking of login without caring what language/API the SDK speaks.
So to me this seems ok. If you do it right.
-
These type of SDKs communicate according to the OAuth2 protocol. If I understand your (very complete) answer, the presenter can have an API to speak the OAuth2 language (i.e. getting a token to send to another server). The Domain then must carry this data, without knowing it's a token (not sure about that), and send it to my server through an interface. I think one flaw of my design is that my Domain layer can communicate directly to the Data layer (through an interface though)Rafi Panoyan– Rafi Panoyan02/27/2018 10:06:15Commented Feb 27, 2018 at 10:06
-
@RafiPanoyan No you shouldn't be skipping layers. Communication from your domain to your data should go through presentation. When it goes through presentation details unique to the protocol can be added back. Also You seem to be missing a controller. Communication from your data to your domain should go in through a controller module. Here info unique to the particular login SDK is striped away and expertiese at talk to the domain input port is employed. This separates input and output.candied_orange– candied_orange02/27/2018 10:17:48Commented Feb 27, 2018 at 10:17
-
@RafiPanoyan Would you be interested in an example? It's a button push implemented in a Clean Architecture.candied_orange– candied_orange02/27/2018 10:21:31Commented Feb 27, 2018 at 10:21
-
"The Domain then must carry this data, without knowing it's a token" The domain shouldn't "statically" know about the protocol. It's OK to dynamically hold useful data. But I shouldn't be able to look at your source code for your domain and get any hint at all which particular login SDK protocol you are using. If those details aren't here you can swap out your presenter to support a different protocol without touching your domain code.candied_orange– candied_orange02/27/2018 10:38:39Commented Feb 27, 2018 at 10:38
-
I'm interested in your example, thanks ! The thing is that even the name "token" for an attribute let us know which kind of protocol we are using. We could already tell that it's not a classic login with email and password but a OAuth type. Here, a classic login and an OAuth login are not swapable easily without touching the domain codeRafi Panoyan– Rafi Panoyan02/27/2018 13:49:04Commented Feb 27, 2018 at 13:49