At one point I had no idea that software architecture and software design, are separate but complementary topics. Therefor, I find it necessary to start this discussion with a short description about the two.
Software architecture is about the intent, about what the system does, about what we are building. While software design is about how we are building.
Software architecture represents a higher level of abstraction than software design.
Architecture is the bigger picture, the choice of frameworks, programming paradigms, software engineering standards, high-level principles, intent, etc.
Design is the smaller picture, how to express, to implement, to plan and structure the code, in order to define as clearly as possible the intent of the architecture.
You can find the code for this topic here: AndroidCleanArchitectureWithMVP
Systems based on clean architecture have the following characteristics: separation of concerns, multilayered, independent of frameworks, independent of user interfaces, independent of databases, testable by layer, with a dependency rule that says that code dependencies can only point inwards, from lower levels like the presentation layer, to higher levels like the data layer.
The solution is an extension based on the boilerpart code for asynchronous MVP design for Android, without 3rd party libraries.
From now on, I shall only talk about clean architecture, in the context of the example application:
The example application is based on the following 3-tier clean architecture: the presentation layer, the domain layer, and the data layer.
The presentation layer is implemented as an MVP design, the domain layer contains plain Java objects, and the data layer is just a dummy singleton implementation for a database.
You can have as many layers as needed, and there is not rule that says that clean architecture should be implemented with only three layers.
The presentation layer represents the application, and is an Android phone & table module. The domain layer and data layer are Java libraries, and used as gradle dependencies. The presentation layer depends of the domain layer and the domain layer depends on the data layer. There is also an extra module, named models, that contains the models of the application. For the sake of simplicity, these models are used in all the layers of the application. In a more complex application usually each layer has its own data modeling.
Because gradle manages dependencies between layers, the models module is only defined as a dependency in the data layer, which is used as a dependency in the domain layer, which in turn is used as a dependency in the presentation layer. In this way, the models dependency becomes available in all the layers. It is called transitivity, and it is how gradle handles dependencies.
To better understand the details of the 3-tier clean architecture with MVP, let’s see another overview, but from a different perspective.
This is the same as the previous overview, but with more details about the presentation layer, which on its own contains three layers: the view, the presenter and the model.
Following the dependency rule, the architecture is layered as follows: the presentation layer (the view, the presenter, the model), the domain layer and the data layer.
The model in the presenter layer is also known as “uses cases” or “interactor”. These use cases, or model, or interactor, or whatever you want to call it, represent application specific business rules. These use cases orchestrate the flow of data between the presentation layer and the domain layer, and they are specific to the application and not the domain. You can think of them, as what the application does, what the presentation layer does. Remember that the presentation layer can be anything from an android application, a web application, a standalone application, etc.
The idea of clean architecture is to have separation of concerns. In our example the presentation layer contains everything that is android related, the domain layer contains plain java objects that represent the business entities, and the data layer contains everything that is database related.
In a clean architecture, is should be possible to replace each layer with a different implementation of the same interface, and this should make no difference on the other layers.
Having separation of concerns in an application might seem like a no-brainier. Yet it is surprisingly difficult to achieve. The best way to start is to understand the purpose of the clean architecture and just practice.
The code of this example application can be used as boilerpart code, upon which to build your own application.
See also a short video discussion about this solution here.