Even though we are living in the Agile world with a bunch of available Time and Energy management techniques that are easy to implement in your life, there are still a few things in software development that may increase your productivity and improve the general quality of your code.
The thing I want to describe in this article is application architecture in Clean Architecture way. By implementing the Clean in your project youâll have decoupled, testable parts for data storing, processing and presenting. Clean Application is extremely maintainable, because of interchangeable implementations it would be easy for you to change every aspect of your app: from UI and simple data processing to DB and API frameworks.
On the first sight you may consider Clean architecture as a bunch of abstract ideas without âreal codeâ power, but in this article, Iâll try to show you how these may be implemented on the Android side.
At first letâs have a quick intro to the project structure: I will be using Views and Presenters to display the UI part of the application and Kotlin+RXJava2+Dagger2 to implement Clean Architecture principles in the work with network\db\cache\etc .
Kotlin
Kotlin features extremely simplify android development not just by allowing you to use smaller constructions of language but maintaining semantically right functions in your app. This will allow you to think less about implementation details and more about the whole app structure. The functional part of Kotlin will reduce side effects of your code and make it easier to test and understand. Take a look at the article which explains why itâs worth to use Kotlin.
RXJava
RX operators that RXJava provides easy to use stuff for working with data streams and threads. But in my opinion, the main purpose of RxJava is to have universal structures for data flow in an application.Seriously, you should check it out if youâre still not familiar with RxJava.
Dagger2
A fast dependency injector for Android and Java.Dagger2 is a great library that allows you to @Inject everything you need where you need it and handle the lifecycle of created objects. Dagger2 is used to avoid detail-complicated boilerplate code of connecting architecture elements one to another.
Letâs get to the architecture
We will follow the dependency rule on this well-known picture to have an application with interchangeable parts.
Just a few principles(S O L I D) will allow us to decouple data fetching and handling processes of our application, build interchangeable views and keep their interfaces clean and simple, with keeping solid abstraction level from frameworks and data layer implementations.
As I mentioned before, UI part of the application architecture will be built on Views and Presenters, you may find great guides to it here and here.Data fetching and processing layers will be presented as UseCases and Repositories.
Sample
Starting from now we will examine a feature of changing the userâs email and what actions are performed on each layer.If youâre not familiar with Clean Architecture approach, you should check Fernando Cejasâ article.
Data layer
Data layer is represented by Repository interfaces. Each repository works with a single, well-defined aspect of application (users, messages, events inbox, etc)
The main purpose of this repository is to handle users workflow: API calls for creating\getting\patching user entity.
Dagger module code:
Notice please that returning value of @Provides annotated function is an interface, not the implementation. That approach will allow us to make huge changes to implementation leaving âclientâ code without changes.
Domain layer
Domain layerâs element is UseCase. UseCaseâs role is to combine data layer elements to perform a combination of data operations.
Another important thing is different entities for each layer of application. As dependency inversion principle works in the other way works additional fields decreasing.The purpose of different entities for each layer is to reduce the amount of information inner layer may depend on. E.g., you donât need api version at your entity in domain and presentation layers of your application, you only need this property in data layers.
Presentation layer
Presentation layer consists of 2 elements: a passive View and a Presenter with presentation logic. The view is completely passive, so it just calls presenter functions when any UI action is performed, and Presenter is deciding what actions must be performed on one or another UI event.
View:
Presenter :
Calls stack
That was a quick dive into layers. Now letâs go through calls stack when user presses confirmButton.
Firstly, button click listener in view is called.
confirmButton.onClick { presenter.onConfirmButtonClicked()}
Then view calls the presenterâs method. In presenter we validate user input with ValidationUtils.isValidEmail(view.getEmailInput()) and show user validation error message if input is not valid. We setup observable to perform its emissions and notifications on a specified thread with observeOn() operator. If we donât need to perform operations on the certain thread weâre letting UseCase or Repository to setup thread that observable will work on.
changeUserEmailUseCase.changeUserEmail(view.getEmailInput()) .observeOn(AndroidSchedulers.mainThread())
Finally, we subscribe to item emissions, specifying âhappyâ and âerrorâ cases.
...
.subscribe({ //Email is successfully changed },{ //Error while changing email })
UseCase itself will use implementation of repository to perform email changing operation.
appUserRepository.changeUserEmail(email).map { DomainMapper.fromDataUserToDomain(it) }
It also maps elements to the understandable by UI layer type, by reducing the amount of outer layer dependencies or adding fields that might be needed to display content.
The repository will perform email changing operation with DB, Firebase or API, cache results in local memory and distribute new info to subscribers through RxJava subjects.
Conclusion
You still may spend your time decoupling feature parts from your code to create some sort of code reusability in your project, or you can use this way of organizing things in Android, which allows you to create a testable and maintainable solution for your clients and customers. And build the app that will be easy to change, because its parts are feature-based and guaranteed, and you wouldnât rewrite half of your app for minor changes, hating your client by the way.
Links
Kotlin language docs & tutorialsRxJava and RxAndroidDagger2 integration samples, tutorials & docsClean architectureâââAndroid way by Fernando CejasUncle Bobâs architectureGit repo for a working sample
If you find this helpful, click the đ below so others can enjoy it too. This article was originally published on UPTech Team blog. Follow us for more articles on how to build great products