Communitygithub.com

revisión-de-código-flutter-dart

Lista de verificación de revisión de código Flutter/Dart independiente de librerías que cubre las mejores prácticas de widgets, patrones de gestión de estado (BLoC, Riverpod, Provider, GetX, MobX, Signals), modismos de Dart, rendimiento, accesibilidad, seguridad y arquitectura limpia. Úsala al revisar código Flutter o Dart, independientemente de la librería de gestión de estado que utilice el proyecto.

¿Qué es revisión-de-código-flutter-dart?

Esta habilidad proporciona una lista de verificación completa e independiente de librerías para revisar aplicaciones Flutter/Dart. Cubre todo, desde la salud general del proyecto y los errores del lenguaje Dart hasta las mejores prácticas de widgets, gestión de estado (independiente de la librería), rendimiento, pruebas, accesibilidad, preocupaciones específicas de la plataforma, seguridad y documentación. Está diseñada para ser utilizada por desarrolladores al revisar el código de colegas o su propio código, asegurando la adherencia a los principios de Dart moderno (como el uso de coincidencia de patrones y registros de Dart 3) y las mejores prácticas de Flutter para widgets, rendimiento y gestión de estado. La lista de verificación está organizada en secciones claramente numeradas, cada una con elementos de acción en formato de lista de verificación. Es útil para revisiones de código manuales, como guía para herramientas de análisis estático o como referencia para incorporar estas prácticas en procesos de CI. La habilidad es independiente de la librería, lo que significa que los principios y elementos de la lista de verificación se aplican independientemente de la solución de gestión de estado (BLoC, Riverpod, Provider, GetX, MobX, Signals, etc.) que utilice un proyecto. Promueve una arquitectura limpia, código inmutable, widgets eficientes con constante, pruebas exhaustivas y aplicaciones accesibles.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/flutter-dart-code-review

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Mejores Prácticas de Revisión de Código Flutter/Dart

Lista de verificación completa e independiente de librerías para revisar aplicaciones Flutter/Dart. Estos principios se aplican independientemente de la solución de gestión de estado, librería de enrutamiento o marco de DI que se utilice.


1. Salud General del Proyecto

  • El proyecto sigue una estructura de carpetas consistente (primero características o primero capas)
  • Separación adecuada de preocupaciones: capas de UI, lógica de negocio y datos
  • Sin lógica de negocio en widgets; los widgets son puramente de presentación
  • pubspec.yaml está limpio — sin dependencias no utilizadas, versiones fijadas adecuadamente
  • analysis_options.yaml incluye un conjunto de lint estricto con configuraciones estrictas del analizador habilitadas
  • Sin sentencias print() en código de producción — usa dart:developer log() o un paquete de logging
  • Los archivos generados (.g.dart, .freezed.dart, .gr.dart) están actualizados o en .gitignore
  • El código específico de la plataforma está aislado detrás de abstracciones

2. Errores del Lenguaje Dart

  • Dinámico implícito: Falta de anotaciones de tipo que lleva a dynamic — habilita strict-casts, strict-inference, strict-raw-types
  • Mal uso de seguridad nula: Uso excesivo de ! (operador bang) en lugar de comprobaciones nulas adecuadas o coincidencia de patrones de Dart 3 (if (value case var v?))
  • Fallos de promoción de tipo: Usar this.field donde funcionaría la promoción de variables locales
  • Captura demasiado amplia: catch (e) sin cláusula on; siempre especifica los tipos de excepción
  • Capturar Error: Los subtipos de Error indican errores y no deben ser capturados
  • async no utilizado: Funciones marcadas como async que nunca hacen await — sobrecarga innecesaria
  • Uso excesivo de late: Se usa late donde sería más seguro usar nullable o inicialización en constructor; difiere errores al tiempo de ejecución
  • Concatenación de cadenas en bucles: Usa StringBuffer en lugar de + para la construcción iterativa de cadenas
  • Estado mutable en contextos const: Los campos en clases con constructores const no deben ser mutables
  • Ignorar valores de retorno de Future: Usa await o llama explícitamente a unawaited() para indicar la intención
  • var donde funciona final: Prefiere final para variables locales y const para constantes en tiempo de compilación
  • Importaciones relativas: Usa importaciones package: para consistencia
  • Colecciones mutables expuestas: Las APIs públicas deben devolver vistas no modificables, no List/Map sin procesar
  • Falta de coincidencia de patrones de Dart 3: Prefiere expresiones switch y if-case en lugar de comprobaciones is verbosas y casting manual
  • Clases desechables para retornos múltiples: Usa registros de Dart 3 (String, int) en lugar de DTOs de un solo uso
  • print() en código de producción: Usa dart:developer log() o el paquete de logging del proyecto; print() no tiene niveles de log y no se puede filtrar

