Skip to main content

Android Actual Clean Architecture (AACA)

by Adrian Tache, 08.05.2024

TODO add TLDRs

Downsides

About this section

In my experience trying to implement this architecture, I have been faced with a lot of resistance, mainly because many people just want to write code as quickly as possible, without considering its maintainability or covering it with tests. As such, I wanted to put together a section on the most common complaints I've heard about this architecture and why you might want to ignore them anyway.

So much code!

People often complain that AACA leads to so many more lines of code than just a regular MVVM, and this is true. Having said that, we must always remember that building this extra scaffolding around your code (and thinking in this different way) brings a lot of benefits which simply don't happen if just throwing code all around your app and praying it remains maintainable. As it is often in life, you can't have something for nothing.

Another counter-argument to this is that, while you do write more code initially, the fact that further refactorings and additions to the code don't require you to rewrite significant parts of your code base is a huge advantage. Just think of the impact of the API changing as part of a normal app, and then consider this architecture. Similarly, consider how changes to your UI will impact your core business logic, and how much of it needs to be rewritten if it is just hanging out in your UI. And of course, don't forget that every time you touch a piece of code, you have a chance to break it!

Finally, a lot of this architecture can be written using templates, and I have built some Live Templates inside my IDE to quickly build mappers (I also use an extension to add all the variables of the data class there for fast autocomplete), use cases, and tests for them. I also have templates for the file structure of a data layer, for example, as well as the UI layer. Once you do this, it's much easier to write a lot of the boilerplate, and I welcome LLMs of the future to do a lot of this heavy lifting for us.

People don’t want to learn it!

So many developers prefer the comfort of what they know, and it is doubly true for mobile development, in my experience. As such, many people will reject this architecture simply because it's unfamiliar and has a significant degree of complexity, until you understand it. Be fully prepared for people who are too lazy to read this documentation to try to poke holes in the architecture, or to skip certain components so that they can just get tasks done quicker. It is very important during those pull requests to highlight their mistakes and educate them on the correct way of doing things.

I've actually seen people make PRs that are thousands of lines to implement a simple change from an API, but after understanding how it should actually look, brought that down to only a few hundreds of lines, and even commented on how easy it is to work with this architecture, despite its initial learning curve. And that has been my experience as well, because I have to admit there have been times when I wanted to just give up on this, and yet time and time again I faced the kind of challenges that this architecture can solve and was glad I was using it.

Just like the previous point, it's really a matter of putting on your big boy pants and suffering through a bit of a learning curve and effort in order to reap the benefits of solid, testable, easy to change code, for many years in the future!

Why not just call the API from the view!

This is something I still see from time to time, and it terrifies me. Some people just want the minimum possible architecture, and the fastest momentary velocity, without even considering how much this will negatively impact their future work on that very same component. I think we've all been guilty of this at one time or another, and if my experience of it is something to go by, you always end up regretting it. To put it simply, the less time you take thinking about a component, and how it will grow, and how you can debug it, the more time you end up spending doing those things in the future, often exponentially so, with an added sprinkling of frustration on top.

You can certainly do something as absurd as just calling an API from a view, but then what coordinates your network calls? What happens if your user rotates their phone? Where do you do your data processing? What happens if you need to change the design? What if your features change, little by little? How do you test your code to prevent regressions or unexpected edge cases (well, that last one is a bit tricky no matter what you do!)?

The answers to all those questions are what a good architecture answers. MVVM, at its core, is pretty much just that, putting network calls inside an Android ViewModel and then just keeping things simple, with potentially a repository pattern as well to isolate the API a bit (which is always a good idea).

My point here is that, the more of these structural and planning questions you answer, the more you will end up reaping the kind of benefits that AACA provides, with the benefit of having my experience with it backing it up! And, unfortunately, you do have to suffer the learning curve of this architecture before you can truly understand why it's good, with the added benefit that there are more upsides to using it than even I have praised here, and I'd love to hear about them from your own examples!

Why so many objects for the same thing!

Building a lot of objects (and the inevitable mappers between them) might seem like a very boring and unnecessary undertaking, but every single mapping protects you. Mapping a DTO to a data layer object protects the repository from changes in the API definitions. Mapping a data layer object (if you built one) to a domain data object protects the domain from changes in the data layer. Mapping an entity to a UI objects protects the entity from being polluted with UI logic (and naming). Mapping a UI object to a View object (via a Presenter and maybe Providers and Formatters) protects the latter from changes in the UI object or in the Presenter's inner logic. Mapping a UI object into a navigation object (if the navigation is part of the UI) protects the UI object from

Why move so slowly while writing this simple screen!

Let’s just compromise for this feature, and make it more “elegant” and “generic”!

Why do I have two entities that are almost the same! TODO Talk about address objects qr address vs payment address