Clean Architecture on Android

Clean Architecture was introduced by Uncle Bob a few years ago and has grown popular in the Android world. There's nothing revolutionary new about it. But it borrows great ideas from other architectures and put them together in a compelling package.

Uncle Bob used this image to describe his architecture:
Clean Architecture diagram from Uncle Bob
Source 8thlight

The main point of the architecture is that outer layers knows about, and can interact with inner layers but never the other way around. We keep our abstract business logic in the center and the concrete implementations in the outer layers. Our business logic doesn't know, or care about which frameworks or databases we use.

If we're developing a bank application for example, the two innermost circles would be our business logic with account data classes, functionality for transferring money and so on. Since inner layers never knows about outer layers we can move our business logic core between different apps. The same center could be used in both our web app and our mobile app.

And even if we're ever only having one app, testing will be far easier when we have a self-contained business logic module.

On Android

If we were to redesign Uncle Bob's diagram to better suit Android, it might look something like this:
Clean Architecture diagram for Android

Besides the business logic in the center, Android apps tend to have a presentation layer like MVP before the UI and we usually use some data, from databases or the network for example.

It's common to divide those layers into 3-4 modules, something like this:
Module division in Android

Domain module

This module contains our business logic. It will contain Entities which is our models. Often just POJOs, data classes or interfaces. But it can also be objects with some logic or contain some validation logic.

Use Cases, or Interactors as they are also sometimes called, are where the main business logic resides. Each use case should be limited to one feature according to Single Responsibility Principle. A rule of thumb is that you should be able to describe your use case with a simple sentence like "Fetch open issues on GitHub" for FetchOpenIssuesUseCase. The opposite would be the fat controller which we'd call like githubClient.fetchOpenIssues().

Finally, we have Repositories, or Abstractions, which is interfaces to the outside world. Repositories are named after the Repository Pattern and are many times just CRUD operations for our models. A TodoRepository could look something like this for example.

interface TodoRepository {
    List<Todo> getAllTodos();
    Todo getTodoById(int id);
    void saveTodo(Todo todo);
    void deleteTodo(int id);
}

The repositories should typically be implementation neutral as in there shouldn't be a TodoDatabaseRepository for example. We decide how and where to store things in the data module.

Presentation module

This module is also commonly called UI- or App module and contains things related to UI and Android. As mentioned earlier we typically have some view architecture like MVP, MVVM, MVI or similar, and we have our activities and fragment here.

It's also common to keep the dependency injection setup in this module.

Data module

This module will contain implementations for the Repository interfaces we created in the Domain module. It will typically contain implementations for storing or fetching data to and from databases, and for doing network requests.

Other modules

Many teams also have a Device module for device specific things like sensor data, notifications, and similar things. It depends on your app, sometimes it's better to put those things in the Data and/or Presentation modules instead.

It could also be useful to keep a App module separate from the Presentation module. Where we can keep configurations, and set up our dependencies. That way Presentation doesn't have to know about the Data module and we can easily keep different build variants for debug/release and similar.

It's beneficial to use real modules in our Android project to separate the modules. That will help to prevent us from accidentally call on things in wrong layers for example. But we can also place everything in one module and separate it with packages instead.

Example of Clean Architecture

In the next part, we'll look create a small example of how to implement Clean Architecture on Android. You can find that here.