Open-source project
EranBoudjnah/CleanArchitectureForAndroid avatar
EranBoudjnah/CleanArchitectureForAndroid

CleanArchitectureForAndroid: a Kotlin sample that argues about layers

Clean Architecture for Android - a sample project

842 stars99 forksKotlinMIT

At a glance

What is it?
CleanArchitectureForAndroid is an MIT licensed Kotlin sample project that implements Clean Architecture on Android with separate UI, presentation, domain, data and data source layers, Hilt injection, Compose and XML, and architecture rules enforced in CI. It suits Android developers learning the pattern or looking for a reference to argue with, and it is not a library you add to a product.
Who is it for?
This repository suits an Android developer who wants a worked reference for Clean Architecture rather than a description of it, since the layers, the module split, the dependency choices and the reasoning behind each of them are all visible in code, and the konsist, detekt and ktlint checks mean the structure is enforced rather than merely suggested.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A sample project, not a library, and it says so

The repository description calls it Clean Architecture for Android, a sample project, and the README says it is a loose implementation of Clean Architecture as presented in the author's book Clean Architecture for Android.

The word loose matters. This is not a framework, not a Gradle plugin and not something you add to your app. There is no published artifact, no API surface to learn and no version compatibility matrix. What you have is a native Android project written in Kotlin that demonstrates the key principles from the book and how they apply to a real life project.

That framing puts the audience in a specific place. It is for a developer who has read about layers, dependency inversion and use cases and wants to see a working set of those ideas, or for a team trying to agree on an architecture and needing something concrete to point at during the argument. The README even links to the original Clean Architecture article on the Clean Coder blog, so the project is positioned as an interpretation of a published idea rather than a new one.

The author states the goal plainly: to keep the project up to date and use it to demonstrate the strengths of the architecture, which he names as scalability, testability and flexibility when it comes to choosing third party solutions.

The project is MIT licensed, with the LICENSE file in the repository root, and there are no GitHub releases. The last push to the repository was on 2026-10-22, so it is being worked on, but you take a commit rather than a version.

Five layers and a directory per feature

The feature list starts with feature separation and layer separation, and then names the layers.

The five layers, in order, are UI, Presentation, Domain, Data and Data Source, and that ordering is the point. The data source layer is the outermost, where the outside world enters, and the domain layer sits in the middle holding the business rules, with the UI and presentation layers on the other side of it. Nothing inside the domain layer knows what a database or a REST API is, and the presentation layer knows about the domain layer and not about data.

The repository layout shows the same idea at module level. Alongside the app module there are analytics, architecture, automation, coroutine, coroutine-test, datasource, home, time and widget modules, plus buildSrc for the build logic, a detekt.yml for the static analysis configuration, and an opensourcenotices directory.

Those module names are not arbitrary. analytics, home, time and widget look like features, and each one is a separate Gradle module. That is what feature separation means in practice: the code for a feature lives in one place rather than being spread across a screen package, a view model package and a repository package that all happen to share a name. The navigation, animations, unit tests and end-to-end tests listed in the features section are the things that come along with it.

The architecture directory is the module that pays for the pattern. It is where the layer contracts live, the abstractions the domain layer depends on, and it is the reason a feature module can be replaced without touching the others.

The author calls the complexity deliberate

The Choices section opens with a quotation about the complexity introduced being an overkill, and the author agrees with it, with a condition.

If this was a final project, to which no new functionality would ever be added, then Clean Architecture would have been overly complicated for it. The reality is that mobile projects seldom are final: user feedback, marketing requirements and new technologies all lead to continuous changes to almost every project, and what may now seem like too much complexity will reward you when the time for change comes.

Then there is the aside, which is the more interesting admission. In some ways the project has been intentionally over-complicated by introducing different technologies, with the goal of showing how the architecture still works even in a real life scenario where a project has grown over time to include more than one technological solution.

That is a frank framing, and it has consequences for how you use the repository. If you fork it as a starting point for a product, you are inheriting layers, modules and abstractions that the author put there to make a point. A feature that will never change does not need a data source layer, and a project with one remote API does not need a mapper class per object.

So the honest way to read this repository is as a demonstration with a specific thesis. The thesis is that the structure survives change, including changes of technology. Whether the complexity pays for itself in your product is a decision you have to make against your own roadmap, not against the sample.

Mapper classes beat extension functions for testability

One of the more useful decisions in the project is the smallest one, and it comes down to testing.

When mapping between models there are options, and the primary decision is between mapper classes and mapping extension functions. Extension functions are more concise, but using them for mapping limits the choices of testing frameworks, and the README is specific that Mockito cannot stub static functions.

The obvious workaround is to inject the extension functions, but the author rejects that, because it removes the benefit of conciseness almost entirely and makes navigation to the implementation harder. So the choice is the slightly more verbose concrete mapper classes.

This is a good example of an architecture sample earning its keep, because the argument is about a real constraint rather than about style. A mapper class is an ordinary object, so it can be constructed in a test and its output asserted directly. A mapping extension function is a static call, so mocking it means either a mocking framework that can handle statics or a design change that undoes the point of using extensions.

The mocking section makes the same point from the other direction. Both Mockito-Kotlin and MockK are used in the project, to demonstrate how each would look, with the author's own preference being Mockito-Kotlin because the code is easier to read and follow, while noting that judging by repository stars the industry seems to lean towards MockK.

Fakes are also mentioned and dismissed. The author was asked about using them, explored them, and found them overly verbose and too expensive to maintain. That is a defensible position, and it is one more example of the project showing the trade-off rather than the ideal.

LiveData and the Android ViewModel are left out on purpose

The most contentious choice in the project is the decision to skip Google's Architecture Components.

