Communitygithub.com

Flutter/Dart Code-Review

Bibliotheksunabhängige Checkliste für Flutter/Dart-Code-Reviews, die Widget-Best Practices, State-Management-Muster (BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart-Idiome, Performance, Barrierefreiheit, Sicherheit und Clean Architecture abdeckt. Verwenden Sie sie beim Review von Flutter- oder Dart-Code, unabhängig von der verwendeten State-Management-Bibliothek.

Was ist Dart Code-Review?

Diese SKILL.md definiert eine umfassende, bibliotheksunabhängige Checkliste für Code-Reviews von Flutter- und Dart-Anwendungen. Sie deckt ein breites Spektrum ab: allgemeine Projektstruktur, Dart-Sprachfallen (z. B. implizites dynamic, Null-Sicherheitsfehler, fehlerhaftes Exception-Handling), Widget-Best Practices (Zerlegung, const-Nutzung, Key-Verwendung, Theming), sowie ein detailliertes, agnostisches State-Management-Kapitel, das Prinzipien für alle gängigen Lösungen (BLoC, Riverpod, Provider, GetX, MobX, Signals) bereitstellt. Weitere Bereiche sind Performance-Optimierung, Teststrategien (Unit-, Widget-, Integrations- und Golden-Tests), Barrierefreiheit (Semantik, Screenreader, visuelle und interaktive Zugänglichkeit), plattformspezifische Überlegungen (iOS/Android, responsives Design) und Sicherheit. Die Checkliste ist mit praktischen Beispielen (z. B. korrekte/sealed State-Modellierung) und klaren Vermeidungsmustern angereichert, um Entwicklerteams eine konsistente Review-Praxis zu ermöglichen. Sie ist für jede Flutter/Dart-Codebasis ohne Bindung an ein bestimmtes Framework oder eine Bibliothek konzipiert.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/flutter-dart-code-review

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Flutter/Dart Code-Review – Best Practices

Umfassende, bibliotheksunabhängige Checkliste für die Überprüfung von Flutter/Dart-Anwendungen. Diese Prinzipien gelten unabhängig davon, welche State-Management-Lösung, Routing-Bibliothek oder DI-Framework verwendet wird.


1. Allgemeine Projektgesundheit

  • Projekt folgt einer konsistenten Ordnerstruktur (Feature-first oder Layer-first)
  • Ordnungsgemäße Trennung der Belange: UI, Geschäftslogik, Datenebenen
  • Keine Geschäftslogik in Widgets; Widgets sind rein präsentational
  • pubspec.yaml ist sauber – keine ungenutzten Abhängigkeiten, Versionen angemessen fixiert
  • analysis_options.yaml enthält ein strenges Lint-Set mit aktivierten strikten Analyzer-Einstellungen
  • Keine print()-Anweisungen im Produktionscode – verwenden Sie dart:developer log() oder ein Logging-Paket
  • Generierte Dateien (.g.dart, .freezed.dart, .gr.dart) sind aktuell oder in .gitignore
  • Plattformspezifischer Code ist hinter Abstraktionen isoliert

2. Dart-Sprachfallen

  • Implizites dynamic: Fehlende Typannotationen führen zu dynamic – aktivieren Sie strict-casts, strict-inference, strict-raw-types
  • Nullsicherheits-Missbrauch: Übermäßiger Einsatz des !-Operators anstelle korrekter Null-Prüfungen oder Dart 3 Pattern Matching (if (value case var v?))
  • Type-Promotion-Fehler: Verwendung von this.field, obwohl lokale Variablen-Promotion funktionieren würde
  • Zu weites Fangen: catch (e) ohne on-Klausel; geben Sie immer Ausnahmetypen an
  • Fangen von Error: Error-Subtypen deuten auf Bugs hin und sollten nicht gefangen werden
  • Unbenutztes async: Funktionen, die als async markiert sind, aber nie await verwenden – unnötiger Overhead
  • Übermäßige Nutzung von late: late wird verwendet, obwohl nullable oder Konstruktor-Initialisierung sicherer wäre; verschiebt Fehler in die Laufzeit
  • String-Konkatenation in Schleifen: Verwenden Sie StringBuffer anstelle von + für iterative Zeichenkettenbildung
  • Veränderlicher Zustand in const-Kontexten: Felder in const-Konstruktor-Klassen sollten nicht veränderbar sein
  • Ignorieren von Future-Rückgabewerten: Verwenden Sie await oder rufen Sie explizit unawaited() auf, um die Absicht zu signalisieren
  • var wo final funktioniert: Bevorzugen Sie final für lokale Variablen und const für Kompilierzeitkonstanten
  • Relative Imports: Verwenden Sie package:-Imports für Konsistenz
  • Veränderliche Sammlungen offengelegt: Öffentliche APIs sollten unveränderliche Ansichten zurückgeben, nicht rohe List/Map
  • Fehlendes Dart 3 Pattern Matching: Bevorzugen Sie Switch-Expressions und if-case gegenüber ausführlichen is-Prüfungen und manuellem Casting
  • Wegwerfklassen für Mehrfachrückgaben: Verwenden Sie Dart 3 Records (String, int) anstelle von einmaligen DTOs
  • print() im Produktionscode: Verwenden Sie dart:developer log() oder das Logging-Paket des Projekts; print() hat keine Log-Level und kann nicht gefiltert werden

3. Widget-Best Practices

Widget-Zerlegung:

  • Kein einzelnes Widget mit einer build()-Methode, die ~80-100 Zeilen überschreitet
  • Widgets werden nach Kapselung UND nach Änderungsverhalten aufgeteilt (Rebuild-Grenzen)
  • Private _build*()-Hilfsmethoden, die Widgets zurückgeben, werden in separate Widget-Klassen extrahiert (ermöglicht Elementwiederverwendung, const-Weitergabe und Framework-Optimierungen)
  • Stateless Widgets werden Stateful vorgezogen, wenn kein veränderlicher lokaler Zustand benötigt wird
  • Extrahierte Widgets befinden sich in separaten Dateien, wenn sie wiederverwendbar sind

Const-Nutzung:

  • const-Konstruktoren werden wo immer möglich verwendet – verhindert unnötige Rebuilds
  • const-Literale für Sammlungen, die sich nicht ändern (const [], const {})
  • Konstruktor wird als const deklariert, wenn alle Felder final sind

Key-Nutzung:

  • ValueKey wird in Listen/Gittern verwendet, um den Zustand bei Neuanordnungen zu erhalten
  • GlobalKey wird sparsam verwendet – nur wenn der Zugriff auf den Zustand über den gesamten Baum hinweg wirklich benötigt wird
  • UniqueKey wird in build() vermieden – erzwingt einen Rebuild bei jedem Frame
  • ObjectKey wird verwendet, wenn die Identität auf einem Datenobjekt und nicht auf einem einzelnen Wert basiert

Theming & Designsystem:

  • Farben stammen aus Theme.of(context).colorScheme – keine hartcodierten Colors.red- oder Hex-Werte
  • Textstile stammen aus Theme.of(context).textTheme – kein Inline-TextStyle mit rohen Schriftgrößen
  • Dunkelmodus-Kompatibilität überprüft – keine Annahmen über hellen Hintergrund
  • Abstände und Größen verwenden konsistente Design-Tokens oder Konstanten, keine magischen Zahlen

Build-Methoden-Komplexität:

  • Keine Netzwerkaufrufe, Datei-I/O oder rechenintensive Operationen in build()
  • Kein Future.then() oder async-Arbeit in build()
  • Keine Erstellung von Abonnements (.listen()) in build()
  • setState() auf den kleinstmöglichen Teilbaum beschränkt

4. State Management (Bibliotheksunabhängig)

Diese Prinzipien gelten für alle Flutter-State-Management-Lösungen (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier usw.).

Architektur:

  • Geschäftslogik lebt außerhalb der Widget-Schicht – in einer State-Management-Komponente (BLoC, Notifier, Controller, Store, ViewModel usw.)
  • State-Manager erhalten Abhängigkeiten per Injektion, nicht durch interne Konstruktion
  • Eine Dienst- oder Repository-Schicht abstrahiert Datenquellen – Widgets und State-Manager sollten keine APIs oder Datenbanken direkt aufrufen
  • State-Manager haben eine einzige Verantwortung – keine „God“-Manager, die nicht zusammenhängende Belange behandeln
  • Abhängigkeiten zwischen Komponenten folgen den Konventionen der Lösung:
    • In Riverpod: Provider, die von anderen Providern via ref.watch abhängen, sind erwartet – kennzeichnen Sie nur zirkuläre oder übermäßig verworrene Ketten
    • In BLoC: Blocs sollten nicht direkt von anderen Blocs abhängen – bevorzugen Sie gemeinsame Repositories oder Koordination in der Präsentationsschicht
    • In anderen Lösungen: Befolgen Sie die dokumentierten Konventionen für die Kommunikation zwischen Komponenten

Unveränderlichkeit & Wertegleichheit (für Lösungen mit unveränderlichem Zustand: BLoC, Riverpod, Redux):

  • Zustandsobjekte sind unveränderlich – neue Instanzen werden über copyWith() oder Konstruktoren erstellt, niemals direkt verändert
  • Zustandsklassen implementieren == und hashCode korrekt (alle Felder in den Vergleich einbezogen)
  • Mechanismus ist über das gesamte Projekt konsistent – manuelle Überschreibung, Equatable, freezed, Dart Records oder andere
  • Sammlungen innerhalb von Zustandsobjekten werden nicht als rohe veränderliche List/Map offengelegt

Reaktivitätsdisziplin (für reaktive Mutationslösungen: MobX, GetX, Signals):

  • Zustand wird nur über die reaktive API der Lösung mutiert (@action in MobX, .value auf Signalen, .obs in GetX) – direkte Feldmutation umgeht die Änderungsverfolgung
  • Abgeleitete Werte verwenden den berechneten Mechanismus der Lösung, anstatt redundant gespeichert zu werden
  • Reaktionen und Disposer werden ordnungsgemäß bereinigt (ReactionDisposer in MobX, Effektbereinigung in Signals)

Zustandsform-Design:

  • Sich gegenseitig ausschließende Zustände verwenden versiegelte Typen, Union-Varianten oder den integrierten asynchronen Zustandstyp der Lösung (z. B. Riverpods AsyncValue) – keine booleschen Flags (isLoading, isError, hasData)
  • Jeder asynchrone Vorgang modelliert Lade-, Erfolgs- und Fehlerzustände als separate Zustände
  • Alle Zustandsvarianten werden in der UI erschöpfend behandelt – keine stillschweigend ignorierten Fälle
  • Fehlerzustände tragen Fehlerinformationen zur Anzeige; Ladezustände enthalten keine veralteten Daten
  • Nullable-Daten werden nicht als Ladeindikator verwendet – Zustände sind explizit
// SCHLECHT – Boolesche Flag-Suppe ermöglicht unmögliche Zustände
class UserState {
  bool isLoading = false;
  bool hasError = false; // isLoading && hasError ist darstellbar!
  User? user;
}

// GUT (unveränderlicher Ansatz) – versiegelte Typen machen unmögliche Zustände undarstellbar
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);
}