3. Mejores Prácticas de Widgets

Descomposición de widgets:

  • Ningún widget con un método build() que exceda ~80-100 líneas
  • Widgets divididos por encapsulación Y por cómo cambian (límites de reconstrucción)
  • Los métodos auxiliares privados _build*() que devuelven widgets se extraen a clases de widget separadas (permite la reutilización de elementos, la propagación de const y las optimizaciones del marco)
  • Widgets Stateless preferidos sobre Stateful cuando no se necesita estado mutable local
  • Los widgets extraídos están en archivos separados cuando son reutilizables

Uso de Const:

  • Constructores const utilizados siempre que sea posible — previene reconstrucciones innecesarias
  • Literales const para colecciones que no cambian (const [], const {})
  • El constructor se declara const cuando todos los campos son final

Uso de Key:

  • ValueKey utilizado en listas/grids para preservar el estado a través de reordenamientos
  • GlobalKey utilizado con moderación — solo cuando realmente se necesita acceder al estado a través del árbol
  • UniqueKey evitado en build() — fuerza la reconstrucción en cada fotograma
  • ObjectKey utilizado cuando la identidad se basa en un objeto de datos en lugar de un solo valor

Tematización y sistema de diseño:

  • Los colores provienen de Theme.of(context).colorScheme — sin Colors.red o valores hexadecimales hardcodeados
  • Los estilos de texto provienen de Theme.of(context).textTheme — sin TextStyle en línea con tamaños de fuente sin procesar
  • Compatibilidad con modo oscuro verificada — sin suposiciones sobre fondo claro
  • El espaciado y el tamaño utilizan tokens de diseño consistentes o constantes, no números mágicos

Complejidad del método build:

  • Sin llamadas de red, E/S de archivos o cálculos pesados en build()
  • Sin Future.then() o trabajo async en build()
  • Sin creación de suscripciones (.listen()) en build()
  • setState() localizado en el subárbol más pequeño posible

4. Gestión de Estado (Independiente de Librerías)

Estos principios se aplican a todas las soluciones de gestión de estado de Flutter (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier, etc.).

Arquitectura:

  • La lógica de negocio reside fuera de la capa de widgets — en un componente de gestión de estado (BLoC, Notifier, Controller, Store, ViewModel, etc.)
  • Los gestores de estado reciben dependencias mediante inyección, no construyéndolas internamente
  • Una capa de servicio o repositorio abstrae las fuentes de datos — los widgets y gestores de estado no deben llamar a APIs o bases de datos directamente
  • Los gestores de estado tienen una única responsabilidad — sin gestores "dios" que manejen preocupaciones no relacionadas
  • Las dependencias entre componentes siguen las convenciones de la solución:
    • En Riverpod: se espera que los proveedores dependan de otros proveedores mediante ref.watch — marca solo cadenas circulares o demasiado enredadas
    • En BLoC: los blocs no deben depender directamente de otros blocs — prefiere repositorios compartidos o coordinación de la capa de presentación
    • En otras soluciones: sigue las convenciones documentadas para la comunicación entre componentes

Inmutabilidad e igualdad de valor (para soluciones de estado inmutable: BLoC, Riverpod, Redux):

  • Los objetos de estado son inmutables — se crean nuevas instancias mediante copyWith() o constructores, nunca se mutan en el lugar
  • Las clases de estado implementan == y hashCode correctamente (todos los campos incluidos en la comparación)
  • El mecanismo es consistente en todo el proyecto — anulación manual, Equatable, freezed, registros de Dart u otro
  • Las colecciones dentro de los objetos de estado no se exponen como List/Map mutables sin procesar