The stated reason is leakage. The greatest issue with the Architecture Components is that they leak Android details into the Presentation layer, which prevents that layer from being truly UI agnostic.

The second reason is responsibility. The Architecture Components give too much responsibility to the ViewModel, making it persist state it does not own, which leads to potential data synchronization bugs.

So, while still following MVVM, the project relies on Kotlin Flows rather than LiveData, and implements pure ViewModels rather than Google's.

This is a stronger position than a style preference, and it connects directly to the layer boundaries the project is trying to demonstrate. If the presentation layer cannot see Android types, then it can be exercised in a plain JVM unit test without an emulator or Robolectric, which is what makes the testability claim credible rather than aspirational.

The state ownership point is the subtler half. A ViewModel that persists state it does not own is a ViewModel whose lifetime is tied to something else, and the README's concern is that the boundaries get blurred until synchronisation bugs appear. Flows, with an explicit owner for each piece of state, make the ownership visible in the code.

If you are adopting this project, expect to have this conversation with whoever on your team prefers the Architecture Components, because the sample takes a clear position rather than hedging.

Hilt over Koin, and Compose plus XML in the same architecture

Two more choices are worth reading in full, because they are the ones a team will have to live with.

The first is dependency injection. The most popular choices in the Android world are Hilt, which is built on top of Dagger, and Koin. Hilt was chosen for two reasons: compile time safety, meaning the confidence that all dependencies are provided before the app starts, and simplicity, since from experience setting up and using Hilt is considerably easier than Koin, and because Hilt introduces fewer breaking changes over time.

Compile time safety is the argument that carries the most weight in a layered architecture. If the graph is verified at build time, a missing binding is a build failure rather than a crash on a screen, and the layering rules can be enforced by the compiler rather than by convention.

The second choice is the user interface mechanism. The author asks why not both, says he still has a lot of concerns around Jetpack Compose, and explains that it was important to show the presented architecture works well regardless of the UI mechanism chosen. The invitation is explicit: replace the UI layer from Compose to XML or vice versa without updating the Presentation layer.

That is the acceptance test for the whole design. If swapping the UI toolkit requires touching the presentation layer, the layer boundary was never really there. The project hosts both, the repository topics list both jetpack-compose and gradle-kotlin-dsl, and coroutines with Flow are demonstrated alongside them.

konsist, detekt and ktlint keep the architecture from decaying

The most underrated part of the project is the tooling, because an architecture that is only enforced by convention is an architecture that erodes.

Three separate checks are listed. Code quality checks use ktlint, and code quality checks also use detekt, which is the static analysis tool configured by the detekt.yml file in the repository root. Then there are architecture consistency checks using konsist, a tool whose documentation the README links for a getting started page.

konsist is the interesting one for a Clean Architecture sample, because it is not a formatter or a linter but a rule engine for the code itself. It lets you write assertions about your own architecture, such as which layer a class may depend on, and it fails the build when a rule is broken. In a project whose entire thesis is that layers should not leak, having the leak check run in CI is the difference between demonstrating the principle and merely describing it.

The CI setup matches. GitHub Actions runs the unit tests, the instrumentation tests and the linting, so the three checks and the two test suites all run on every change.

The test story is complete as well. The features list calls out unit tests and end-to-end tests separately, and the repository has a coroutine-test module, and there is a history directory alongside the others, which is a reference implementation of a feature used to show the pattern end to end rather than in fragments.

Contributions are welcome, with issues reported and pull requests raised from a fork, and the project is MIT licensed with the licence file at the root. What it is not is a production template. Treat it as a well argued reference implementation with a CI that keeps it honest.

Editorial conclusion

This repository suits an Android developer who wants a worked reference for Clean Architecture rather than a description of it, since the layers, the module split, the dependency choices and the reasoning behind each of them are all visible in code, and the konsist, detekt and ktlint checks mean the structure is enforced rather than merely suggested. It does not suit a team that wants a reusable library or a starting template to fork wholesale, because the author describes the project as intentionally over-complicated for a real application. Before you copy any of it, read the Choices section and decide whether you agree with the author on Hilt over Koin, on mapper classes over extension functions, and on Kotlin Flows over LiveData, because those are the decisions that will travel with the code, and note that the last push to the repository was on 2026-10-22.

Frequently asked questions

What is CleanArchitectureForAndroid?

It is a sample native Android project written in Kotlin that loosely implements Clean Architecture as presented in the author's book, demonstrating the key principles and how they apply to a real life project. It is a reference implementation rather than a library.

Which layers does the CleanArchitectureForAndroid sample separate?

The README lists five: UI, Presentation, Domain, Data and Data Source. The repository is also split into feature modules such as analytics, home, time and widget, alongside app, architecture, automation, coroutine, coroutine-test and datasource modules.

Why does the sample use Kotlin Flows instead of LiveData?

The author says Google's Architecture Components leak Android details into the Presentation layer and give the ViewModel too much responsibility, making it persist state it does not own. The project therefore relies on Kotlin Flows and implements pure ViewModels while still following MVVM.

How are architecture rules enforced in the CleanArchitectureForAndroid project?

The project uses konsist for architecture consistency checks, detekt for static analysis and ktlint for code quality, with GitHub Actions running the unit tests, the instrumentation tests and the linting on every change.

Does the sample support both Jetpack Compose and XML?

Yes. The README states that the project demonstrates Jetpack Compose and invites you to replace the UI layer from Compose to XML or vice versa without updating the Presentation layer, which is the test of whether the layer boundary is real.

Official sources

  1. EranBoudjnah/CleanArchitectureForAndroid on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/eranboudjnah-cleanarchitectureforandroid.svg)](https://hysenlabs.com/projects/eranboudjnah-cleanarchitectureforandroid)

Was this useful?