Clean Architecture & Use Cases Interview Questions
ARCHITECTURE › Patterns
Walk me through how you'd decide whether a ViewModel should call a Repository directly or go through a UseCase.
What a strong answer covers: If the ViewModel needs exactly one repository call with no extra logic, mapping, or combination with other data sources, calling the repository directly is fine, and a UseCase would just be a pass-through wrapper adding a file and indirection with no real payoff. A UseCase earns its place when there's actual logic to encapsulate, combining two repositories, applying a business rule, or when the same operation is genuinely reused across multiple ViewModels, since duplicating that logic per ViewModel is the real problem a UseCase solves. A weak answer treats 'always use a UseCase' or 'never use one' as a fixed rule instead of a case-by-case judgment call.
Give a concrete example of the dependency rule paying off, a change you could make in the data layer without touching domain or UI, because of that boundary.
What a strong answer covers: A strong example is swapping a repository's underlying data source, like moving from a REST endpoint to GraphQL, or adding a local Room cache in front of a network call, as long as the repository still implements the same domain-defined interface and returns the same domain model; nothing in the domain layer or ViewModel needs to change because the domain only depends on the interface, not the implementation, via dependency inversion. The nuance a weak answer misses is naming what makes this possible: the domain module has no compile-time dependency on the data module at all, dependency injection wires the concrete implementation in at runtime, so this is enforced by module boundaries, not just convention.
Where have you seen Clean Architecture over-applied on a real Android team, and how would you push back on it in review without coming across as someone who doesn't care about architecture?
What a strong answer covers: Common over-application: a UseCase per repository method that does nothing but call through with zero extra logic, separate domain models that are field-for-field identical to the DTO or entity with a mapper adding no value, or splitting a genuinely simple two-screen feature into presentation, domain, and data Gradle modules when one module would compile and test just as well. The constructive pushback argues from each layer's stated purpose, asks what the UseCase, mapping, or module boundary actually lets you do that you couldn't do without it, names the real cost, extra files, extra indirection when debugging, slower onboarding, and proposes collapsing it, while being explicit that the objection is to paying the cost where the benefits, testability, swappable implementations, reuse, aren't actually being exercised.