Hay errores que aparecen siempre en el mismo sitio y son fáciles de reproducir, y hay errores que aparecen de vez en cuando, sin un patrón claro, y que desaparecen antes de que nadie consiga capturarlos. Estos últimos son los más peligrosos, porque dan la sensación de que el problema se ha resuelto solo, cuando en realidad sigue ahí, esperando el momento menos oportuno para volver a aparecer. Esto es justo lo que le ocurría a uno de nuestros clientes del sector transportes, y en SETDEVELOPERS lo resolvimos migrando su aplicación a Nuestro Framework.

 

Necesidad inicial

Cero margen de error en un servicio esencial

El cliente ofrece un servicio en el sector transportes a través de una aplicación móvil, un contexto donde un fallo no es simplemente una molestia: puede significar que un usuario no llegue a tiempo a su destino o que una operación crítica del negocio se vea interrumpida. La necesidad era clara: eliminar los errores no controlados que aparecían de forma intermitente y conseguir que la aplicación se comportara de forma predecible en cualquier circunstancia.

 

App en Flutter que falla en situaciones no controladas

blank

Errores que aparecían sin patrón aparente

La aplicación estaba desarrollada en Flutter y, en líneas generales, funcionaba correctamente. El problema surgía en situaciones muy concretas y difíciles de reproducir: momentos en los que varias partes de la aplicación intentaban modificar el mismo dato al mismo tiempo, o en los que una acción del usuario llegaba antes de que la respuesta de una acción anterior hubiera terminado de procesarse.

El origen: un estado de la aplicación impredecible

La causa raíz era la forma en que la aplicación gestionaba su propio estado. Sin una estructura clara que controlara cómo y cuándo podía modificarse cada dato, distintas partes del código competían entre sí por actualizar la misma información, generando condiciones de carrera. El resultado eran errores de concurrencia que no dependían del código en sí, sino del orden exacto en el que ocurrían ciertos eventos, lo que los hacía casi imposibles de depurar con los métodos tradicionales.

 

Arquitectura de la solución para evitar errores de concurrencia

Migrar a un modelo de estado centralizado y predecible

La solución pasaba por sustituir la gestión de estado dispersa por un modelo centralizado en el que cualquier modificación siguiera siempre el mismo camino, sin excepciones. Migramos la aplicación a Nuestro Framework, que en su capa de gestión de datos utiliza Redux como patrón central de arquitectura.

Un único punto de verdad para todo el estado de la app

Con Redux, todo el estado de la aplicación vive en un único almacén central, y la única forma de modificarlo es a través de acciones que se procesan de forma estrictamente ordenada, una detrás de otra. Ninguna parte de la aplicación puede modificar el estado directamente ni saltarse este proceso, lo que elimina de raíz la posibilidad de que dos actualizaciones compitan entre sí por el mismo dato.

 

Detalle de la implementación de Nuestro Framework para conseguir que el estado de la aplicación sea predecible

blank

Flujo de datos unidireccional

Nuestro Framework implementa un flujo de datos estrictamente unidireccional: una acción se despacha, un reducer calcula el nuevo estado a partir del estado anterior, y la interfaz se actualiza en consecuencia. Nunca ocurre en sentido contrario, y nunca hay dos actualizaciones procesándose de forma simultánea. Esto convierte cada cambio de estado en un evento completamente determinista y reproducible.

Separación de responsabilidades con Arquitectura Hexagonal

Además de Redux, el Framework aplica Arquitectura Hexagonal para separar la lógica de negocio de los detalles de infraestructura y de interfaz. Esto significa que la lógica que decide cómo debe reaccionar la aplicación ante un evento queda completamente aislada de cómo se muestra esa información en pantalla, facilitando enormemente la localización de cualquier comportamiento inesperado.

Errores no controlados convertidos en errores tratables

Al ser el estado completamente predecible, cualquier error que se produzca deja de ser un misterio intermitente y se convierte en un evento que se puede capturar, registrar y tratar de forma explícita. El equipo pasa de perseguir fallos fantasma a poder anticiparlos y gestionarlos como parte normal del flujo de la aplicación.

 

Ventajas de la implementación de Nuestro Framework en apps

Estabilidad real en producción

La principal ventaja para el cliente fue la desaparición de los errores intermitentes que antes afectaban al servicio. Al eliminar las condiciones de carrera en la gestión del estado, la aplicación se comporta de la misma forma cada vez, independientemente del orden en que lleguen los eventos o de cuántas acciones se disparen de forma casi simultánea. Para un servicio del sector transportes, donde la aplicación debe responder con fiabilidad en cualquier momento del día, esta estabilidad se traduce directamente en confianza por parte de los usuarios finales.

Depuración más rápida y sencilla

Cuando surge cualquier incidencia, el equipo puede reproducirla con precisión gracias al flujo de datos determinista de Redux, en lugar de intentar adivinar qué combinación exacta de eventos la provocó. Antes de la migración, un error intermitente podía requerir horas de intentos fallidos por reproducirlo; ahora, al conocer exactamente la secuencia de acciones y el estado resultante en cada paso, localizar la causa raíz es una cuestión de minutos. Esto reduce drásticamente el tiempo dedicado a depurar problemas complejos y libera al equipo para centrarse en construir nuevas funcionalidades.

Una base de código más mantenible a largo plazo

La separación de responsabilidades que aporta la Arquitectura Hexagonal, junto con el cumplimiento de los principios SOLID en todo el Framework, facilita que el equipo pueda añadir nuevas funcionalidades sin arriesgarse a introducir nuevos efectos secundarios inesperados en otras partes de la aplicación. Cada pieza del sistema tiene una responsabilidad clara y delimitada, de modo que modificar la lógica de negocio no obliga a tocar la capa de presentación ni viceversa.

Un estándar que se replica en cualquier proyecto

Al estar implementado de forma idéntica en Flutter, Dotnet C#, NodeJS Typescript y Python, migrar esta aplicación a Nuestro Framework no solo resolvió el problema puntual del cliente, sino que la dejó alineada con el mismo estándar de calidad que aplicamos en el resto de nuestros proyectos. Cualquier desarrollador del equipo, independientemente de la tecnología en la que esté más especializado, puede entender y contribuir a la aplicación sin tener que aprender un patrón de arquitectura distinto para cada proyecto.
Si tu aplicación sufre errores intermitentes que nadie consigue reproducir con seguridad, cuéntanos tu proyecto y analizamos juntos cómo devolverle la estabilidad que necesita.