Clean Architecture is not Domain-Data-Presentation.

Marko Novakovic
6 min readAug 3, 2021

I am writing this as Android and Flutter developer and this is what I’ve observed happening over past few years regarding architecture.

“Clean Architecture”. You see it everywhere. Seems like, to me, that everybody has written an article on this topic. And what those articles talk about? Separating your app into three layers: domain, data and presentation. Everybody showcases same structure, same convention, same implementation with UseCases, Repositories, ViewModels (if you are reading Android related article), they throw in couple of SOLID words etc.

Don’t get me wrong. Layering (separating you app into layers) is great thing. Layering is one of the first patterns software developers were using to separate the code and make it more CLEAN.

What I am saying is that if you are just getting your feet wet, and if you are more advanced, with code architecture and design you would miss a point and write code that is NOT clean.

Going forward I will call this domain-data-presentation layered “Clean Architecture” -> Quasi Clean Architecture.

Also, am writing this post as an Android Developer for Android Developers (that doesn’t mean that you can’t follow it if you are not one) so word module will be used in two contexts: Android module and module as cohesive code structure.

I will talk about problem with this approach, what is the solution and at the end I will talk about history of this, how we ended like this.

Why are we layering our apps?

We were told that if we layer our apps into domain-data-presentation layers/modules that we will have: easily maintainable code, break monolith into more maintainable peaces, faster build times etc.

Is this actually true? Let’s see.
My explanation will cover the three points I’ve mentioned above, so I’ll be killing 3 birds with one stone.

Let’s say you have travel guide application.
You create your domain module that holds model classes, usecases and repository interfaces. Then you create data module that implements those repository interfaces and then you have your presentation layer where you use and combine all of that into flow that you need and expose it to the UI. Everyone is happy. You have “Clean Architecture”. Wrong.

What happens when you want to add some functionality? Let’s say your travel destinations search functionality was just filtering destination you’ve already fetched and now you want to fetch search result’s from the server. That involves:

  1. (domain) Adding method to the repository interface.
  2. (data) Implementing that method in the repository implementation class.
  3. (data/network) Adding API call to your network client.
  4. (presentation) Changing your ViewModel and UI to reflect changes.

Do you see what have we just did? We changed every layer of the app! Changes as simple as adding argument to the repository method involves changes listed above and changing every single module.

  1. Is that easier to maintain? No, it’s pretty much the same.
  2. Did we break the monolith into smaller peaces? Meh, we just created distributed monolith.
  3. Do we have faster build times? No, we changed every module and every module need to be built again. To be fair in some situations we do have faster build times, you changed just UI for example but….

We effectively did nothing. That brings us to the biggest flaw in this layering approach.

Domain-Data-Presentation layering is for small apps or features that live inside their own modules.

Here I will add what Martin Fowler wrote in his blog post on this topic:

Although presentation-domain-data separation is a common approach, it should only be applied at a relatively small granularity. As an application grows, each layer can get sufficiently complex on its own that you need to modularize further. When this happens it’s usually not best to use presentation-domain-data as the higher level of modules. Often frameworks encourage you to have something like view-model-data as the top level namespaces; that’s OK for smaller systems, but once any of these layers gets too big you should split your top level into domain oriented modules which are internally layered.

How would implementation like this look like? Let’s say that in our travel guide app we have this functionalities:

  1. Destination search.
  2. Airport search.
  3. Trip planning.
  4. Purchasing plain tickets.

Instead of having three layers and package inside those layers that correspond to these four features we should have module per feature listed above and every module separated into domain-data-presentation. We completely inverted the structure.

Structure on the left becomes structure on the right:

Keep in mind that this is just an example and in app like this you would have network and persistence modules and that you would maybe modularize further but let’s keep this simple.

As Uncle Bob said, and am paraphrasing here, we want our modules to be independently deployable even tho we will almost aways build and ship it as complete app. This creates clean separation between modules and will ensure that changes in one will not affect others at all. On the contrary of our domain-data-presentation layered example from above.

Having all this said, what is our separation criteria? Do we have module per screen? No. Screens are not good enough criteria because they are prone to change: rearranged, redesigned etc. Functionality/feature should be your criteria for a module. Every feature, unique functionality, should have it’s own module. Just be careful to not overdo this, modules should be small enough and not too small.

What is Clean Architecture actually?

Here is the original post by Uncle Bob on clean architecture: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html.

In this post you can see a list of what qualities Clean system has as well as explanation of the Dependency Rule. What is this Dependency Rule? From the original article:

The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an inner circle. That includes, functions, classes. variables, or any other named software entity.

Do we see any qualities of the Clean system reflected in Quasi Clean Architecture? Kind of but it hurts more than it helps.
What about dependency rule? Yes, but we can it better.

Ok then, how we ended up like this?

A little bit of history

If am not mistaken this Quasi Clean Architecture, and am not trying to insult the author by saying this, sprung up from this post from 2014 -> https://fernandocejas.com/blog/engineering/2014-09-03-architecting-android-the-clean-way/.

It either promoted it a lot but I think that this was unique at the time. It was 2014 people were still writing God Activities so this was massive leap forward.
We still follow this approach even tho author himself said, in second or third iteration some year after the original post, that creating and separating code into domain-data-presentation layers was a mistake.

Conclusion

I will leave you with this quote from Yigit Boyar:

There is no best architecture. There is only architecture that’s best for you application and your needs.

That would be it. I would LOVE to hear what you think about this, in the comments. Take care!

--

--