Android: MVVM and separation of concerns - android

I'm almost finishing migrating my app to MVVM with databinding and livedata (still java though) and now I have much more than a decent architectured Android app (which I'm showing below). I'm happy with that, but would like to go one step further.
Talking about clean architecture, I'm trying to figure out how to do a proper separation of concerns in Android (database, business, services, etc).
I work in .net and in that platform, what you do to separate layers is to create a different proyect for each layer (database, bussiness, presentation) and then you reference them in the correct order, but projects are mostly independent one of the others.
In Android, and as far as I know, you have an app module and even though I have a nice package agrupation, all is "together" into the same project.
I'm not sure if this is the best approach to really follow clean architecture principles. I've heard about Dagger, heard you can create modules with it, but not sure if it is intended for what I'm trying to do.
Any help/hints about a good way to implement separation of concerns in Android?
My current app structure:
com
xxx
xxx
dto
class_1_dto.java
...
class_N_dto.java
helpers
helper_http.java
helper_json.java
helper_utils.java
helper_enum.java
helper_file.java
helper_smtp.java
helper_date.java
...
model
model_class_1
model_class_2
...
all_model_classes_linked_to_AWS_database
poco
some_poco_classes
repository
aws
IAWSDAO
AWS_Repository
...
all_stuff_related_to_AWS_database_query
local
model_class_1_repo
model_class_2_repo
...
all_stuff_related_to_SQLite_database_query
services
model_class_1_serv
model_class_2_serv
...
all_stuff_related_to_local_repos_query
ui
activities
activity_1
activity_1_viewmodel
activity_2
activity_2_viewmodel
...
activity_N
activity_N_viewmodel
component
custom_view_1
custom_view_2
...
helpers
view_helper_1
...
view_helper_N
assets
res
...

You can segregate your concerns like (app, core, network, service, repository) by making multiple modules. Just like 'app' is a module, you can create an independent module for each concern and you can use Koin for dependency injection between the modules.
For reference here is an example github repo:
https://github.com/Fahad-github/Bykea-CaseStudy-MusicApp

Related

Why do we need to separate DI wiring from Implementation in Android multi modular architecture?

