El código de Flutter que me niego a escribir más (y mis alternativas más limpias)

Harsh Mittal

Harsh Mittal.13 de julio de 2025. MEDIUM

Siendo sincero, mi código inicial de Flutter era un desastre .
Hice lo que la mayoría: lo escribí todo yo mismo, intenté controlarlo todo y terminé manteniendo un código espagueti. 🙈

Pero con el tiempo (y mucha refactorización), comencé a tratar mi código base de Flutter como un producto: modular, legible y optimizado para la cordura.

A continuación, un vistazo al código que ya no escribo , lo que uso en su lugar y por qué hice el cambio (con lecciones aprendidas con esfuerzo).

1️⃣ ❌ Conexión manual de varios campos de texto OTP

✅ Cambiado a:pinput

campo_de_texto_de_entrada_pin | Paquete Flutter

Un widget de campo de texto que ayuda a mostrar diferentes estilos de pin escritos en Dart puro, sin dependencias adicionales.

pub.dev

Entonces (Yo vs 50 líneas de texto repetitivo):

Fila ( 
hijos : Lista.generar ( 6 , (índice) { devolver Expandido ( hijo : CampoDeTexto ( controlador : controladores[índice], NodoDeFoco : NodosDeFoco[índice], LongitudMáxima : 1 , ), ); }), ) ;







😵 Concéntrate en saltar pesadillas, sin animación incorporada, sin estilos de error, solo un gran bloque de dolor manual.

Ahora (1 línea de felicidad):

Pinput ( 
longitud : 6 ,
onCompleted : (pin) => imprimir (pin),
)

💡Por qué me cambié : se ve mejor, se siente mejor, maneja casos extremos y me permite concentrarme en la lógica empresarial, no en reinventar el teclado.

2️⃣ ❌ Creación manual de formularios conTextEditingController

✅ Cambiado a:flutter_form_builder

flutter_form_builder | Paquete Flutter

Este paquete ayuda en la creación de formularios en Flutter eliminando el código repetitivo, reutilizando la validación y reaccionando…

pub.dev

En el pasado, mi lógica de formulario se veía así:

final_emailController = TextEditingController ();
TextFormField( 
controlador: _emailController,
validador: (valor) {
si (!valor!.contiene('@')) devuelve 'Correo electrónico no válido';
devuelve nulo;
},
)

¿Problemas?

  • El infierno del controlador
  • Validación manual
  • Pesadilla a escala

Ahora:

FormBuilderTextField ( 
nombre : 'email' ,
validador : FormBuilderValidators.email ( ),
)

💡Por qué me cambié : validadores integrados, sin código repetitivo de controlador y mucho más fácil de escalar para formularios grandes.

3️⃣ ❌ setState()En todas partes

✅ Cambiado a: Provider+ ViewModels estilo MVVM

Cuando no me importaba la arquitectura, esto era común:

TextField ( 
onChanged : (valor) {
setState (() {
nombre = valor;
});
},
)

🛑 Problemas:

  • Lógica pegada a la interfaz de usuario
  • No se puede reutilizar ni probar
  • Se siente sucio en aplicaciones grandes.

Ahora:

clase  UserViewModel  extiende  ChangeNotifier { 
String nombre = '' ;
void updateName ( String newName ) {
nombre = newName;
notifyListeners ();
}
}

En la interfaz de usuario:

Campo de texto ( 
onChanged: context.read<UserViewModel>() .updateName ,
)

💡 Por qué me cambié : Este patrón escala. Puedes probar el ViewModel, reutilizarlo y mantener tus widgets simples (como deberían ser).

4️⃣ ❌ Análisis manual de JSON

✅ Cambiado a:json_serializable

Si tuviera un dólar por cada vez que escribí esto:

fábrica Usuario . fromJson ( Map < String , dynamic> json ) { 
return Usuario (
nombre : json[ 'nombre' ],
edad : json[ 'edad' ],
);
}

