Use cases
Domain Layer
Summary
This lesson introduces the concept of Use Cases within the Domain layer of Clean Architecture. The instructor explains that a Use Case represents a specific, independent action a user or system can perform, such as fetching featured books. While acknowledging that Use Cases might seem redundant for small, simple projects, the lesson emphasizes their critical role in adhering to the Single Responsibility Principle (SRP) for larger, scalable applications. By isolating business logic—like checking user permissions or validating states before fetching data—into dedicated Use Case classes, developers keep Repositories focused strictly on data contracts and ensure the architecture remains highly maintainable.
Key Ideas
- The Domain layer contains the core business rules of the application, encompassing Entities, Repositories (abstract contracts), and Use Cases.
- A Use Case defines a single, specific action that an Actor (a user or external system) can execute within the application.
- Applying the Single Responsibility Principle (SRP), each Use Case should be encapsulated within its own dedicated class rather than bundling multiple methods into a single service class.
- Use Case classes act as intermediaries, handling prerequisite business rules (e.g., verifying permissions) before interacting with the Repository to fetch or mutate data.
- Skipping Use Cases and calling Repository methods directly from the UI or state management layer is common in simple apps but leads to bloated, unmaintainable code in enterprise-scale projects.
- The current Bookly project has two primary use cases for the home screen: fetchFeaturedBooks and fetchNewestBooks.
Code Snippets
abstract class HomeRepo {
Future<Either<Failure, List<BookEntity>>> fetchFeaturedBooks();
Future<Either<Failure, List<BookEntity>>> fetchNewestBooks();
}Architecture Insight
A use case is one verb the app can do: FetchFeaturedBooks, SignUserIn, AddBookToCart. The Single Responsibility framing matters because it puts a hard cap on what a single class can grow into — you'll never have a HomeService god-class because each verb is its own file.
CA's strict form makes use cases mandatory; pragmatic teams sometimes call repositories directly from the presentation layer when the use case would be a one-line passthrough. That's a knowing trade — fewer files, but the day you need to add caching or analytics around a call, you'll wish there was a use case to inject behavior into.
My Notes
This is a pure theory and architecture justification lesson. The instructor does a solid job explaining why we shouldn't just call HomeRepo.fetchFeaturedBooks() directly from a Bloc/Cubit. The core takeaway is the Single Responsibility Principle (SRP). By moving the invocation into a dedicated FetchFeaturedBooksUseCase class, we create a designated space for any business logic that must happen before or after the data fetch (like validating a user's subscription tier, or combining data from multiple repositories), without polluting the Repository interface or the Presentation layer.
- [Editor's note] The instructor mentions Use Cases are sometimes skipped in smaller apps. Skipping them often leads to an "anemic domain" anti-pattern or a "fat Bloc" where business logic bleeds into state management. Since the goal of this course is a Deep Dive, strictly implementing independent Use Case classes is the right path to build muscle memory for enterprise applications.