Linting y analysis_options en Flutter: ejercicio resuelto
Linting y analysis_options en Flutter: ejercicio resuelto
El analizador estático de Dart detecta errores, malas prácticas y código muerto antes de ejecutar la app. Un analysis_options.yaml bien configurado es la primera línea de defensa de calidad en cualquier proyecto profesional.
Enunciado
Configura analysis_options.yaml con:
Las reglas de flutter_lints como base.
Reglas adicionales de producción (prefer_final, avoid_print, etc.).
Errores de análisis tratados como errores de compilación.
Exclusiones para código generado.
Luego corrige los warnings más comunes en código Dart real.
Dependencias
1
2
3
4
dev_dependencies:flutter_lints:^5.0.0# Alternativa más estricta (opcional):# very_good_analysis: ^7.0.0
# analysis_options.yaml (en la raíz del proyecto)include:package:flutter_lints/flutter.yamlanalyzer:# Tratar warnings como errores (recomendado en CI)errors:invalid_annotation_target:ignore # necesario con Freezedmissing_required_param:errordead_code:warningunused_import:errorunused_local_variable:warningexclude:- "**/*.g.dart"# generado por build_runner / json_serializable- "**/*.freezed.dart"# generado por Freezed- "lib/generated/**"# i18n generado- "test/.test_coverage.dart"linter:rules:# ── Calidad de código ──────────────────────────────────────────────────prefer_final_locals:true# var → final cuando no se reasignaprefer_final_fields:true# campos inmutables → finalprefer_const_constructors:true# usa const donde sea posibleprefer_const_literals_to_create_immutables:trueunnecessary_const:trueunnecessary_new:true# ── Seguridad y bugs ───────────────────────────────────────────────────avoid_print:true# usa debugPrint o un loggeravoid_dynamic_calls:true# sin .call() en dynamicalways_use_package_imports:false# relativo OK en mismo packagecancel_subscriptions:true# StreamSubscription.cancel()close_sinks:true# Sink.close()unawaited_futures:true# await todas las Futures relevantes# ── Estilo ────────────────────────────────────────────────────────────directives_ordering:true# imports ordenadossort_pub_dependencies:false# pub.dev los ordena automáticamentelines_longer_than_80_chars:false# Dart fmt ya lo gestionaflutter_style_todos: true # TODO(nombre):descripción# ── Nulabilidad ───────────────────────────────────────────────────────prefer_null_aware_operators:trueavoid_null_checks_in_equality_operators:truenull_closures:true# ── Rendimiento ───────────────────────────────────────────────────────avoid_unnecessary_containers:true# sin Container innecesariouse_colored_box:true# Container(color:) → ColoredBoxuse_decorated_box:true# Container(decoration:) → DecoratedBox
Ejemplos: código con warning y su corrección
1. avoid_print
1
2
3
4
5
6
7
8
9
// ❌ Warning: avoid_print
voidfetchData(){print('Cargando datos...');}// ✅ Correcto
voidfetchData(){debugPrint('Cargando datos...');// solo en debug mode
}
2. prefer_final_locals
1
2
3
4
5
6
7
8
9
10
11
12
13
// ❌ Warning: prefer_final_locals
voidprocessUser(Map<String,dynamic>json){varname=json['name']asString;// name nunca se reasigna
varage=json['age']asint;debugPrint('$name, $age');}// ✅ Correcto
voidprocessUser(Map<String,dynamic>json){finalname=json['name']asString;finalage=json['age']asint;debugPrint('$name, $age');}
3. use_colored_box
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ❌ Warning: use_colored_box
Widgetbuild(BuildContextcontext){returnContainer(color:Colors.red,child:constText('Hola'),);}// ✅ Correcto (más eficiente, sin capa de layout extra)
Widgetbuild(BuildContextcontext){returnconstColoredBox(color:Colors.red,child:Text('Hola'),);}
4. unawaited_futures
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ❌ Warning: unawaited_futures
voidonButtonTap(){saveToDatabase();// Future no esperado
}// ✅ Correcto
Future<void>onButtonTap()async{awaitsaveToDatabase();}// ✅ Alternativa si es intencionado:
voidonButtonTap(){unawaited(saveToDatabase());// import 'dart:async'
}
very_good_analysis es más estricto que flutter_lints y activa ~200 reglas. Es la opción que usa Very Good Ventures en proyectos de producción. Si estás arrancando un proyecto nuevo con estándares altos, empieza con él:
Ignorar todos los warnings con // ignore:: los ignore inline deberían ser la excepción, no la regla. Si un warning aparece en muchos sitios, evalúa si la regla es apropiada para tu proyecto y ajusta analysis_options.yaml.
No excluir archivos generados: *.g.dart y *.freezed.dart generan cientos de warnings falsos si no se excluyen.
Añadir --fatal-warnings en CI sin limpiar warnings primero: el pipeline falla desde el primer commit. Fija todos los warnings antes de activarlo.
Aplicación práctica
Un proyecto con linting estricto desde el día 1 detecta bugs antes de que lleguen a review, estandariza el estilo sin debates en PR y hace el onboarding más rápido porque el código es predecible.
No. El análisis es estático y corre en paralelo al compilador. No impacta el tiempo de flutter run ni de flutter build.
¿Puedo desactivar una regla solo para un archivo?
Sí. Añade al inicio del archivo:
1
//ignore_for_file:avoid_print
O en una línea concreta:
1
print('debug');//ignore:avoid_print
¿dart fix --apply es seguro?
Para la mayoría de correcciones automáticas sí — son equivalencias de código probadas. Revisa siempre el diff antes de hacer commit, especialmente en proyectos grandes.