// GUT (reaktiver Ansatz) – beobachtbares Enum + Daten, Mutationen über die Reaktivitäts-API
// enum UserStatus { initial, loading, loaded, error }
// Verwenden Sie den observable/signal Ihrer Lösung, um Status und Daten getrennt zu wrappen

Rebuild-Optimierung:

  • Zustandskonsumenten-Widgets (Builder, Consumer, Observer, Obx, Watch usw.) sind so eng wie möglich eingegrenzt
  • Selektoren werden verwendet, um nur bei Änderungen bestimmter Felder neu zu bauen – nicht bei jeder Zustandsemission
  • const-Widgets werden verwendet, um die Rebuild-Weitergabe durch den Baum zu stoppen
  • Berechneter/abgeleiteter Zustand wird reaktiv berechnet, nicht redundant gespeichert

Abonnements & Freigabe:

  • Alle manuellen Abonnements (.listen()) werden in dispose() / close() gekündigt
  • Stream-Controller werden geschlossen, wenn sie nicht mehr benötigt werden
  • Timer werden im Freigabe-Lebenszyklus gekündigt
  • Framework-verwalteter Lebenszyklus wird gegenüber manuellen Abonnements bevorzugt (deklarative Builder statt .listen())
  • mounted-Prüfung vor setState in asynchronen Callbacks
  • BuildContext wird nach await nicht ohne Überprüfung von context.mounted verwendet (Flutter 3.7+) – veralteter Context verursacht Abstürze
  • Keine Navigation, Dialoge oder Scaffold-Nachrichten nach asynchronen Lücken, ohne zu überprüfen, ob das Widget noch eingehängt ist
  • BuildContext wird niemals in Singletons, State-Managern oder statischen Feldern gespeichert

