Claude-skill-registry Clean Architecture Patterns
Domain, Data, and Presentation layer separation with dependency inversion and use case patterns
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/clean-architecture-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-clean-architecture-patterns && rm -rf "$T"
manifest:
skills/data/clean-architecture-patterns/SKILL.mdsource content
Clean Architecture Patterns
Layer Structure
┌─────────────────────────────────────┐ │ PRESENTATION LAYER │ │ (Controllers, Widgets, Bindings) │ ├─────────────────────────────────────┤ │ DOMAIN LAYER │ │ (Entities, Use Cases, Interfaces) │ ├─────────────────────────────────────┤ │ DATA LAYER │ │ (Models, Repositories, Sources) │ └─────────────────────────────────────┘
Dependency Rule: Outer layers depend on inner layers, NEVER reverse.
Domain Layer (Pure Business Logic)
Entities
// lib/domain/entities/user.dart import 'package:equatable/equatable.dart'; class User extends Equatable { final String id; final String name; final String email; const User({ required this.id, required this.name, required this.email, }); @override List<Object?> get props => [id, name, email]; }
Repository Interfaces
// lib/domain/repositories/user_repository.dart import 'package:dartz/dartz.dart'; import '../../core/errors/failures.dart'; import '../entities/user.dart'; abstract class UserRepository { Future<Either<Failure, User>> getUser(String id); Future<Either<Failure, List<User>>> getAllUsers(); Future<Either<Failure, User>> createUser(User user); }
Use Cases
// lib/domain/usecases/get_user.dart import 'package:dartz/dartz.dart'; import '../../core/errors/failures.dart'; import '../entities/user.dart'; import '../repositories/user_repository.dart'; class GetUser { final UserRepository repository; GetUser(this.repository); Future<Either<Failure, User>> call(String id) { return repository.getUser(id); } }
Data Layer (Implementation Details)
Models
// lib/data/models/user_model.dart import '../../domain/entities/user.dart'; class UserModel extends User { const UserModel({ required super.id, required super.name, required super.email, }); factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['id'], name: json['name'], email: json['email'], ); } Map<String, dynamic> toJson() { return { 'id': id, 'name': name, 'email': email, }; } User toEntity() { return User(id: id, name: name, email: email); } }
Repository Implementation
// lib/data/repositories/user_repository_impl.dart import 'package:dartz/dartz.dart'; import '../../core/errors/failures.dart'; import '../../core/errors/exceptions.dart'; import '../../domain/entities/user.dart'; import '../../domain/repositories/user_repository.dart'; import '../providers/user_provider.dart'; class UserRepositoryImpl implements UserRepository { final UserProvider provider; UserRepositoryImpl(this.provider); @override Future<Either<Failure, User>> getUser(String id) async { try { final model = await provider.fetchUser(id); return Right(model.toEntity()); } on ServerException catch (e) { return Left(ServerFailure(e.message)); } } }
Presentation Layer (UI & State Management)
Controllers
// lib/presentation/controllers/user_controller.dart import 'package:get/get.dart'; import '../../domain/usecases/get_user.dart'; class UserController extends GetxController { final GetUser getUserUseCase; UserController({required this.getUserUseCase}); final _user = Rx<User?>(null); User? get user => _user.value; Future<void> loadUser(String id) async { final result = await getUserUseCase(id); result.fold( (failure) => Get.snackbar('Error', failure.message), (user) => _user.value = user, ); } }
Dependency Inversion
// ❌ BAD: High-level module depends on low-level module class UserController { final UserApiClient apiClient; // Concrete implementation void loadUser() { apiClient.fetchUser(); // Direct dependency on implementation } } // ✅ GOOD: Both depend on abstraction class UserController { final UserRepository repository; // Abstract interface void loadUser() { repository.getUser(); // Depends on abstraction } }