Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when scaffolding a project, refactoring into layers, creating view models/repositories, configuring dependency injection, or implementing unidirectional data flow (MVVM).
.claude/skills/evanca-flutter-app-architecture/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-01 | ✗→✓ | ▲ Improved | -2% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -15% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 46% | 0% |
This skill defines how to structure Flutter applications using layered architecture, proper data flow, and MVVM patterns for maintainability and testability.
Use this skill when:
Separate every app into a UI Layer and a Data Layer. Add a Logic (Domain) Layer only for complex apps.
┌──────────────────────────────────────────────────────────────┐
│ UI Layer │ Views + ViewModels │
├──────────────────────────────────────────────────────────────┤
│ Logic Layer │ Use Cases / Interactors (optional) │
├──────────────────────────────────────────────────────────────┤
│ Data Layer │ Repositories + Services │
└──────────────────────────────────────────────────────────────┘Rules:
dartclass BookingViewModel extends ChangeNotifier { final BookingRepository _repo; BookingViewModel(this._repo); List<Booking> _bookings = []; List<Booking> get bookings => List.unmodifiable(_bookings); bool _isLoading = false; bool get isLoading => _isLoading; Future<void> loadBookings() async { _isLoading = true; notifyListeners(); _bookings = await _repo.getBookings(); _isLoading = false; notifyListeners(); } Future<void> cancelBooking(String id) async { await _repo.cancelBooking(id); _bookings = await _repo.getBookings(); notifyListeners(); } }
dartclass BookingRepository { final BookingApiService _apiService; final BookingLocalService _localService; BookingRepository(this._apiService, this._localService); Future<List<Booking>> getBookings() async { try { final remote = await _apiService.fetchBookings(); await _localService.cacheBookings(remote); return remote; } catch (_) { return _localService.getCachedBookings(); } } Future<void> cancelBooking(String id) async { await _apiService.cancelBooking(id); await _localService.removeCachedBooking(id); } }
dartclass BookingApiService { final http.Client _client; BookingApiService(this._client); Future<List<Booking>> fetchBookings() async { final response = await _client.get(Uri.parse('/api/bookings')); if (response.statusCode != 200) { throw HttpException('Failed to load bookings'); } final data = jsonDecode(response.body) as List; return data.map((json) => Booking.fromJson(json)).toList(); } }
Supply dependencies via constructors. Define abstract interfaces so implementations can be swapped for testing.
dart// Abstract interface for the repository abstract class BookingRepository { Future<List<Booking>> getBookings(); Future<void> cancelBooking(String id); } // Concrete implementation class BookingRepositoryImpl implements BookingRepository { final BookingApiService _api; BookingRepositoryImpl(this._api); @override Future<List<Booking>> getBookings() => _api.fetchBookings(); @override Future<void> cancelBooking(String id) => _api.cancelBooking(id); }
Introduce use cases only when:
dartclass GetUpcomingBookingsUseCase { final BookingRepository _bookingRepo; final UserRepository _userRepo; GetUpcomingBookingsUseCase(this._bookingRepo, this._userRepo); Future<List<Booking>> call() async { final user = await _userRepo.getCurrentUser(); final bookings = await _bookingRepo.getBookings(); return bookings .where((b) => b.userId == user.id && b.date.isAfter(DateTime.now())) .toList(); } }
shared_preferences) for configuration and preferences.drift, sqflite) for complex relational data.StatelessWidget when possible; avoid unnecessary StatefulWidgets.final for fields and top-level variables. Prefer const constructors when the class supports it.Command0<void> over dynamic signatures)._todoTableName over _kTableTodo).Other measured skills in the registry, with their headline benchmark lift.