I’ll go from the most abstract center to the edges.

Entities

Entities, aka domain objects or business objects, are the core of the app. They represent the main functionality of the app, and you should be able to tell what the app is about just by looking at them. They contain business logic, but it’s constrained to them only — validation and stuff like that. They don’t interact with the gritty outside-world details, and they also don’t handle persistence. If you had a news app, the entities would be Category, Article, and Commercial, for example.

Use cases

Use cases, aka interactors, aka business services, are an extension of the entities, an extension of the business logic, that is. They contain the logic that isn’t constrained only to one entity but handle more of them. An indicator of a good use case is that you can describe what it does in a simple sentence using common language — for example, “Transfer money from one account to another.” You can even use such nomenclature to name the class, e.g., TransferMoneyUseCase.

Repositories

Repositories serve to persist the entities. It’s as simple as that. They are defined as interfaces and serve as output ports for the use cases that want to perform CRUD operations on entities. Additionally, they can expose some more complex operations related to persistence such as filtering, aggregating, and so on. Concrete persistence strategies, e.g., database or the Internet, are implemented in the outer layers. You could name the interface AccountRepository, for instance.

Presenters

Presenters do what you would expect them to do if you are familiar with the MVP pattern. They handle user interactions, invoke appropriate business logic, and send the data to the UI for rendering. There is usually some mapping between various types of models here. Some would use controllers here, which is fine. The presenter we use is officially called the supervising controller. We usually define one or two presenters per screen, depending on the screen orientation, and our presenters’ lifecycles are tied to that of a view. One piece of advice: try to name your methods on a presenter to be technology agnostic. Pretend that you don’t know what technology the view is implemented in. So, if you have methods named onSubmitOrderButtonClicked and onUserListItemSelected in the view, the corresponding presenter methods that handle those events could be named submitOrder and selectUser.

Device

This component has already been teased before in the notifications (again) example. It contains the implementations of the gritty Android stuff such as sensors, alarms, notifications, players, all kinds of *Managers, and so on. It is a two-part component. The first part is the interfaces defined in the inner circles that business logic uses as the output port for communication with the outer world. The second part, and that’s drawn in the diagram, are implementations of those interfaces. So, you can define, for example, interfaces named Gyroscope, Alarm, Notifications, and Player. Notice that the names are abstract and technology agnostic. Business logic doesn’t care how the notification will be shown, how the player will play the sound, or where the gyroscope data comes from. You can make an implementation that writes the notifications to the terminal, write the sound data to the log, or gather the gyroscope data from the predefined file. Such implementations are useful for debugging or creating a deterministic environment for you to program in. But you will, of course, have to make implementations such as AndroidAlarm, NativePlayer, etc. In most cases, those implementations will just be wrappers around Android’s manager classes.

DB & API

No philosophy here. Put the implementations of repositories in this component. All the under-the-hood persistence stuff should be here: DAOs, ORM stuff, Retrofit (or something else) stuff, JSON parsing, etc. You can also implement a caching strategy here or simply use in-memory persistence until you are done with the rest of the app. We had an interesting discussion in the team recently. The question was this: Should the repository expose methods such as fetchUsersOffline (fetchUsersFromCache) and fetchUsersOnline (fetchUsersFromInternet)? In other words, should business logic know where the data comes from? Having read everything from this post, the answer is simple: no. But there is a catch. If the decision about the data source is part of the business logic — if the user can choose it, for example, or if you have an app with explicit offline mode — then you CAN add such a distinction. But I wouldn’t define two methods for every fetch. I would maybe expose methods such as enterOfflineMode and exitOfflineMode on the repository. Or if it applies to all the repositories, we could define an OfflineMode interface with enter and exit methods and use it on the business logic side, leaving repositories to query it for the mode and decide it internally.

UI

Even less philosophy here. Put everything related to the Android UI here. Activities, fragments, views, adapters, etc. Done.

Modules

The following diagram shows how have we divided all these components into Android Studio modules. You might find another division more appropriate.