Lokaler vs. globaler Zustand:

  • Flüchtiger UI-Zustand (Checkbox, Slider, Animation) verwendet lokalen Zustand (setState, ValueNotifier)
  • Gemeinsam genutzter Zustand wird nur so hoch wie nötig gehoben – nicht übermäßig globalisiert
  • Feature-begrenzter Zustand wird ordnungsgemäß freigegeben, wenn das Feature nicht mehr aktiv ist

5. Performance

Unnötige Rebuilds:

  • setState() wird nicht auf der obersten Widget-Ebene aufgerufen – lokalisieren Sie Zustandsänderungen
  • const-Widgets werden verwendet, um die Rebuild-Weitergabe zu stoppen
  • RepaintBoundary wird um komplexe Teilbäume verwendet, die unabhängig neu zeichnen
  • Der child-Parameter von AnimatedBuilder wird für Teilbäume verwendet, die unabhängig von der Animation sind

Teure Operationen in build():

  • Kein Sortieren, Filtern oder Mapping großer Sammlungen in build() – in der State-Management-Ebene berechnen
  • Keine Regex-Kompilierung in build()
  • MediaQuery.of(context)-Nutzung ist spezifisch (z. B. MediaQuery.sizeOf(context))

Bildoptimierung:

  • Netzwerkbilder verwenden Caching (jede für das Projekt geeignete Caching-Lösung)
  • Angemessene Bildauflösung für das Zielgerät (kein Laden von 4K-Bildern für Thumbnails)
  • Image.asset mit cacheWidth/cacheHeight, um in der Anzeigegröße zu dekodieren
  • Platzhalter- und Fehler-Widgets für Netzwerkbilder bereitgestellt

