I'm creating a sample app which I'm following the clean architecture, my app structure now is like this :
:app
:firebase
:library_base (which contains all the baseActivity, baseFragment, etc.. I know I could create a base_ui, base_data, module, but let's first solve this question that I'm having right now)
:networking (which contains retrofit stuff)
feature1
feature2
....
So now, my question is, now I do not need a core module, but in case one of my featureX, needs a dependency from featureY, what should I do in this case? I'm used to have a core on my app that contains stuff like LoginSettings which contains data from the user logged and things like that, and now if I'd have to do this I could not because featureX can not depend on app, so that's why I'm thinking about adding a core module and insert all of the needs from featureX there so they can use it. (Yes, I said "all of the needs", I did not mean to create a god module, but just to start the app).
Is it necessary to create a core module? I'm not using dynamic feature tho, and also I'm seeing that on each build.gradle files I'm duplicating a lot of dependencies...
From now in the app I have everything with api should I put that in the core?
One approach would be create modules "with UI" (call them features) and "without UI" (call them libraries).
Rule is "features" can not depend on each other directly, they can only depend on "libraries". While "libraries" can depend on each other.
Now LoginSettings, SessionConfigs kind of things can be a "library" where multiple "features" (UI) can depend on. Not all features has to depend on that "library".
Related
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
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.
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.
My scenario
I have to implement a "modular" android app. There is a core module from which I should be able to invoke other modules. Each module provides a different feature to the user. Imagine I am making a city guide, then one module may contain a map with POIs, another one an event calendar and a third one pre-defined city guides. The modules contain views to be loaded in activities of the core module (like dashboards where each module puts its item/picture). They also contain activities which should be invoked (like when a user taps an item on the dashboard). As far as I know, I will need a database and/or preferences only in the core module. The "plug-in modules" use classes (utilities) of the core module, e.g. when connecting to the backend.
My solution on iOS
For iOS, I achieved this with targets in XCode. I have one project and depending on the customer's needs I compile only the relevant modules. It would be even better if the user can install modules whenever he wants, without the need of reinstalling the "core" application.
My problems on Android
In SO, I already found various solutions like library project, switching from Eclipse to Android Studio + something, using package manager and broadcast receiver... But I still don't understand... How is the modularity of an android application to be achieved?
Here are some concrete problems that I see:
Libraries: My modules all use classes of the core module, so they are not independent. I achieve the modularity by using interfaces/inheritance depending on the flexibility that I need.
Broadcast receiver: This seems to be everything else than recommended. See, for example, here or here.
What I need is, at least, to be able to use the same code for delivering app with features A and B to one customer and with B and C to another one. And, until now, I have no idea how to achieve it.
PS: I don't want to use scripting, I am not familiar with that.
I don't see this "modular" app as anything different from one app, with several packages, each containing discrete functionality, that is adapted to some list of settings or external parameter (either provided by the user or you).
My approach would be to have a "main" package. That package would contain the shared functionality you mention above and serve as the hub for your application. I would then create separate sub-packages for the different "add on" functionality. This allows you to still use the code in your main package with a simple import statement. From your description these additional functions should probably be implemented as a Fragment. A Fragment is almost a stand alone application with the exception that it is "hosted" by an Activity. Depending on how these add on functions are used (I cannot tell if they relate to the UI, just background processing etc) you could easily have 3 of 4 different fragments and choose to load only 1 or 3 or 2 of them at runtime.
To control which parts of the code are used I would just set up a simple switching class (it could even be part of the first activity launched, I cant tell from your description above). Here I would check for some setting indicating which parts of the app will be "active." This could be easily defined using SharedPreferences to store a specific configuration, e.g. use A and B, prior to delivering the final project. You would then just initialize the fragments you need and display them either (1) individually in a Fragment layout element or FrameLayout; (2) collectively in some other view structure like a ViewPager.
I follows your links on the BroadcastReceiver and I am still not sure why they are "everything else than recommended." Used correctly a BroadcastReceiver is very useful. I tend to use a LocalBroadcastManager along with a BroadcastReceiver to notify other sections of the app when some AsyncTask, e.g. downloading a lot of data, is complete. These parts of the app can then access a local database or process the information downloaded on their own time. I wouldn't use a BroadcastReceiver to modulate parts of the app if that is what you're looking for. I would instead just use a SharedPreference file to set the configuration at runtime.
If you need modules like facebook sdk or something like that better use library project. If you use Idea or Android Studio there is such thing like Module. If I need some modeles in one app I prefer just put in different packages like com.appname.model, com.appname.ui and so on. Broadcast Receiver isn't about modules. As I know there isn't analog of ios target.
Some time ago I created and Android app. Then I needed to create very similar app (functionality-wise) with some cosmetic, branding and small-scale functionality changes. I refactored the original app as a library project, created an app that used this library project and recreated the original functionality. Then I created a new app that used that same library project and also implemented the small-scale changes required for the second app. This worked perfectly fine. Now if a change is needed, it's very easy to implemented it in multiple apps: I just change the library project and recompile all the apps.
I also had the original application available for iOS - and need to make the second app available for iOS. I could, naturally, copy the project, make the changes and create another apps. However this would mean double work if I needed to change something in the core functionality. I'd like to be able to refactor the iOS project/app similarly to the Android one, but not sure how to go about it - or if such functionality is even available. Any suggestions are much appreciated.
You can create a Single project with differents targets.
Then, you will have target A, and B for example and CoreFile files that are common for all targets.
Let's suppose you have HomeViewController with some slightly differences.
You can create a single interface HomeViewController.h and two implementation AHomeViewController and BHomeViewController, both extending BaseViewController.
Then open AHomeViewController, and on FileInspector at 'Target Membership' mark only target A. On BHomeViewController you do the same. Image 1, illustrate what you have to do (names are differents from the example because it's a real example from one of my projects).
If for some reason you have need to know what's targets are you using you can define it using Preprocessor Macros on Target -> Build Settings. As illustrate by Image 2.
Then you can use #ifdef APP_CB to check the current target.
As was mentioned you can really regulate target membership[About] of every file which you add. But in my opinion is better to create a separate framework(library) and add it as dependency
[Swift consumer -> Swift dynamic framework]