From ecc
위젯 모범 사례, 상태 관리 패턴(BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart 관용구, 성능, 접근성, 보안 및 클린 아키텍처를 아우르는 라이브러리에 독립적인 Flutter/Dart 코드 리뷰 체크리스트입니다.
npx claudepluginhub sam42-lab/everything-claude-code-krThis skill uses the workspace's default tool permissions.
Flutter/Dart 애플리케이션 리뷰를 위한 포괄적이고 라이브러리에 독립적인 체크리스트입니다. 이 원칙들은 어떤 상태 관리 솔루션, 라우팅 라이브러리 또는 DI 프레임워크를 사용하는지와 관계없이 적용됩니다.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Flutter/Dart 애플리케이션 리뷰를 위한 포괄적이고 라이브러리에 독립적인 체크리스트입니다. 이 원칙들은 어떤 상태 관리 솔루션, 라우팅 라이브러리 또는 DI 프레임워크를 사용하는지와 관계없이 적용됩니다.
pubspec.yaml이 깨끗한가 (미사용 의존성 제거, 버전 고정 등)analysis_options.yaml에 엄격한 린트 규칙과 분석기 설정이 포함되어 있는가print() 문이 없는가 (dart:developer의 log() 또는 로깅 패키지 사용).g.dart, .freezed.dart, .gr.dart)이 최신 상태이거나 .gitignore에 포함되어 있는가dynamic 발생 확인 — strict-casts, strict-inference, strict-raw-types 활성화 권장if (value case var v?)) 대신 과도한 ! (bang 연산자) 사용 여부this.field를 사용하고 있지 않은가on 절 없는 catch (e) 사용 자제; 항상 예외 타입을 명시할 것Error 캐치: Error의 하위 타입들은 버그를 나타내므로 캐치해서는 안 됨async: await를 한 번도 하지 않는 함수에 async 마크가 되어 있지 않은가 (불필요한 오버헤드 발생)late 남용: Null 허용 처리나 생성자 초기화가 더 안전한 상황에서 late를 사용하고 있지 않은가 (런타임 에러 위험)+ 대신 StringBuffer를 사용하고 있는가const 컨텍스트의 가변 상태: const 생성자 클래스의 필드가 가변(mutable) 상태가 아닌가Future 반환 값 무시: 의도를 명확히 하기 위해 await를 사용하거나 명시적으로 unawaited()를 호출하는가var vs final: 로컬 변수에는 final을, 컴파일 타임 상수에는 const를 우선적으로 사용하는가package: 임포트를 사용하고 있는가List/Map 대신 수정 불가능한 뷰(unmodifiable view)를 반환하는가is 체크와 수동 캐스팅 대신 switch 표현식이나 if-case를 사용하고 있는가(String, int)를 사용하고 있는가print(): dart:developer log() 또는 로깅 패키지를 사용하는가; print()는 로그 레벨이 없고 필터링이 불가능함build() 메서드가 80-100라인을 초과하지 않는가_build*() 헬퍼 메서드 대신 별도의 위젯 클래스로 추출되어 있는가 (엘리먼트 재사용, const 전파 및 프레임워크 최적화 가능)const 생성자를 사용하여 불필요한 리빌드를 방지하고 있는가const 리터럴을 사용하는가 (const [], const {})const로 선언했는가ValueKey를 사용하고 있는가GlobalKey는 트리 전체에서 상태 접근이 정말로 필요한 경우에만 제한적으로 사용하고 있는가build() 내에서 UniqueKey 사용을 피하고 있는가 (매 프레임마다 리빌드를 강제함)ObjectKey를 사용하고 있는가Theme.of(context).colorScheme에서 가져오는가 (하드코딩된 Colors.red 또는 헥사 코드 금지)Theme.of(context).textTheme에서 가져오는가 (폰트 크기가 하드코딩된 인라인 TextStyle 금지)build() 내에 네트워크 호출, 파일 I/O 또는 무거운 계산 로직이 없는가build() 내에 Future.then()이나 async 작업이 없는가build() 내에 구독 생성(.listen())이 없는가setState() 호출 범위를 최소한의 서브트리로 국한하고 있는가이 원칙들은 모든 Flutter 상태 관리 솔루션(BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier 등)에 적용됩니다.
ref.watch를 통한 프로바이더 간 의존성은 정상적이나, 순환 참조나 과도하게 복잡한 체인은 주의copyWith()나 생성자를 통해 새 인스턴스를 생성하며, 내부 값을 직접 수정하지 않음==와 hashCode를 올바르게 구현했는가 (모든 필드 비교 포함)Equatable, freezed, Dart records 등)List/Map으로 노출되지 않는가@action, signals의 .value, GetX의 .obs) — 직접 필드 수정 시 변경 추적 불가isLoading, isError 등의 나열 대신 Sealed types나 Union variants 사용)// 나쁨 — 불리언 플래그들의 조합은 불가능한 상태를 허용함
class UserState {
bool isLoading = false;
bool hasError = false; // isLoading && hasError 같은 상태가 표현 가능함!
User? user;
}
// 좋음 (불변 방식) — sealed 타입을 통해 불가능한 상태를 원천 차단
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);
}
const 위젯을 사용하는가.listen())이 dispose() / close()에서 취소되는가setState 호출 전 mounted 여부를 확인하는가await 이후 BuildContext 사용 시 context.mounted를 확인하는가 (Flutter 3.7+; 만료된 컨텍스트는 크래시 원인)BuildContext를 싱글톤, 상태 관리자 또는 스태틱 필드에 저장하지 않는가setState, ValueNotifier)를 사용하는가setState()를 호출하지 않는가const 위젯을 사용해 리빌드 전파를 차단하는가RepaintBoundary를 사용하는가AnimatedBuilder의 child 파라미터를 활용하는가build() 내에서 큰 컬렉션의 정렬, 필터링, 매핑 작업을 하지 않는가 (상태 관리 레이어에서 처리 권장)build() 내에서 정규표현식을 컴파일하지 않는가MediaQuery.of(context) 대신 필요한 정보만 가져오는 전용 메서드(예: MediaQuery.sizeOf(context))를 사용하는가Image.asset 사용 시 cacheWidth/cacheHeight를 지정해 표시 크기에 맞춰 디코딩하는가ListView(children: [...]) 대신 ListView.builder / GridView.builder를 사용하는가deferred as)을 적용했는가Opacity 위젯 대신 AnimatedOpacity 또는 FadeTransition을 사용하는가operator ==를 오버라이드하지 않고 const 생성자를 활용하는가IntrinsicHeight, IntrinsicWidth) 사용을 최소화하는가pumpWidget과 pump를 올바르게 사용하는가find.byType, find.text, find.byKey 등을 상황에 맞게 활용하는가pumpAndSettle 또는 명시적인 pump(Duration)를 사용하는가Semantics 위젯을 사용하여 스크린 리더용 레이블을 제공하는가ExcludeSemantics를 사용하는가MergeSemantics를 사용하는가semanticLabel 속성이 설정되어 있는가onPressed 콜백이 없는가 (동작을 구현하거나 버튼을 비활성화할 것)SafeArea 위젯으로 처리했는가AndroidManifest.xml과 Info.plist에 정의되어 있는가LayoutBuilder나 MediaQuery를 사용하여 반응형 레이아웃을 구현했는가Flexible, Expanded, FittedBox 활용--dart-define, 버전 관리에서 제외된 .env 파일 또는 컴파일 타임 구성을 사용할 것.gitignore 확인)^1.2.3)을 사용해 호환 가능한 업데이트를 허용하는가flutter pub outdated를 실행해 오래된 의존성을 확인하는가pubspec.yaml에 임시 수정 목적의 의존성 오버라이드(dependency_overrides)가 남아 있지 않은가src/ 임포트 금지)analysis_options.yaml을 공유하거나 상속하는가Navigator.push와 선언적 라우터를 섞어 쓰지 않음)Map<String, dynamic>이나 Object? 캐스팅 지양)FlutterError.onError를 오버라이드했는가PlatformDispatcher.instance.onError를 설정했는가ErrorWidget.builder를 커스터마이징했는가 (붉은 화면 대신 사용자 친화적 UI 제공)runApp 주변을 전역 에러 캡처 래퍼로 감쌌는가 (예: runZonedGuarded, Sentry/Crashlytics 래퍼)if 체크 대신 구성을 사용했는가analysis_options.yaml이 존재하는가strict-casts: true, strict-inference: true, strict-raw-types: true// ignore:) 사용 시 정당한 이유가 주석으로 설명되어 있는가flutter analyze가 실행되며 실패 시 머지가 차단되는가prefer_const_constructors — 위젯 트리 성능 최적화avoid_print — 적절한 로깅 사용 유도unawaited_futures — 비동기 에러 방지prefer_final_locals — 변수 레벨의 불변성 확보always_declare_return_types — 명확한 API 계약avoid_catches_without_on_clauses — 특정 에러 처리 강제always_use_package_imports — 일관된 임포트 스타일아래 표는 인기 있는 상태 관리 솔루션들이 공통 원칙을 어떻게 구현하는지 보여줍니다. 프로젝트에서 사용하는 솔루션에 맞춰 리뷰 규칙을 조정하세요.
| 원칙 | BLoC/Cubit | Riverpod | Provider | GetX | MobX | Signals | 내장 기능 |
|---|---|---|---|---|---|---|---|
| 상태 컨테이너 | Bloc/Cubit | Notifier/AsyncNotifier | ChangeNotifier | GetxController | Store | signal() | StatefulWidget |
| UI 소비자 | BlocBuilder | ConsumerWidget | Consumer | Obx/GetBuilder | Observer | Watch | setState |
| 셀렉터 | BlocSelector/buildWhen | ref.watch(p.select(...)) | Selector | 해당 없음 | computed | computed() | 해당 없음 |
| 사이드 이펙트 | BlocListener | ref.listen | Consumer 콜백 | ever()/once() | reaction | effect() | 콜백 함수 |
| 해제 (Disposal) | BlocProvider에 의해 자동 처리 | .autoDispose | Provider에 의해 자동 처리 | onClose() | ReactionDisposer | 수동 처리 | dispose() |
| 테스트 | blocTest() | ProviderContainer | ChangeNotifier 직접 테스트 | 테스트 내 Get.put | Store 직접 테스트 | Signal 직접 테스트 | 위젯 테스트 |