Reportar cada error de validación
Requisito
Cinco formularios de registro del lote 2026-08 se comprueban contra
tres reglas (nombre presente, email con @, edad 18+). Un
formulario puede romper varias reglas — reporta cada
regla rota por formulario, y luego lista los formularios que pasaron.
Los datos están en el código; las dos versiones deben imprimir las
líneas que aparecen bajo Salida esperada.
Salida esperada
form #2: name is required; email is malformed; must be 18 or older form #4: email is malformed form #5: name is required; must be 18 or older valid: ana, cy
Lado a lado
RxDart
FxDart
Por qué difieren
La validación acumulativa es el trabajo que el canal de errores de Rx
es estructuralmente incapaz de hacer. Un error de stream lleva
exactamente un objeto, y emitirlo termina el stream — lanza la
primera regla rota y ni los demás fallos de ese formulario ni los
formularios restantes se verán jamás. Cada operador de recuperación
(onErrorReturn, onErrorResumeNext) está
construido para esa forma de un-error-y-fin. Así que la versión
RxDart funcional que se muestra aquí abandona en silencio el canal de
errores: mapea cada formulario a un registro de sus fallos en el
canal de datos — y llegados a ese punto el stream aporta un
main async y un toList, nada más.
El lado FxDart es la misma idea sin el envoltorio: los errores son
valores llanos, así que un map + partition
síncronos entregan los formularios fallidos (con todos sus
errores) y los válidos en una sola expresión. Y como FxDart trata los
errores como valores en todas partes, este patrón escala más allá de
los registros: la capa de errores tipados acumula por ti —
zipOrAccumulate ejecuta cada regla y concatena los
fallos en una NonEmptyList, y
mapOrAccumulate valida una colección entera fail-slow.
Mira el tutorial de accumulate para esa versión
completa; el modelo de streams no tiene contrapartida a la que
recurrir.
Benchmark
N = 100
Tiempo Empate
Memoria pico Gana RxDart
N = 1,000,000
Tiempo Gana FxDart
Memoria pico Gana RxDart
Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.