Clean Architecture diagrams look great in conference slides and feel heavy in a mobile repo. After applying it (and over-applying it) across several production apps, here's my honest accounting of what pays for itself.
Keep: the dependency rule
The single most valuable idea: source code dependencies point inward. UI knows about use cases; use cases know about entities; nothing knows about the UI.
// domain/usecases/confirm-booking.ts — no React, no HTTP, no storage
export async function confirmBooking(
repo: BookingRepository,
slot: Slot,
): Promise<Booking> {
if (slot.isExpired()) throw new SlotExpiredError(slot);
return repo.confirm(slot);
}This function runs in a unit test, a CLI, or either mobile framework unchanged. That portability is the whole point.
Keep: repository interfaces
Mobile apps live and die by data edge cases: offline, stale cache, mid-sync conflicts. An interface between "what the app needs" and "where bytes come from" is where you handle all of that once.
Skip: one use-case class per method
GetUserUseCase, UpdateUserUseCase, DeleteUserUseCase, GetUserByIdUseCase...That's Java ceremony, not architecture. Plain functions grouped in a module carry the same guarantees with a tenth of the files.
Skip: entities that mirror your API
If your User entity is field-for-field identical to the API response, the mapping layer is pure overhead. Add a domain model when domain behavior appears — not before.
Rule of thumb: every layer must earn its keep by absorbing a real change you have actually experienced — a swapped backend, a redesigned UI, an offline mode. Layers added "just in case" are where velocity goes to die.
The mobile-sized version
Three folders, one rule:
src/
├── domain/ # entities + use-case functions, framework-free
├── data/ # repositories, API clients, local storage
└── features/ # UI + state, imports domain, never data directlyThat's enough architecture for the first hundred thousand users. Add rings when reality — not a book — demands them.