Flutter & Dart Code Reviewer
Повысьте качество вашего Flutter-приложения с помощью навыка ревью кода Flutter & Dart. Автоматизируйте аудит управления состоянием, производительности и чистой архитектуры.
Этот навык предоставляет Claude строгую систему для рецензирования кодовых баз Flutter и Dart, сфокусированную на архитектуре, производительности и идиоматических стандартах кодирования. Он включает специализированный контрольный список, охватывающий структуру проекта, типичные ошибки Dart, декомпозицию виджетов и логику управления состоянием в основных библиотеках, таких как BLoC, Riverpod и Provider. Применяя эти стандарты, разработчики могут выявлять утечки памяти, предотвращать ненужные перестроения виджетов и гарантировать, что их приложения следуют принципам чистой архитектуры, независимо от используемого технического стека.
Ключевые возможности
Примеры использования
| name | flutter-dart-code-review |
|---|---|
| description | Library-agnostic Flutter/Dart code review checklist covering widget best practices, state management patterns (BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart idioms, performance, accessibility, security, and clean architecture. |
| origin | ECC |
Comprehensive, library-agnostic checklist for reviewing Flutter/Dart applications. These principles apply regardless of which state management solution, routing library, or DI framework is used.
- Project follows consistent folder structure (feature-first or layer-first)
- Proper separation of concerns: UI, business logic, data layers
- No business logic in widgets; widgets are purely presentational
-
pubspec.yamlis clean — no unused dependencies, versions pinned appropriately -
analysis_options.yamlincludes a strict lint set with strict analyzer settings enabled - No
print()statements in production code — usedart:developerlog()or a logging package - Generated files (
.g.dart,.freezed.dart,.gr.dart) are up-to-date or in.gitignore - Platform-specific code isolated behind abstractions
- Implicit dynamic: Missing type annotations leading to
dynamic— enablestrict-casts,strict-inference,strict-raw-types - Null safety misuse: Excessive
!(bang operator) instead of proper null checks or Dart 3 pattern matching (if (value case var v?)) - Type promotion failures: Using
this.fieldwhere local variable promotion would work - Catching too broadly:
catch (e)withoutonclause; always specify exception types - Catching
Error:Errorsubtypes indicate bugs and should not be caught - Unused
async: Functions markedasyncthat neverawait— unnecessary overhead -
lateoveruse:lateused where nullable or constructor initialization would be safer; defers errors to runtime - String concatenation in loops: Use
StringBufferinstead of+for iterative string building - Mutable state in
constcontexts: Fields inconstconstructor classes should not be mutable - Ignoring
Futurereturn values: Useawaitor explicitly callunawaited()to signal intent -
varwherefinalworks: Preferfinalfor locals andconstfor compile-time constants - Relative imports: Use
package:imports for consistency - Mutable collections exposed: Public APIs should return unmodifiable views, not raw
List/Map - Missing Dart 3 pattern matching: Prefer switch expressions and
if-caseover verboseischecks and manual casting - Throwaway classes for multiple returns: Use Dart 3 records
(String, int)instead of single-use DTOs -
print()in production code: Usedart:developerlog()or the project's logging package;print()has no log levels and cannot be filtered
- No single widget with a
build()method exceeding ~80-100 lines - Widgets split by encapsulation AND by how they change (rebuild boundaries)
- Private
_build*()helper methods that return widgets are extracted to separate widget classes (enables element reuse, const propagation, and framework optimizations) - Stateless widgets preferred over Stateful where no mutable local state is needed
- Extracted widgets are in separate files when reusable
-
constconstructors used wherever possible — prevents unnecessary rebuilds -
constliterals for collections that don't change (const [],const {}) - Constructor is declared
constwhen all fields are final
-
ValueKeyused in lists/grids to preserve state across reorders -
GlobalKeyused sparingly — only when accessing state across the tree is truly needed -
UniqueKeyavoided inbuild()— it forces rebuild every frame -
ObjectKeyused when identity is based on a data object rather than a single value
- Colors come from
Theme.of(context).colorScheme— no hardcodedColors.redor hex values - Text styles come from
Theme.of(context).textTheme— no inlineTextStylewith raw font sizes - Dark mode compatibility verified — no assumptions about light background
- Spacing and sizing use consistent design tokens or constants, not magic numbers
- No network calls, file I/O, or heavy computation in
build() - No
Future.then()orasyncwork inbuild() - No subscription creation (
.listen()) inbuild() -
setState()localized to smallest possible subtree
These principles apply to all Flutter state management solutions (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier, etc.).
- Business logic lives outside the widget layer — in a state management component (BLoC, Notifier, Controller, Store, ViewModel, etc.)
- State managers receive dependencies via injection, not by constructing them internally
- A service or repository layer abstracts data sources — widgets and state managers should not call APIs or databases directly
- State managers have a single responsibility — no "god" managers handling unrelated concerns
- Cross-component dependencies follow the solution's conventions:
- In Riverpod: providers depending on providers via
ref.watchis expected — flag only circular or overly tangled chains - In BLoC: blocs should not directly depend on other blocs — prefer shared repositories or presentation-layer coordination
- In other solutions: follow the documented conventions for inter-component communication
- In Riverpod: providers depending on providers via
- State objects are immutable — new instances created via
copyWith()or constructors, never mutated in-place - State classes implement
==andhashCodeproperly (all fields included in comparison) - Mechanism is consistent across the project — manual override,
Equatable,freezed, Dart records, or other - Collections inside state objects are not exposed as raw mutable
List/Map
- State is only mutated through the solution's reactive API (
@actionin MobX,.valueon signals,.obsin GetX) — direct field mutation bypasses change tracking - Derived values use the solution's computed mechanism rather than being stored redundantly
- Reactions and disposers are properly cleaned up (
ReactionDisposerin MobX, effect cleanup in Signals)
- Mutually exclusive states use sealed types, union variants, or the solution's built-in async state type (e.g. Riverpod's
AsyncValue) — not boolean flags (isLoading,isError,hasData) - Every async operation models loading, success, and error as distinct states
- All state variants are handled exhaustively in UI — no silently ignored cases
- Error states carry error information for display; loading states don't carry stale data
- Nullable data is not used as a loading indicator — states are explicit
// BAD — boolean flag soup allows impossible states
class UserState {
bool isLoading = false;
bool hasError = false; // isLoading && hasError is representable!
User? user;
}
// GOOD (immutable approach) — sealed types make impossible states unrepresentable
sealed class UserState {}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
final User user;
const UserLoaded(this.user);
}
class UserError extends UserState {
final String message;
const UserError(this.message);
}
// GOOD (reactive approach) — observable enum + data, mutations via reactivity API
// enum UserStatus { initial, loading, loaded, error }
// Use your solution's observable/signal to wrap status and data separately- State consumer widgets (Builder, Consumer, Observer, Obx, Watch, etc.) scoped as narrow as possible
- Selectors used to rebuild only when specific fields change — not on every state emission
-
constwidgets used to stop rebuild propagation through the tree - Computed/derived state is calculated reactively, not stored redundantly
- All manual subscriptions (
.listen()) are cancelled indispose()/close() - Stream controllers are closed when no longer needed
- Timers are cancelled in disposal lifecycle
- Framework-managed lifecycle is preferred over manual subscription (declarative builders over
.listen()) -
mountedcheck beforesetStatein async callbacks -
BuildContextnot used afterawaitwithout checkingcontext.mounted(Flutter 3.7+) — stale context causes crashes - No navigation, dialogs, or scaffold messages after async gaps without verifying the widget is still mounted
-
BuildContextnever stored in singletons, state managers, or static fields
- Ephemeral UI state (checkbox, slider, animation) uses local state (
setState,ValueNotifier) - Shared state is lifted only as high as needed — not over-globalized
- Feature-scoped state is properly disposed when the feature is no longer active
-
setState()not called at root widget level — localize state changes -
constwidgets used to stop rebuild propagation -
RepaintBoundaryused around complex subtrees that repaint independently -
AnimatedBuilderchild parameter used for subtrees independent of animation
- No sorting, filtering, or mapping large collections in
build()— compute in state management layer - No regex compilation in
build() -
MediaQuery.of(context)usage is specific (e.g.,MediaQuery.sizeOf(context))
- Network images use caching (any caching solution appropriate for the project)
- Appropriate image resolution for target device (no loading 4K images for thumbnails)
-
Image.assetwithcacheWidth/cacheHeightto decode at display size - Placeholder and error widgets provided for network images
-
ListView.builder/GridView.builderused instead ofListView(children: [...])for large or dynamic lists (concrete constructors are fine for small, static lists) - Pagination implemented for large data sets
- Deferred loading (
deferred as) used for heavy libraries in web builds
-
Opacitywidget avoided in animations — useAnimatedOpacityorFadeTransition - Clipping avoided in animations — pre-clip images
-
operator ==not overridden on widgets — useconstconstructors instead - Intrinsic dimension widgets (
IntrinsicHeight,IntrinsicWidth) used sparingly (extra layout pass)
- Unit tests: Cover all business logic (state managers, repositories, utility functions)
- Widget tests: Cover individual widget behavior, interactions, and visual output
- Integration tests: Cover critical user flows end-to-end
- Golden tests: Pixel-perfect comparisons for design-critical UI components
- Aim for 80%+ line coverage on business logic
- All state transitions have corresponding tests (loading → success, loading → error, retry, etc.)
- Edge cases tested: empty states, error states, loading states, boundary values
- External dependencies (API clients, databases, services) are mocked or faked
- Each test file tests exactly one class/unit
- Tests verify behavior, not implementation details
- Stubs define only the behavior needed for each test (minimal stubbing)
- No shared mutable state between test cases
-
pumpWidgetandpumpused correctly for async operations -
find.byType,find.text,find.byKeyused appropriately - No flaky tests depending on timing — use
pumpAndSettleor explicitpump(Duration) - Tests run in CI and failures block merges
-
Semanticswidget used to provide screen reader labels where automatic labels are insufficient -
ExcludeSemanticsused for purely decorative elements -
MergeSemanticsused to combine related widgets into a single accessible element - Images have
semanticLabelproperty set
- All interactive elements are focusable and have meaningful descriptions
- Focus order is logical (follows visual reading order)
- Contrast ratio >= 4.5:1 for text against background
- Tappable targets are at least 48x48 pixels
- Color is not the sole indicator of state (use icons/text alongside)
- Text scales with system font size settings
- No no-op
onPressedcallbacks — every button does something or is disabled - Error fields suggest corrections
- Context does not change unexpectedly while user is inputting data
- Platform-adaptive widgets used where appropriate
- Back navigation handled correctly (Android back button, iOS swipe-to-go-back)
- Status bar and safe area handled via
SafeAreawidget - Platform-specific permissions declared in
AndroidManifest.xmlandInfo.plist
-
LayoutBuilderorMediaQueryused for responsive layouts - Breakpoints defined consistently (phone, tablet, desktop)
- Text doesn't overflow on small screens — use
Flexible,Expanded,FittedBox - Landscape orientation tested or explicitly locked
- Web-specific: mouse/keyboard interactions supported, hover states present
- Sensitive data (tokens, credentials) stored using platform-secure storage (Keychain on iOS, EncryptedSharedPreferences on Android)
- Never store secrets in plaintext storage
- Biometric authentication gating considered for sensitive operations
- API keys NOT hardcoded in Dart source — use
--dart-define,.envfiles excluded from VCS, or compile-time configuration - Secrets not committed to git — check
.gitignore - Backend proxy used for truly secret keys (client should never hold server secrets)
- All user input validated before sending to API
- Form validation uses proper validation patterns
- No raw SQL or string interpolation of user input
- Deep link URLs validated and sanitized before navigation
- HTTPS enforced for all API calls
- Certificate pinning considered for high-security apps
- Authentication tokens refreshed and expired properly
- No sensitive data logged or printed
- Check pub points score (aim for 130+/160)
- Check likes and popularity as community signals
- Verify the publisher is verified on pub.dev
- Check last publish date — stale packages (>1 year) are a risk
- Review open issues and response time from maintainers
- Check license compatibility with your project
- Verify platform support covers your targets
- Use caret syntax (
^1.2.3) for dependencies — allows compatible updates - Pin exact versions only when absolutely necessary
- Run
flutter pub outdatedregularly to track stale dependencies - No dependency overrides in production
pubspec.yaml— only for temporary fixes with a comment/issue link - Minimize transitive dependency count — each dependency is an attack surface
- Internal packages import only from public API — no
package:other/src/internal.dart(breaks Dart package encapsulation) - Internal package dependencies use workspace resolution, not hardcoded
path: ../../relative strings - All sub-packages share or inherit root
analysis_options.yaml
- One routing approach used consistently — no mixing imperative
Navigator.pushwith a declarative router - Route arguments are typed — no
Map<String, dynamic>orObject?casting - Route paths defined as constants, enums, or generated — no magic strings scattered in code
- Auth guards/redirects centralized — not duplicated across individual screens
- Deep links configured for both Android and iOS
- Deep link URLs validated and sanitized before navigation
- Navigation state is testable — route changes can be verified in tests
- Back behavior is correct on all platforms
-
FlutterError.onErroroverridden to capture framework errors (build, layout, paint) -
PlatformDispatcher.instance.onErrorset for async errors not caught by Flutter -
ErrorWidget.buildercustomized for release mode (user-friendly instead of red screen) - Global error capture wrapper around
runApp(e.g.,runZonedGuarded, Sentry/Crashlytics wrapper)
- Error reporting service integrated (Firebase Crashlytics, Sentry, or equivalent)
- Non-fatal errors reported with stack traces
- State management error observer wired to error reporting (e.g., BlocObserver, ProviderObserver, or equivalent for your solution)
- User-identifiable info (user ID) attached to error reports for debugging
- API errors result in user-friendly error UI, not crashes
- Retry mechanisms for transient network failures
- Offline state handled gracefully
- Error states in state management carry error info for display
- Raw exceptions (network, parsing) are mapped to user-friendly, localized messages before reaching the UI — never show raw exception strings to users
- Localization solution configured (Flutter's built-in ARB/l10n, easy_localization, or equivalent)
- Supported locales declared in app configuration
- All user-visible strings use the localization system — no hardcoded strings in widgets
- Template file includes descriptions/context for translators
- ICU message syntax used for plurals, genders, selects
- Placeholders defined with types
- No missing keys across locales
- Localization accessor used consistently throughout the project
- Date, time, number, and currency formatting is locale-aware
- Text directionality (RTL) supported if targeting Arabic, Hebrew, etc.
- No string concatenation for localized text — use parameterized messages
- Classes depend on abstractions (interfaces), not concrete implementations at layer boundaries
- Dependencies provided externally via constructor, DI framework, or provider graph — not created internally
- Registration distinguishes lifetime: singleton vs factory vs lazy singleton
- Environment-specific bindings (dev/staging/prod) use configuration, not runtime
ifchecks - No circular dependencies in the DI graph
- Service locator calls (if used) are not scattered throughout business logic
-
analysis_options.yamlpresent with strict settings enabled - Strict analyzer settings:
strict-casts: true,strict-inference: true,strict-raw-types: true - A comprehensive lint rule set is included (very_good_analysis, flutter_lints, or custom strict rules)
- All sub-packages in monorepos inherit or share the root analysis options
- No unresolved analyzer warnings in committed code
- Lint suppressions (
// ignore:) are justified with comments explaining why -
flutter analyzeruns in CI and failures block merges
-
prefer_const_constructors— performance in widget trees -
avoid_print— use proper logging -
unawaited_futures— prevent fire-and-forget async bugs -
prefer_final_locals— immutability at variable level -
always_declare_return_types— explicit contracts -
avoid_catches_without_on_clauses— specific error handling -
always_use_package_imports— consistent import style
The table below maps universal principles to their implementation in popular solutions. Use this to adapt review rules to whichever solution the project uses.
| Principle | BLoC/Cubit | Riverpod | Provider | GetX | MobX | Signals | Built-in |
|---|---|---|---|---|---|---|---|
| State container | Bloc/Cubit |
Notifier/AsyncNotifier |
ChangeNotifier |
GetxController |
Store |
signal() |
StatefulWidget |
| UI consumer | BlocBuilder |
ConsumerWidget |
Consumer |
Obx/GetBuilder |
Observer |
Watch |
setState |
| Selector | BlocSelector/buildWhen |
ref.watch(p.select(...)) |
Selector |
N/A | computed | computed() |
N/A |
| Side effects | BlocListener |
ref.listen |
Consumer callback |
ever()/once() |
reaction |
effect() |
callbacks |
| Disposal | auto via BlocProvider |
.autoDispose |
auto via Provider |
onClose() |
ReactionDisposer |
manual | dispose() |
| Testing | blocTest() |
ProviderContainer |
ChangeNotifier directly |
Get.put in test |
store directly | signal directly | widget test |
🧩 Что это
Flutter & Dart Code Reviewer — это исчерпывающий чек-лист для ревью кода Flutter/Dart-приложений, не привязанный к конкретным библиотекам. Он охватывает все ключевые аспекты: от типичных ошибок языка Dart и best practices виджетов до архитектуры управления состоянием, производительности, безопасности и тестирования.
Этот гайд подходит для разработчиков, которые проводят code review, и для тимлидов, желающих внедрить единые стандарты качества. С его помощью можно системно проверить, что в проекте соблюдаются современные идиомы Flutter/Dart, избегаются антипаттерны, и приложение готово к продакшену.
⚙️ Как работает
Чек-лист разбит на 15 тематических разделов. Каждый пункт — это конкретное правило или вопрос, на который нужно ответить «да/нет» в ходе ревью. Вместо того чтобы давать готовые сниппеты, он описывает подход и критерии, оставляя реализацию на усмотрение команды.
📁 Общее здоровье проекта
Сначала проверяется структура папок (feature-first или layer-first), чистота pubspec.yaml, наличие строгого статического анализа (analysis_options.yaml) и отсутствие print() в коде. Platform-специфичный код должен быть изолирован за абстракциями.
💎 Ошибки Dart
Основные ловушки языка:
- Implicit
dynamic— отсутствие аннотаций типов. Включайтеstrict-casts,strict-inference,strict-raw-types. - Злоупотребление
!— используйте паттерн-матчинг Dart 3:if (value case var v?). - Слишком широкий
catch— всегда указывайте тип исключения (on).Error(субтипы ошибок) ловить нельзя. lateбез нужды — предпочитайте nullable или инициализацию в конструкторе.- Конкатенация строк в цикле — используйте
StringBufferвместо+. - Игнорирование
Future— либоawait, либо явноunawaited(). - Мутабельные коллекции в публичном API — возвращайте
unmodifiableview. - Пропущенный Dart 3 pattern matching — применяйте
switch-выражения иif-case. varвместоfinal— на местах предпочитайтеfinal, а для констант —const.- Относительные импорты — используйте
package:для единообразия. - Throwaway классы для возврата нескольких значений — используйте Dart 3 records:
(String, int).
🧱 Best Practices для виджетов
- Метод
build()не должен превышать 80–100 строк. - Частные
_build*()методы, возвращающие виджеты, должны быть вынесены в отдельные классы — это улучшает reuse, const-пропагацию и оптимизации фреймворка. - Const-конструкторы — обязательны где только возможно.
- Ключи:
ValueKeyдля списков,ObjectKeyдля объектов,UniqueKeyне использовать вbuild(). - Темизация: цвета и текст — только через
Theme.of(context), без хардкода. - В
build()запрещены сетевые вызовы, файловый I/O, подписки (listen()) иFuture.then().
🔄 Управление состоянием (library-agnostic)
Подход единый для BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier:
- Бизнес-логика живёт вне виджетов — в
Bloc,Notifier,Controller,Store,ViewModelи т.п. - Зависимости внедряются, а не создаются внутри.
- Слой
Service/Repositoryабстрагирует источники данных. - Immutability (для BLoC, Riverpod, Redux): состояние — неизменяемые объекты с
copyWith()и корректными==/hashCode. - Reactive discipline (для MobX, GetX, Signals): мутация только через реактивное API (
@action,.value,.obs), вычисляемые поля — черезcomputed. - Дизайн состояния: взаимоисключающие состояния — sealed class/union, а не флаги. Каждая асинхронная операция моделирует
loading,success,error. - Оптимизация перестроений:
Consumer/Builder— максимально узкие,Selectorдля точечной реакции,const-виджеты останавливают пропагацию. - Подписки: все
.listen()отменяются вdispose(),StreamControllerзакрываются,Timersотменяются. Послеawaitпроверятьcontext.mounted(Flutter 3.7+).BuildContextне хранить в синглтонах. - Локальное vs глобальное: UI-состояние (чекбоксы, слайдеры) —
setState/ValueNotifier. Общее — поднимать на минимально необходимый уровень, не глобализировать всё подряд.
⚡ Производительность
- Лишние перестроения:
setState()— только в минимальном поддереве,RepaintBoundary— для сложных поддеревьев,AnimatedBuilder.child— для независимых от анимации. - Тяжёлые операции (сортировка, фильтрация, regex) — не в
build(), а в слое управления состоянием. - Изображения: кеширование network-изображений,
cacheWidth/cacheHeightдляImage.asset, плейсхолдеры. - Ленивая загрузка:
ListView.builder,GridView.builderдля больших списков, пагинация,deferred asдля тяжёлых библиотек на вебе. - Избегать
Opacityв анимациях — использоватьAnimatedOpacityилиFadeTransition.
🧪 Тестирование
- Unit-тесты — бизнес-логика (state managers, repositories, утилиты).
- Widget-тесты — индивидуальное поведение виджетов.
- Integration-тесты — критически важные пользовательские сценарии.
- Golden-тесты — для дизайн-критичных компонентов.
- Цель: 80%+ coverage на бизнес-логике; все переходы состояний (loading→success, loading→error, retry).
- Внешние зависимости — моки/фейки; один тест — один класс; тесты проверяют поведение, не детали реализации.
- Widget-тесты: корректное использование
pumpWidget/pump/pumpAndSettle, никаких flaky тестов.
♿ Доступность (Accessibility)
Semanticsдля скринридеров,ExcludeSemanticsдля декоративных элементов,MergeSemanticsдля объединения,semanticLabelу изображений.- Контраст 4.5:1, таргеты ≥48×48 пикселей, цвет — не единственный индикатор состояния.
- Текст адаптируется к системному размеру шрифта.
- У ошибок есть подсказки по исправлению, контекст не меняется неожиданно.
📱 Platform-Specific & 💻 Responsive
- Platform-адаптивные виджеты, корректная обработка back-навигации,
SafeArea. LayoutBuilder/MediaQueryдля адаптивности, брейкпоинты (телефон/планшет/десктоп),Flexible/Expanded/FittedBoxдля предотвращения overflow.- Веб: поддержка мыши/клавиатуры, hover-состояния.
🔒 Безопасность
- Secure storage (Keychain/EncryptedSharedPreferences) для токенов и credentials.
- API-ключи — никогда в исходном коде; используйте
--dart-define,.env(исключён из VCS), backend-прокси. - Валидация ввода на клиенте перед отправкой; отсутствие raw SQL или интерполяции строк.
- Deep link URL — валидировать и санитизировать перед навигацией.
- HTTPS, certificate pinning (для high-security), ротация токенов.
📦 Зависимости
- При оценке пакетов на pub.dev: score ≥130/160, verified publisher, дата последнего обновления (<1 год), лицензия, поддержка платформ.
- Версии: caret syntax (
^1.2.3), безdependency_overridesв production (только временно с комментарием/ссылкой на issue). - Минимизировать транзитивные зависимости.
- Monorepo (melos/workspace): импорты только из публичного API (
package:other), не изsrc/internal.dart.
🧭 Навигация
- Один подход (императивный
Navigator.pushили декларативный Router), не смешивать. - Route-аргументы — типизированные, не
Map<String, dynamic>. - Auth guards — централизованные.
- Deep links настроены на обеих платформах и валидированы.
❗ Обработка ошибок
FlutterError.onErrorпереопределён для фреймворк-ошибок;PlatformDispatcher.instance.onError— для асинхронных.ErrorWidget.builderкастомизирован для release mode.- Интегрирован сервис репортинга (Crashlytics, Sentry).
BlocObserver(или аналог) подключён к репортингу.- Graceful degradation: API-ошибки → user-friendly UI, retry для временных сбоев, корректная работа офлайн.
- Исключения не показываются пользователю в сыром виде — мапятся в локализованные сообщения.
🌐 Интернационализация (l10n)
- Используется Flutter ARB/l10n или аналог.
- Все строки — через систему локализации, без хардкода.
- ICU message syntax для плюралей/рода/выбора.
- Типизированные плейсхолдеры.
- Дата, время, числа и валюта — locale-aware.
- Поддержка RTL, если необходимо.
💉 Dependency Injection
- Классы зависят от абстракций (интерфейсов), а не конкретных реализаций на границах слоёв.
- Зависимости предоставляются снаружи (конструктор, DI-фреймворк), не создаются внутри.
- Lifetime: singleton vs factory vs lazy singleton.
- Нет циклических зависимостей.
- Service locator (если используется) — не разбросан по всей бизнес-логике.
🔍 Статический анализ
strict-casts: true,strict-inference: true,strict-raw-types: true.- Набор правил:
very_good_analysis,flutter_lintsили кастомный. - В CI —
flutter analyze; предупреждения блокируют merge. // ignore:— только с обоснованием.- Ключевые правила:
prefer_const_constructors,avoid_print,unawaited_futures,prefer_final_locals,always_declare_return_types,avoid_catches_without_on_clauses,always_use_package_imports.
✅ Когда использовать
- В процессе code review нового Pull Request в Flutter/Dart-проекте — пройтись по разделам и отметить несоответствия.
- При разработке стандартов кодирования в команде — взять за основу и адаптировать.
- Перед релизом — как итоговый аудит приложения по всем ключевым аспектам (безопасность, доступность, производительность).
- При выборе стека — раздел State Management Quick Reference помогает сравнить решения (BLoC vs Riverpod vs Provider vs MobX vs Signals) по единым критериям.
📌 Важно знать
- Чек-лист library-agnostic — он не навязывает конкретный стек, а описывает универсальные принципы. В конце есть таблица соответствия для популярных решений.
- Некоторые пункты могут быть избыточны для маленького проекта или MVP — можно выборочно применять.
- Особое внимание — разделу State shape design: он описывает, как избежать «невозможных» состояний (impossible states) с помощью sealed types или реактивных enum.
- Правила по управлению подписками и context.mounted критически важны для предотвращения крешей после асинхронных операций.
Какие библиотеки управления состоянием поддерживаются этим навыком?
Этот навык не привязан к конкретной библиотеке и включает специальные рекомендации для BLoC, Riverpod, Provider, GetX, MobX и Signals, а также общие реактивные принципы.
Проверяет ли он платформозависимый код?
Навык уделяет внимание тому, чтобы платформозависимая логика была должным образом изолирована за абстракциями для поддержания чистой и тестируемой кодовой базы.
Как он улучшает производительность Flutter-приложений?
Он выявляет типичные проблемы производительности, такие как ненужные перестроения виджетов, отсутствие const-конструкторов, дорогостоящие операции внутри build-методов и неоптимизированную отрисовку списков.
Какие стандарты тестирования он применяет?
Он проверяет реализацию модульных, виджетных и интеграционных тестов, обеспечивая высокое покрытие бизнес-логики и правильную изоляцию зависимостей с помощью моков.
Может ли этот навык помочь с возможностями Dart 3?
Да, он специально проверяет использование современных идиом Dart 3, включая pattern matching, records для множественных возвращаемых значений и sealed classes для моделирования состояний.
Синхронизируйте навыки с Claude Cowork, Claude Code, Codex и другими.
Установка одной командой.
npx skillfish add affaan-m/everything-claude-code flutter-dart-code-reviewИсточник: https://mcpmarket.com/tools/skills/flutter-dart-code-reviewer-1
Комментарии
Комментариев пока нет. Будьте первым.