Disciplina de reactividad (para soluciones de mutación reactiva: MobX, GetX, Signals):

  • El estado solo se muta a través de la API reactiva de la solución (@action en MobX, .value en signals, .obs en GetX) — la mutación directa de campos evita el seguimiento de cambios
  • Los valores derivados utilizan el mecanismo computado de la solución en lugar de almacenarse de forma redundante
  • Las reacciones y los removedores se limpian adecuadamente (ReactionDisposer en MobX, limpieza de efectos en Signals)

Diseño de forma del estado:

  • Los estados mutuamente excluyentes utilizan tipos sellados, variantes de unión o el tipo de estado asíncrono integrado de la solución (ej. AsyncValue de Riverpod) — no indicadores booleanos (isLoading, isError, hasData)
  • Cada operación asíncrona modela los estados de carga, éxito y error como estados distintos
  • Todas las variantes de estado se manejan de forma exhaustiva en la UI — sin casos ignorados silenciosamente
  • Los estados de error llevan información de error para mostrar; los estados de carga no llevan datos obsoletos
  • Los datos anulables no se utilizan como indicador de carga — los estados son explícitos
// MAL — la sopa de indicadores booleanos permite estados imposibles
class UserState {
  bool isLoading = false;
  bool hasError = false; // ¡isLoading && hasError es representable!
  User? user;
}

// BIEN (enfoque inmutable) — los tipos sellados hacen que los estados imposibles no sean representables
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);
}

// BIEN (enfoque reactivo) — enumeración observable + datos, mutaciones a través de API de reactividad
// enum UserStatus { initial, loading, loaded, error }
// Usa el observable/signal de tu solución para envolver estado y datos por separado

Optimización de reconstrucción:

  • Los widgets consumidores de estado (Builder, Consumer, Observer, Obx, Watch, etc.) se limitan al alcance más estrecho posible
  • Se utilizan selectores para reconstruir solo cuando cambian campos específicos — no en cada emisión de estado
  • Se utilizan widgets const para detener la propagación de reconstrucción a través del árbol
  • El estado computado/derivado se calcula de forma reactiva, no se almacena de forma redundante

Suscripciones y eliminación:

  • Todas las suscripciones manuales (.listen()) se cancelan en dispose() / close()
  • Los controladores de flujo se cierran cuando ya no son necesarios
  • Los temporizadores se cancelan en el ciclo de vida de eliminación
  • Se prefiere el ciclo de vida administrado por el marco sobre la suscripción manual (constructores declarativos sobre .listen())
  • Verificación de mounted antes de setState en callbacks asíncronos
  • No se usa BuildContext después de await sin verificar context.mounted (Flutter 3.7+) — el contexto obsoleto causa fallos
  • Sin navegación, diálogos o mensajes de scaffold después de brechas asíncronas sin verificar que el widget todavía esté montado
  • BuildContext nunca se almacena en singletons, gestores de estado o campos estáticos

Estado local vs global:

  • El estado de UI efímero (checkbox, slider, animación) utiliza estado local (setState, ValueNotifier)
  • El estado compartido se eleva solo tan alto como sea necesario — no se globaliza en exceso
  • El estado específico de una característica se elimina adecuadamente cuando la característica ya no está activa

5. Rendimiento

Reconstrucciones innecesarias:

  • No se llama a setState() al nivel del widget raíz — localiza los cambios de estado
  • Se utilizan widgets const para detener la propagación de reconstrucción
  • Se utiliza RepaintBoundary alrededor de subárboles complejos que se repintan independientemente
  • El parámetro child de AnimatedBuilder se utiliza para subárboles independientes de la animación

Operaciones costosas en build():

  • Sin ordenamiento, filtrado o mapeo de colecciones grandes en build() — calcula en la capa de gestión de estado
  • Sin compilación de regex en build()
  • El uso de MediaQuery.of(context) es específico (ej., MediaQuery.sizeOf(context))

Optimización de imágenes:

  • Las imágenes de red utilizan caché (cualquier solución de caché apropiada para el proyecto)
  • Resolución de imagen apropiada para el dispositivo de destino (sin cargar imágenes 4K para miniaturas)
  • Image.asset con cacheWidth/cacheHeight para decodificar al tamaño de visualización
  • Se proporcionan widgets de marcador de posición y error para imágenes de red

Carga diferida:

  • Se utiliza ListView.builder / GridView.builder en lugar de ListView(children: [...]) para listas grandes o dinámicas (los constructores concretos están bien para listas pequeñas y estáticas)
  • Se implementa la paginación para conjuntos de datos grandes
  • Se utiliza la carga diferida (deferred as) para librerías pesadas en compilaciones web

