Flutter: Manejo de estados para entidades

¿Qué es una entidad?
Una entidad es un concepto o cosa que tiene una identidad única y representa algo significativo en el dominio del problema o sistema que se está modelando o construyendo. Según DDD (Diseño Orientado al Dominio): Una entidad es un objeto que tiene una identidad que abarca tiempo y diferentes estados. Es fundamental en DDD distinguir entre entidades y objetos de valor. Las entidades tienen una identidad única (como un ID o número de serie), mientras que los objetos de valor se identifican por sus atributos.
¿Por qué usar manejo de estados en aplicaciones Flutter?
El manejo de estados en aplicaciones Flutter es esencial para manejar eficientemente la naturaleza dinámica de las interfaces de usuario. A medida que las aplicaciones crecen en complejidad, rastrear y actualizar el estado de varios componentes puede volverse desafiante. Las soluciones de gestión del estado proporcionan una forma estructurada de manejar esta complejidad, asegurando que la aplicación siga siendo responsiva y que la experiencia del usuario sea coherente. Además, el uso de herramientas de manejo de estados puede llevar a un código más mantenible, ya que a menudo fomentan la separación de concerns, facilitando a los desarrolladores entender, depurar y extender la aplicación con el tiempo.
Un framework para el Desarrollo Orientado al Estado (SDD):
El problema con el Desarrollo de UI Tradicional es que erróneamente se considera que el estado de una aplicación es un mero efecto secundario de las acciones dentro de la aplicación. El Desarrollo Orientado al Estado (SDD) enfatiza la importancia del estado de una aplicación en el proceso de desarrollo. Necesitamos un framework (o biblioteca) para manejar este problema con un enfoque State-first.
El paquete Spread ofrece una forma simplificada de gestionar el estado dentro de las aplicaciones Flutter. Con el uso de entidades, suscriptores y emisores de estado, los desarrolladores pueden almacenar, observar y manipular estados fácilmente sin el código repetitivo habitual.
Beneficios del SDD:
- Carga cognitiva reducida: Al centrarse en el estado, los desarrolladores pueden pensar en estados de aplicación individuales de forma aislada, asegurando que los cambios en un estado no afecten inesperadamente a otro.
- Facilidad de prueba: Con caminos bien definidos a través de la aplicación, las pruebas de instantáneas se vuelven sencillas. La clara distinción de estados simplifica el proceso de prueba.
- Facilidad de documentación visual: El enfoque compartimentado del SDD facilita la representación visual del flujo y comportamiento de la aplicación.
- Vínculos estrechos con el Desarrollo Orientado al Comportamiento (BDD): SDD se alinea con las técnicas de BDD, enfatizando los comportamientos de la aplicación mapeados a través del estado y las acciones.
Implementando la gestión del estado para entidades:
- Crea tu entidad:
import 'package:spread/spread.dart';
class User implements Entity {
final int id;
final String name;
final List<UserPost> posts = List.empty(growable: true);
// constructor
User({required this.id, required this.name});
// an Entity must provide an entityId getter.
@override
String get entityId => id.toString();
}
El paquete Spread proporciona un contrato (interfaz) para Entidades: todas las Entidades deben proporcionar un getter entityId.
2. Crea un Widget para mostrar tu entidad:
import 'package:flutter/material.dart';
import 'package:spread/spread.dart';
import 'user.dart';
class UserItem extends StatelessWidget {
final User user;
const UserItem({super.key, required this.user});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(user.id.toString()),
subtitle: Row(
children: [
Text(user.name.toString()),
const SizedBox(width: 10),
Spread<User>(
entity: user,
stateCondition: (User? entity) => entity!.posts.length.isEven,
builder: (BuildContext context, User? entity) {
return Text('- posts: ${entity!.posts.length.toString()}');
})
],
));
}
}
En este ejemplo, el Widget UserItem muestra propiedades del usuario como id, nombre y contador de publicaciones. El contador de publicaciones es la única propiedad actualizada en tiempo real. Usamos el Widget Spread para manejar las actualizaciones de la UI cuando se emite un Usuario (como estado) con un ID específico (entidad). Nota que el Widget Spread está parametrizado con la clase “User” y el argumento “entity” del constructor se establece con el objeto user (la Entidad). El Widget Spread puede obtener el ID de la entidad y suscribirse a cambios en un objeto User con ese ID de entidad (porque la clase User implementa la interfaz Entity). Cuando se emite un objeto User con el mismo ID de entidad, el Widget Spread evalúa la función stateCondition y si es verdadera, invoca la función builder y actualiza la UI.
3. Emite tu entidad:
import 'package:spread/spread.dart';
import 'user.dart';
class RefreshUserPosts with StateEmitter implements UseCase {
final User user;
RefreshUserPosts(this.user);
@override
void execute() async {
emitEntity<User>(user);
}
}
En este ejemplo, tenemos un caso de uso (UseCase) combinado con el mixin StateEmitter. Un mixin en Dart es una forma de reutilizar el código de una clase en múltiples jerarquías de clases sin necesidad de herencia. EL mixin StateEmitter proporciona un conjunto de funciones para emitir estados:
- emitNamed(name, state) para estados con nombre
- emit<T>(state) para estados tipados.
- emitEntity<E>(entity) para estados de entidad.
El método execute es proporcionado por la interfaz UseCase. Una vez que se emite el estado, todos los suscriptores de ese estado recibirán el estado emitido.
Conclusión:
El manejo de estados en aplicaciones Flutter es una herramienta esencial para manejar la dinámica cambiante de las interfaces de usuario. A medida que las aplicaciones se vuelven más complejas, es imperativo tener un sistema robusto que permita rastrear y actualizar el estado de los componentes de manera eficiente. El enfoque de Desarrollo Orientado al Estado (SDD) y el paquete Spread ofrecen soluciones simplificadas para este desafío, poniendo énfasis en la importancia del estado en el proceso de desarrollo. Al adoptar estas prácticas y herramientas, los desarrolladores no solo pueden mejorar la reactividad y consistencia de sus aplicaciones, sino también reducir la carga cognitiva, facilitar las pruebas y mejorar la mantenibilidad del código. En resumen, para construir aplicaciones Flutter escalables y de alto rendimiento, es crucial adoptar una estrategia de gestión del estado efectiva y bien estructurada.