Fetch featured books use case
Domain Layer
Summary
This lesson demonstrates the practical implementation of a UseCase in Clean Architecture by creating the FetchFeaturedBooksUseCase within the domain layer. The instructor explains that a UseCase represents a specific action a user can take, structured as an independent class rather than a simple method to ensure single responsibility and scalability. By abstracting the call to the Repository inside a dedicated UseCase, developers can cleanly inject future business logic, such as permission checks or validation, without cluttering the data layer or violating architectural principles.
Key Ideas
- UseCases represent specific, individual actions that a user can trigger within a feature.
- UseCases should be implemented as full classes rather than standalone methods to support dependency injection and maintain clean architecture boundaries.
- The FetchFeaturedBooksUseCase class depends on the HomeRepo interface to fetch data, effectively hiding the implementation details of the data source.
- Using a dedicated class for a single action strictly adheres to the Single Responsibility Principle (SRP) from the SOLID principles.
- Abstracting calls into a UseCase allows for easy injection of pre-execution logic, such as permission checks, without modifying the repository interface or the presentation layer.
- Separating logic into UseCases makes the codebase more maintainable, easier to test, and simpler to refactor as the application grows.
Code Snippets
import 'package:bookly/core/errors/failure.dart';
import 'package:bookly/features/home/domain/entities/book_entity.dart';
import 'package:bookly/features/home/domain/repos/home_repo.dart';
import 'package:dartz/dartz.dart';
class FetchFeaturedBooksUseCase {
final HomeRepo homeRepo;
FetchFeaturedBooksUseCase(this.homeRepo);
Future<Either<Failure, List<BookEntity>>> fetchFeaturedBooks() {
// check permission
return homeRepo.fetchFeaturedBooks();
}
}My Notes
The instructor raises an excellent theoretical point here: why wrap a simple repository call inside a dedicated UseCase class if it's just passing the data through? The answer boils down to the Single Responsibility Principle (SRP) and future-proofing. If you skip the UseCase and call the repository directly from the presentation layer (e.g., from a Bloc or Cubit), you risk putting domain business logic—like permission checks or data formatting—inside your UI state management. [Editor's note] While the instructor named the method fetchFeaturedBooks(), standard Clean Architecture in Flutter often utilizes Dart's call() method. This allows you to invoke the UseCase instance like a function (e.g., fetchFeaturedBooksUseCase()), which makes the code slightly cleaner. Furthermore, a foundational UseCase abstract class or interface (often taking a generic Type and Params) is omitted in this video but is highly recommended for standardizing the input and output contracts of all UseCases in the app.