Lazy Loading:

  • ListView.builder / GridView.builder wird anstelle von ListView(children: [...]) für große oder dynamische Listen verwendet (konkrete Konstruktoren sind für kleine, statische Listen in Ordnung)
  • Paginierung für große Datensätze implementiert
  • Verzögertes Laden (deferred as) für schwere Bibliotheken in Web-Builds

Sonstiges:

  • Opacity-Widget wird in Animationen vermieden – verwenden Sie AnimatedOpacity oder FadeTransition
  • Clipping wird in Animationen vermieden – Bilder vorher zuschneiden
  • operator == wird nicht auf Widgets überschrieben – stattdessen const-Konstruktoren verwenden
  • Intrinsische Dimension-Widgets (IntrinsicHeight, IntrinsicWidth) werden sparsam verwendet (zusätzlicher Layout-Durchlauf)

6. Testen

Testarten und Erwartungen:

  • Unit-Tests: Deckt die gesamte Geschäftslogik ab (State-Manager, Repositories, Hilfsfunktionen)
  • Widget-Tests: Deckt das Verhalten einzelner Widgets, Interaktionen und visuelle Ausgabe ab
  • Integrationstests: Deckt kritische Benutzerabläufe End-to-End ab
  • Golden-Tests: Pixelgenaue Vergleiche für designkritische UI-Komponenten