Otros:

  • Se evita el widget Opacity en animaciones — utiliza AnimatedOpacity o FadeTransition
  • Se evita el recorte en animaciones — recorta las imágenes de antemano
  • No se anula operator == en widgets — utiliza constructores const en su lugar
  • Los widgets de dimensiones intrínsecas (IntrinsicHeight, IntrinsicWidth) se utilizan con moderación (pase de diseño adicional)

6. Pruebas

Tipos de prueba y expectativas:

  • Pruebas unitarias: Cubren toda la lógica de negocio (gestores de estado, repositorios, funciones de utilidad)
  • Pruebas de widgets: Cubren el comportamiento individual de los widgets, las interacciones y la salida visual
  • Pruebas de integración: Cubren flujos de usuario críticos de principio a fin
  • Pruebas golden: Comparaciones de píxeles perfectos para componentes de UI críticos para el diseño

Objetivos de cobertura:

  • Apunta a una cobertura de línea del 80%+ en la lógica de negocio
  • Todas las transiciones de estado tienen pruebas correspondientes (carga → éxito, carga → error, reintento, etc.)
  • Casos límite probados: estados vacíos, estados de error, estados de carga, valores límite

Aislamiento de pruebas:

  • Las dependencias externas (clientes de API, bases de datos, servicios) se simulan o falsifican
  • Cada archivo de prueba prueba exactamente una clase/unidad
  • Las pruebas verifican el comportamiento, no los detalles de implementación
  • Los stubs definen solo el comportamiento necesario para cada prueba (stubbing mínimo)
  • Sin estado mutable compartido entre casos de prueba

Calidad de las pruebas de widgets:

  • pumpWidget y pump se utilizan correctamente para operaciones asíncronas
  • find.byType, find.text, find.byKey se utilizan adecuadamente
  • Sin pruebas inestables que dependan del tiempo — utiliza pumpAndSettle o pump(Duration) explícito
  • Las pruebas se ejecutan en CI y los fallos bloquean las fusiones

7. Accesibilidad

Widgets semánticos:

  • El widget Semantics se utiliza para proporcionar etiquetas de lector de pantalla donde las etiquetas automáticas son insuficientes
  • ExcludeSemantics se utiliza para elementos puramente decorativos
  • MergeSemantics se utiliza para combinar widgets relacionados en un único elemento accesible
  • Las imágenes tienen la propiedad semanticLabel configurada

Soporte de lector de pantalla:

  • Todos los elementos interactivos son enfocables y tienen descripciones significativas
  • El orden de enfoque es lógico (sigue el orden de lectura visual)

Accesibilidad visual:

  • Relación de contraste >= 4.5:1 para texto contra fondo
  • Los objetivos táctiles tienen al menos 48x48 píxeles
  • El color no es el único indicador de estado (utiliza iconos/texto junto a él)
  • El texto escala con la configuración del tamaño de fuente del sistema

Accesibilidad de interacción:

  • Sin callbacks onPressed sin operación — cada botón hace algo o está deshabilitado
  • Los campos de error sugieren correcciones
  • El contexto no cambia inesperadamente mientras el usuario está ingresando datos

8. Preocupaciones Específicas de la Plataforma

Diferencias iOS/Android:

  • Se utilizan widgets adaptativos de plataforma cuando corresponde
  • La navegación hacia atrás se maneja correctamente (botón de retroceso de Android, deslizar hacia atrás en iOS)
  • La barra de estado y el área segura se manejan mediante el widget SafeArea
  • Los permisos específicos de la plataforma se declaran en AndroidManifest.xml e Info.plist

Diseño responsivo:

  • Se utiliza LayoutBuilder o MediaQuery para diseños responsivos
  • Los puntos de interrupción se definen de manera consistente (teléfono, tableta, escritorio)
  • El texto no se desborda en pantallas pequeñas — utiliza Flexible, Expanded, FittedBox
  • La orientación horizontal se prueba o se bloquea explícitamente
  • Específico de web: se admiten interacciones de mouse/teclado, hay estados de hover presentes

9. Seguridad

Almacenamiento seguro:

  • Los datos sensibles

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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

Skills relacionados