Square Inc. has presented it's internal modular architecture at Droidcon SF'19:
https://www.droidcon.com/media-detail?video=380843878
However, I'm a bit confused with some bullets. Could you please help me?
Why do they actually need :wiring modules? I find it adding complexity:
you get extra gradle module for each new feature
you have to make a sort of global injection into your Fragments somewhere in :app, because Fragments defined in :impl modules cannot access it's DaggerComponent, which is defined in :impl-wiring modules. :impl doesn't depend on :impl-wiring, because the dependency is reversed.
you cannot have an Android Dynamic Feature modules, because they should know about it's DaggerComponent in order to inject it's Fragment. But there is no way to do such injection from :app module, which is base-module for Dynamic Features.
so why :wiring modules at all?
One can merge :impl and :impl-wiring, or :fake and :fake-wiring together to eliminate all the issues mentioned above. And also, in :demo-apps one could just have a dependency on either :impl or :fake``, and not on :impl-wiring(or:fake-wiring```).
The creation of this type of modules is to separate even more. With this you generate an abstraction of the type of component you use (koin, dagger) and how. If the project is large, it makes sense to do it.
Currently I generate the following flow of dependencies between modules:
WARNING: Check the directionalities well.
:feature-A:open <- :feature-A:impl -> :feature-A:impl-wiring
:feature-A:impl-wiring -> :feature-A:impl, :feature-A:open
:app -> :feature-A:open, :feature-A:impl-wiring
I'm still not sure if app should depend on open and impl-wiring, or which app should only depend on open and open from impl-wiring.
Eventually, I came up with the following solution:
each feature consists of the following gradle-modules:
api
impl and fake
data:api
data:impl1 ... data:implN and data:fake
data:wiring
ui
demo
So, here api, impl and fake as usual, but I've my data layers separated. I bought myself that I need multiple different implementation of data layers sometimes, for example - if I develop Stock-Charts App, I could rely on Finnhub Open API or MBOUM API or provide fake implementation.
Thus I have data:api, data:implX. Indeed, data:api defines FeatureRepository interface (one or many) and data:implX provides actual implementation for them. In order to bind interface and implementation, I use data:wiring, which defines Dagger modules and component(s). In addition, I keep the same package names within each data:implX module in order to "write-once" the data:wiring module. And to replace one implementation with another, I just change a single line in data:wiring/build.gradle which states a sort of:
implementation project(":data:implA")
to
implementation project(":data:implB")
Also, to break the confusion mentioned in my original question, I introduce ui module, which contains some Views of a particular feature. Fragments go in demo (a standalone app to test feature) or in ui, they refer to viewModel which have some bindings ctor-injected from Dagger component of a feature. But the UI and library are separated here. Fragment instantiates a dedicated Dagger component that uses component dependencies to refer to feature's library bindings, such as interactor or repository etc.
So, to wrap up - separation between UI and business logic implementation (a "library") for each feature makes it possible to solve the issue. Feature's api declares an entry point to it's functionality as a library, and it's global access via Dagger multibindings from :app. So it can be used further in any :demo, :ui and :dynamic-feature.

Need Clarification on the Usage of library dependencies inside Data module in Clean Code + MVVM (Android)

I'm very familiar with MVVM architectural pattern in android. To take it much further, I'm doing my next project by following clean code principles (SOLID). I have separated the entire app in three modules. 1) App (presentation + framework) 2) Data 3) Domain. My doubt is that whether I can keep library dependencies (i.e. Firebase) in Data module or not. Right now, I'm using interface to access app related stuffs like shared preferences, location fetchers, retrofit, etc.
I need to expect values like AuthResult from Data module. For that I need to add Firebase dependencies in the data module's Gradle file. I think that will violate the Higher level module should not depend on lower lever module rule.
Can anyone clarify this for me?
After going through several articles on MVVM + Clean Code, I came to a conclusion that I cannot be using any dependencies related to android framework inside either domain or data module. Otherwise it will be violating the Dependency Inversion principle of SOLID.
Dependency Inversion principle
Higher level module should not be dependent on Lower level modules, and both should be dependent on abstraction.
In English -> You cannot directly access framework related components like database, gps, retrofit, etcetera from data or domain layers. They should not care about those stuffs. They should be totally independent of android related components. We can use interface to satisfy the rule of abstraction.
Therefore, my data module and domain module contains only language dependencies. Whatever android-framework-related data I want, I acquire it by implementing interfaces.

Testing Firebase Database with an in-memory fake/db

Is there any in-memory implementation for Firebase database for testing Android client logic and integration? I have seen node.js fakes but could not find anything in java. I am not looking for a plain mock which is only good for basic unit-testing.
You must do refactoring your application, and implement an architectural approach. For example, such as MVP, MVVM, Clean, etc. The main thing is the layers. In this case, you can test these layers independently of each other using mock objects.
On the Internet you will find a lot of documentation on this topic,
eg Essential Guide For Designing Your Android App Architecture,
Why to choose MVVM over MVP — Android Architecture and many others.

Uncle Bob's clean architecture approach - what is recommended package structure?

I'd like to know if I'm using Clean Architecture the right way. I am trying to lay it like this diagram:
I've read that the package structure should be arranged by use case but I'm having difficulty following how that would be done.
Let's take a look at my package structure:
notice I don't know where to really put the activities in the UI folder, could you recommend ? does it matter?
In the data folder, I have my repositories I use for repository design pattern.
my retrofit network calls are on the same level as the UI folder. likewise for my dependency injection framework.
My concern comes after reading this publication I am now wondering if I did the package structure correctly?
One aspect Uncle Bob is emphasizing is that the clean architecture is screaming. That means that the top-level structure and names should express your business domain and not technical details and frameworks u use. On the second level we should separate the different circles.
In an e-commerce app things like cart, search and product catalog would shape the top-level structure. Use cases, controller and presenters would be on the second level.
I have blogged about this with more detailed example: Implementing Clean Architecture - Make it scream.
I would suggest you have a look to this repository. You can have a lot of feedback from the discussions in the issues section. I'll would read specially this discussion.
Now in orther to answer your question.
Does it matter? I would say no, it does not matter. Package structure is only a convinient way to structure your code to make it more readable and mantaiable. As long as you respect the Clean-Architecture principles it does not matter where you have your classes. Remember you can always do a refactor while you are progressing and your project is growing.
Where to put activities? If you already separate your UI package in components, you should stick to it and have an activities folder.
Recomendations: first I like to have one package or even a module for each layer (e.g. data, domain, presentation, infrastructure...) then within each package you can make your own decisions that you prefer. For example, I like to separate the presentation layer into features but the domain and data layer by components. The benefits of having one module for each layer is that if a new developer is going to contribute to the project you can enforce the clean architecture principles since they wont be able to reference a data class inside a domain usecase.

What are the benefits of a multi-project build in Android?

I'm reading the source code of Android : Clean Architecture, mostly to learn how to properly organize an application into layers, and for the MVP pattern, and also to match it with what I've been reading on MVP here.
However, as pretty as I find the structure, I don't really understand the benefit of order a single application into multiple sub-projects or modules. Considering they (data, presentation, domain) depend on one another, and eventually will be part of the same executable, it looks more like configuration hell.
dependencies {
...
compile project(':domain')
compile project(':data')
What are the benefits of compartmentalizing an Android application into multiple subprojects (modules), rather than keep them in one project but separate them merely by packages?
Actually this question is not Android-specific but more software architecture related as it applies to almost any software you develop (e.g. why does any app consists of several modules and not all in one package).
Splitting the code into modules would provide you at least the following benefits (these are the first 3 that comes to my mind):
Clear isolation between the modules. The whole goal of the MVP pattern is to make sure your business logic and presentations layer are not tightly coupled together. By defining these in different modules it makes this separation more clear and encourages you to stick to this pattern.
Code reuse - consider the case where you have one application that you'd to sell for several customers, but each of these customers would like to get a different look and feel. If you'll have all of your code in one monolithic project you'll have to either have many forks of your project, one for each customer or otherwise bloat the provided app code with the customization options. Now, if on the other hand you had separated your modules, then you could just prepare a different presentation layer for each customer and bundle it with the other common modules.
Splitting your project into sub-project allows more efficient build and testing as you can rebuild and test only the modules that changed rather than recompiling the whole project whenever there's a change in one of the files.
I hope that this makes sense to you.
The main benefit of using multi-module projects, instead of just packages, is that the code usage between modules goes in one direction only.
Any code inside the module can have a back-and-forth relationship:
A -> uses classes from -> B
and
B -> uses classes from -> A
If A and B are in separate modules, this only goes one-way:
A -> (uses classes from) -> B...
But B can't see anything in A.
This splits up your thinking into smaller, bite-sized chunks. If you need to understand how a class in module B works, you only need to look at the other classes in B.
But in the first scenario, you have to look at the all the classes in both A and B.
As an added bonus, if you do want to reuse any code, you can copy that module right over to the next project.
I usually put the bulk of my code in modules, with a thin app layer connecting them all together. I recommend using dependency inversion to make any connections between modules.
Another Android specific advantage of splitting into modules apart from faster build time is that the update size of your app will be less.

Categories

Resources