Abdeckungsziele:

  • Ziel: 80 %+ Zeilenabdeckung der Geschäftslogik
  • Alle Zustandsübergänge haben entsprechende Tests (Laden → Erfolg, Laden → Fehler, Wiederholung usw.)
  • Randfälle getestet: leere Zustände, Fehlerzustände, Ladezustände, Grenzwerte

Testisolierung:

  • Externe Abhängigkeiten (API-Clients, Datenbanken, Dienste) werden gemockt oder gefaked
  • Jede Testdatei testet genau eine Klasse/Einheit
  • Tests überprüfen das Verhalten, nicht die Implementierungsdetails
  • Stubs definieren nur das für jeden Test benötigte Verhalten (minimales Stubbing)
  • Kein gemeinsamer veränderlicher Zustand zwischen Testfällen

Widget-Testqualität:

  • pumpWidget und pump werden korrekt für asynchrone Operationen verwendet
  • find.byType, find.text, find.byKey werden angemessen verwendet
  • Keine flaky Tests, die von Timing abhängen – verwenden Sie pumpAndSettle oder explizites pump(Duration)
  • Tests laufen in CI und Fehler blockieren Merges

7. Barrierefreiheit

Semantische Widgets:

  • Semantics-Widget wird verwendet, um Screenreader-Labels bereitzustellen, wenn automatische Labels nicht ausreichen
  • ExcludeSemantics wird für rein dekorative Elemente verwendet
  • MergeSemantics wird verwendet, um verwandte Widgets zu einem einzigen zugänglichen Element zusammenzufassen
  • Bilder haben die Eigenschaft semanticLabel gesetzt

Screenreader-Unterstützung:

  • Alle interaktiven Elemente sind fokussierbar und haben sinnvolle Beschreibungen
  • Die Fokus-Reihenfolge ist logisch (folgt der visuellen Lesereihenfolge)

Visuelle Barrierefreiheit:

  • Kontrastverhältnis >= 4,5:1 für Text gegenüber Hintergrund
  • Berührbare Ziele sind mindestens 48x48 Pixel groß
  • Farbe ist nicht der einzige Indikator für den Status (Symbole/Text daneben verwenden)
  • Text skaliert mit den Systemschriftgrößen-Einstellungen

Interaktions-Barrierefreiheit:

  • Keine No-op-onPressed-Callbacks – jeder Button tut etwas oder ist deaktiviert
  • Fehlerfelder schlagen Korrekturen vor
  • Der Kontext ändert sich nicht unerwartet, während der Benutzer Daten eingibt

8. Plattformspezifische Belange

iOS/Android-Unterschiede:

  • Plattformadaptive Widgets werden verwendet, wo angemessen
  • Rückwärtsnavigation wird korrekt behandelt (Android-Zurück-Button, iOS-Wischen-zurück)
  • Statusleiste und Safe-Area werden über das SafeArea-Widget behandelt
  • Plattformspezifische Berechtigungen werden in AndroidManifest.xml und Info.plist deklariert

Responsive Design:

  • LayoutBuilder oder MediaQuery werden für responsive Layouts verwendet
  • Breakpoints sind konsistent definiert (Telefon, Tablet, Desktop)
  • Text läuft auf kleinen Bildschirmen nicht über – verwenden Sie Flexible, Expanded, FittedBox
  • Querformat getestet oder explizit gesperrt
  • Webspezifisch: Maus-/Tastaturinteraktionen unterstützt, Hover-Zustände vorhanden

9. Sicherheit

Sichere Speicherung:

  • Sensitive Daten …

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Verwandte Skills