My app is a cookbook containing recipes that we frequently make in my house.
This project is developed in order to create a scalable architecture, with good design principles that could be maintained by a large number of collaborators/teams. Additionally, newer libraries or approaches can be used for experimentation.
- 100% kotlin
- coroutines
- StateFlow (instead of LiveData)
- Jetpack ViewModel
- Jetpack Compose
- Koin
- Retrofit
- Moshi
- Timber
- Gradle Groovy
- Github actions
SOLID and clean architecture are the pillars.
In a feature scope (a screen for this project), the architecture relies on 5 distinct layers: View, Presentation, Domain, Data, Data source. These layers follows a Clean architecture dependency that can be represented by the below picture:
For "view architecture" I'm using MVVM (Jetpack ViewModel), kotlin StateFlow to provide state, and Compose.
Since I'm using 100% kotlin, any asynchronous operation or background work uses kotlin coroutines and Flow when a reactive approach is necessary. For any SDK integration, I would wrap them using suspendCoroutine/channelFlow to give them a suspend function abstraction over the API calls.
There are some solutions for navigation that have huge impact by modularization. Today, I have a MainNavigator interface that receives an object that relates to a given screen. The injected list of Navigation resolvers are provided using Koin "multibinding".
The application has dark and light mode that can be changed at runtime. All definitions/styles are inside design-system module.
Light | Dark |
---|---|
Koin
The whole application is composed of several modules that are ruled by a hierarchy dependency structure. All modules are classified into a specific module layer and this layer must respect the dependency direction, this is, a given module can only depend on modules of the same layer or below.
The picture shows the current modules and how they are structured.
- App - Glue all modules and it has project configurations like build variants, API keys.
- Feature - Product features are developed at this level of modules. For this project I have modules:screen 1:1 but it may vary a lot.
- Core - Here I have modules that are not tied to a specific feature scope but the entire app like Base Classes when needed (I am pretty confident that I keep this layer really small).
- Infrastructure - Modules that compose the foundation of the project. Configuration, navigation, analytics, design-system...
- Utility - Helpers and extensions classes goes here. But only the ones that are not related to business of the project and it can be reused by other projects.
Strict Mode is a developer tool which detects things you might be doing by accident and brings them to your attention so you can fix them.
//TODO
//TODO
Currently I'm using Sentry for crash report and Timber as log abstraction layer. Monitoring must be the first thing to initialize!
The module analytics
is an abstraction for event report. We currently rely on Amplitude platform to send and analyse user/application behaviour.
I tried to use gradle kotlin DSL but I've encountered errors when splitting build files for modules reuse.
To synchronize dependency versions and avoid string duplications, I'm using a common file that declares dependency versions as constants referencing them inside build.gradle files. [ref:link]
In general, features modules have a lot of common dependency. Said that, I'm reusing a base build.gradle files whenever is possible.
Applying obfuscation and shrink code is a must for the release build.
I'm using Github actions for CI. Currently, it's still pretty basic...
//TODO
- Cesar Morigaki
The MIT License (MIT)
Copyright (c) 2020 Cesar Augusto Morigaki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.