Clean Architecture on Android

Architecture

The art of planning, designing and structuring buildings concepts

-Joe Birch

AppDevCon

Last Thursday and Friday I went to AppDevCon in Amsterdam, and among others I saw two very interesting talks about mobile app architecture. First, “Getting Clean, Keeping Lean” by Joe Birch (Buffer) and second, “Hidden mysteries behind big mobile codebases”, by Fernando Cejas (Soundcloud). Both of them discussed the architecture applied to their apps, and they got me thinking about app architecture.. again. In this post I will share some of my findings with you.

Clean architecture

Both Joe and Fernando actually refer to something called clean architecture. Clean architecture proposes four layers, to decouple application components, improve code quality and simplify maintenance. Strictly decoupling the layers is probably the most important thing to keep in mind when using clean architecture. Let’s take a closer look at those layers.

Frameworks and drivers

The first, outermost layer is “Frameworks and Drivers” containing everything platform specific. In case of Android this contains things like custom views, fragments, activities and the native storage methods like SharedPreferences and Sqlite.

Presenters

The second layer (or module) contains presenters aka. “interface adapters”. This layer build on the underlying layer and adapts it to the UI (frameworks and drivers) layer. The UI delegates almost everything to this layer to decouple it from the native framework as much as possible.

Business rules

The third layer contains “business rules”, or “use-cases”. It has for example methods to retrieve data, for a specific use-case, from the underlying layer. Albeit from the server or from local cache. Where it comes from does not matter. This layer only knows about the layer it is wrapping, the domain logic or entity layer.

Entity layer

The “entity (or domain logic) layer” contains the actual methods to fetch the data from wherever it needs to come from and provides it’s own representation of this data. It also does not know anything about native networking, communication or shared preferences. These are implementation details hidden behind interfaces.

Visually these layers look like an union, each layer wrapping the other. These layers look like this:

Clean Architecture*

As you can see each layer is wrapped by the next. You can also see the dependencies are pointing inwards. So presenters is only aware of use cases, not entities, and UI is only aware of presenters, not use cases or entities.

Note that if a layer does not work for you, because for some reason it does not make sense, don’t hesitate to skip it. Or in case you need an additional layer because that makes total sense four your app, just add it.

Testability

Both speakers, Joe and Fernando, explained how this architecture led to better testability of their applications. Which brings me to the next point: “Because only the Frameworks and Drivers layer, is coupled to the Android framework, all other code can (and should) be plain java modules.” Joe even takes it a step further and argues that by first having the inner three layers in place, you can work on stability even before you start working on the UI.

Plain Java Modules

I am talking about modules in the application in this case. In Android’s case this means a separate Gradle module for each layer. Because this allows you to develop them as normal java code, with normal unit tests. It also forces dependency inversion on you because you can’t access components upwards. And because it is plain java, you do not require a phone or an emulator to run your tests. Which means, faster build times and a faster development cycle.

One thing to keep in mind is that the models from one layer should not be reused in another layer. This may seem like overhead, but simple delegates can minimize the impact of this. Joe proposes to use mapper object that convert the model object to your own type as soon as they cross the layer’s boundaries. You could choose to utilize Android’s annotations for this as well. There are annotations to mark classes and packages as part of a certain group and you can then restrict access from other groups. For example @RestrictTo(RestrictTo.Scope.GROUP_ID)

Separation of the layers*

Mixing with databinding

I like Android’s databinding framework a lot, so I have been thinking about the best way to mix clean architecture with Android’s databinding framework. It is actually very simple. You need just two components for each of your bindings. The first component is a data model and the second component is a behavioral delegate. The behavioral delegate receives all ui-events and forwards them to the presenter. And in turn the presenter can act as needed. The data model is simply the object containing your data. You could also use two-way binding to make it easier to send updates events straight into the presenter-layer.

This would result in activities and fragments that almost don’t contain any code, which obviously leads to a better separation of concerns. And because the next layer contains most of the complexity, and because it is a plain java module, it is a lot easier to test.

LightCycle

Which brings me to a library Fernando showed. At Soundcloud they developed a library called LightCycle, which allows you define objects within your activities and fragments, that automatically get the required lifecycle events forwarded to them. This allows you to create separate controllers for your activities and fragments. Because these controllers are no longer hard-wired to the activity or fragment, you can instantiate them in your tests and easily simulate the activity’s or fragment’s behavior.

Mixing with Reactive frameworks

When you combine clean architecture with a reactive framework (which seem to be used by almost everybody presenting at the conference) this architecture really starts to shine. It makes it very easy to automatically refresh the ui whenever an update happens. The architectural diagram of this look as follows:

Observable stream of data between each of the Layers*

As you can see the data is backed by observable repositories, this can for example be an RX-observable or an Agera repository. So registering a listener in the top (ui) layer, will cause the observable to be observed and load its data. It would be very simple to map one type into the other using Agera. Let’s take a look at the following code sample, we could place at a layer boundary:

// Source layer, for example injected using DI
Repository<Result<SourceType>> mSourceRepo;
// My layer, mapped from source value 
// could be injected as a singleton
MutableRepository<Result<LayerType>> mDataRepo;
// On update of layer below
void doUpdate() {
    mSourceRepo.get()
       .ifSucceededAttemptMap(DataMapper::map)
       .ifSucceededSendTo(mDataRepo);
}

As you can see we can observe the source repository. In the doUpdate method, which handles the update, we can map the value to the correct type for this layer. Within this layer the local data repository is exposed and can be observed by the next layer. Remember that observing repositories should be driven by the lifecycle of the components to prevent leaks. Usually this would mean subscribing from the onStart callback en unsubscribing from the onStop callback.

Package structure

Before concluding I would like to take a little side-step. One of the things that struck me most in Joe Birch’s talk is that he argues that by seeing the package structure of an application you should be able to see what the application does. He argues code organization starts with a clear and understandable package structure. Having a package named activities, fragments, views and adapters tells nothing about the application (besides that is probably is an Android application), it only tells you where to find what kind of classes and not what they actually do. So, imagine you are new, and you need to change something in the instant messaging component of the app, wouldn’t it make sense if that was somewhere in a package named messaging or im?

Conclusion

Obviously every architecture or way of working has its downsides. Joe also points out the following disadvantages to clean architecture:

  • Adds initial overhead
  • Takes time to get used to
  • Can feel overkill for some tasks
  • Difficult to make decisions

However, the advantages easily outweigh the disadvantages:

  • High test coverage
  • Easy to navigate package structure
  • Easier to maintain
  • Allows us to move faster
  • Focussed classes and test classes
  • Separation of concerns
  • Define, test, stabilize before UI
  • Futureproof implementations

I hope you agree that these advantages by far outweigh the disadvantages. To summarize, using this architecture should allows us to develop faster, test better and apply solid principles by design. Using the correct tools allows you to move even faster because you need less boiler plate.

I must say I am really looking forward to experiencing this architecture. Perhaps in the next project I’ll be working on there will be an opportunity to try this.

* Images copied come from https://github.com/android10/Android-CleanArchitecture

Packages are like classes

Packages with classes grouped by type, are like utility classes. This may not always be what you want.

This post is not specific to Android, or Java for that matter. Some other languages may offer similar features.

Introduction

Packages are something we usually don’t give much thought. For that reason developers sometimes just use them to group classes together, for example classes that perform similar actions or share a common ancestor. I think packages can offer a lot more than just grouping similar classes and should be thought of as an OOP (Object Oriented Programming) concept. That’s why I say: “Packages are like classes”. Now let’s investigate what other possibilities of organizing code are available with packages, and how that relates to classes.

Packages in app-architecture

Like I said before, I consider packages an OOP concept, just like inheritance and delegates. Using packages as such will help you design better libraries and apps, because using these features will help you to hide the implementation details, clients don’t need to know about. (Clients being any code using your code, even in the same app)

Access modifiers

Before diving deeper into this, let’s discuss how we organize code and how we use access modifiers to determine what methods should be visible.

The first building block is code. Your application consists of code. This code is grouped into methods. These methods are grouped into classes and the classes, in turn, are grouped into packages. And finally we use access modifiers to control the visibility of these methods. By doing so we can make them internal to the class or to their subclasses. Or private within the package. Package private is like protected, except that the methods and fields are not available to subclasses (in other packages). The full access table looks like this:

ModifierClassPackageSubclassWorld
publicYYYY
protectedYYYN
no modifierYYNN
privateYNNN

credits: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

Now think about this for a moment, think how you usually use these various modifiers to hide certain methods from external clients or subclasses. Think about how private methods contain very specific implementation details you don’t want a client to use.

Think again!

Now imagine, that you can also use these modifiers on your classes, as members of your package. Now think about grouping classes in a package “because they are all fragments or activities” or “because they are all helpers”. Think about them as if they were methods of a class, which ones would you like your clients to use, and which ones would you like to hide.

When you group your classes by type, you lose package private, and thereby the option to minimize the visibility of these classes. You can’t hide your implementation details because the class needs to be accessible from other packages as well, for example to create an instance.

Grouping by type

So what packaging by type really brings is the same thing static utility classes bring. They allow you to group a set of classes together. You can see this for example in Java’s collections framework. Most of the implementations are intentionally grouped in the java.util package. This is intentional because they are all supposed to be used by any client that needs them.

Conclusion

So spreading your implementation details over multiple packages leaks your implementation details to the client. If you are creating a library this is even worse. These implementation details are now part of your public API. You need to maintain it, and make sure it is keeps working for all consumers of your library. People will also start using it in ways you never intended and are going to start reporting bugs on those use-cases.

So next time you create a class, specifically for a single feature, think whether it is something that should be public or package private. And remember, you can always refactor your code if you are not satisfied with the result.