Clean Architecture on Android: Over Engineering or Just Common Sense?

Yoel Gluschnaider
4 min readNov 13, 2016

One of the main questions I asked myself in the process of thinking about how to create a robust architecture for large scale Android applications was am I over engineering this? I know I have a tendency to over complicate things and to over engineer. How can I avoid doing that but at the same time not creating implementation that doesn’t scale.

One of the approaches I recently adopted was of the Clean Architecture. I spoke in the last few posts about this so I will not repeat myself. The thing I came to realise lately is that MVP/MVVM are not an architecture, these are design patterns. Assuming that your View implementation is an Activity/Fragment/Custom View and you put all your UI logic in the Presenter/ViewModel, what goes into this black box called the Model?

I just watched the great presentation by Florina Muntenescu from upday called A Journey Through MV Wonderland. Though I am not sure I agree with all the points Florina makes about the different patterns (you can see my perspective in this post) what I mostly don’t agree with from her talk is treating these patterns as an architecture. An Android app might contain caching strategies, some persistent storage, location services, accelerometer etc. All these things fall behind this huge box called the Model. There is a layer missing and I feel like without that layer you are solving some of the issues in your code, but still leave a lot of room for mess in this mythical Model.

Having said that, one of the key principles of good design is simplicity. So if I look at the Clean Architecture approach, behind the Presenter/ViewModel you will have Use Cases/Interactors. They will interact with the Gateways (all the peripheral elements like DB, network etc) and contain the business logic itself.

The thing is, after implementing a few of these interactors, I noticed that they do relatively little and sometimes act just as a proxy to a gateway that does the actual work. For example, in a simple Master/Details application, the list of items in the master screen just needs to get the list of items. It can get that directly from the Items Repository instead of executing the GetItems use case which does exactly that.

I had several discussions about this and here are some takeaways from those:

In a simple app that will not live long (an app for a conference for example) you might want to consider not having this extra layer. To me it looks like over engineering. You should probably use some presentation layer pattern like MVP or MVVM, but beyond that it seems excessive to me.

In an app that needs to live for a long time and needs to scale, this approach just doesn’t cut it. Even though that at the moment your use case class seems trivial, the fact that it is there allows you to extend and change the logic with ease and minimum risk.

I will give an example. Let’s say you have a data source that returns a list of popular restaurants in your area. That data source might want your location in order to show what’s in your area. So your presenter needs to interact with the restaurants repository as well as the location provider of your application. That’s fine, not too bad right? You show that list in two different places with two different presenters, so you have it twice already. Not ideal, but adding a whole class just to do that seems over complicated. But then comes another requirement to remove the ones you already rated (meaning you visited them already) from this list since it makes less sense to show them to you. Or better yet, put the ones you rated high at the top of the list because you will probably want to go back and the ones you rated low should be removed.

This can become really messy really fast. You might do the first change in the two presenters. You might forget to do this is both. You might even start creating these utility classes that do that, but I think you can see where this is going. Not before long you will have a big mess.

The assumption behind the Agile methodologies is that requirements always change and we should craft our code in a way it can react to change quickly. Having this extra layer of abstraction will allow this flexibility.

Some might argue that at first you should create something without a use case and then as soon as you need to do something more complex (like sending the location) you should abstract that out. While that is true, sadly the reality that I have experienced is far from this. Developers are either lazy or inexperienced to know when something needs to be abstracted out. Having these rigid guidelines like: “you should always have a use case, and should never access gateways directly” is a good thing IMHO. It helps creating alignment within the team and avoids some of the pitfalls caused by not having the right abstractions in place.

This is not by any means a silver bullet. Using MVP doesn’t prevent developers from putting UI logic in the View and using Clean Architecture does not prevent Logic from leaking to the presentation layer. Not to mention that even with the right separation of concerns, the interfaces might be not very well crafted. Having these abstractions in place just helps you steer this big boat which is a large scale application in a better way.

I am very keen to get some feedback on this post as this is completely subjective and I am yet to see if this is even the correct approach.

--

--