😤 Repetitivo, frágil y propenso a errores a medida que tus modelos crecen.

Ahora:

@JsonSerializable() 
clase Usuario {
final String nombre;
final int edad;
  fábrica User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); 
Map<String, dynamic> toJson() => _$UserToJson(this);
}

💡 Por qué me cambié : Confío más en la generación de código que en mi velocidad de escritura. Además, es más limpio y está preparado para el futuro.

5️⃣ ❌ Uso MediaQuerypara cualquier diseño adaptable

✅ Cambiado a: LayoutBuildercon puntos de interrupción

Antes hice:

si (MediaQuery.of(contexto).size.width < 600 ) { 
devolver Columna(...);
} de lo contrario {
devolver Fila(...);
}

Funcionó. Hasta que dejó de funcionar.

😓 Los diseños se rompieron, la lógica se dispersó y los ajustes de respuesta se convirtieron en un desastre.

Ahora:

LayoutBuilder ( 
constructor: (contexto, restricciones) {
devolver restricciones .maxWidth < 600
? MobileLayout ()
: DesktopLayout ();
},
)

💡 Por qué me mudé : Un solo lugar para la lógica del diseño. Mucho más fácil de gestionar en pantallas más grandes.

6️⃣ ❌ Llamar a las API directamente dentro de los widgets

✅ Cambiado a: Capa de servicio API + ViewModel

Sí, solía hacer esto:

FutureBuilder ( 
futuro : http.get ( Uri.parse ( ' https://api.com/data' )),
constructor : (contexto, instantánea) => ...
);

⛔ La interfaz de usuario se integró con la lógica de la API. No se pudo reutilizar. No se pudo reintentar. No se pudo separar.

Ahora:

clase  ApiService  {
Future< Lista <Elemento>> fetchItems() async {respuesta
final = await http.get( Uri.parse ( 'URL de la API' ) ); return parseItems(response.body); }} clase ItemsViewModel extiende ChangeNotifier { ApiService final _apiService; Lista <Elemento> elementos = []; Future< void > loadItems() async { elementos = await _apiService.fetchItems(); notifyListeners(); }}











💡Por qué me cambié : Mejor arquitectura, interfaz de usuario más limpia, más control sobre estados de error, reintentos y almacenamiento en caché.

🚀 Palabras finales: El código que no escribes importa

A medida que maduré como desarrollador, aprendí esto:

No te pagan por escribir código. Te pagan por resolver problemas. Cuanto menos código, mejor, si logras más.

Ya no busco código ingenioso. Busco código limpio.
Reutilizable. Mantenible. Probable. ¿Y, sinceramente? Simplemente menos agotador.

💬 Tu turno

¿Cuál fue el peor código de Flutter que solías escribir pero que luego descartaste?

Déjalo en los comentarios: ayudemos al próximo desarrollador a evitar el dolor. 😅

🔗 Mantengámonos en contacto

Comparto prácticas reales de Flutter, patrones de arquitectura, configuraciones REST/Firebase y cómo administro aplicaciones de clientes reales, no solo tutoriales.

Comparte en tus perfiles

Facebook
Twitter
LinkedIn

Artículos Relacionados:

No culpes a la lluvia

Por Ambiente: situación y retos Pablo Kaplún H.. Agosto 25, 2025. El Nacional Por ONG Clima 21 En Venezuela, se estima que este año las lluvias y desbordamientos de ríos han afectado de 250.000 a 300.000 personas*. No podemos culpar a la lluvia, ni al cambio climático por estos desastres. En parte, esta situación forma parte de

Seguir leyendo »

Adam Smith a los 250 años

Michael Spence. 18 de agosto de 2025. Project Syndicate Hace casi 250 años, Adam Smith identificó dos posibles limitaciones a la especialización económica: la «extensión del mercado» y los riesgos inevitables. Hoy en día, la restricción del riesgo se está demostrando más poderosa, y ha surgido otro desafío, aún más fundamental, al modelo de especialización

Seguir leyendo »