DEV Community

Cover image for Either vs Try (vs Result)
Ivan Lorenz for Adevinta Spain

Posted on • Updated on

Either vs Try (vs Result)

Preguntas y respuestas sobre las sesiones live coding de Arrow.

La siguiente pregunta fue realizada durante la segunda sesión. Os dejamos también el enlace directo a la discusión en Github.

Pregunta

Para captura de excepciones presentasteis Either<L,R>. Arrow incluye Try<T> y la librería standard de Kotlin incluye Result<T>.

Arrow ya tiene Try marcada como deprecated porque no se alinea del todo con los principios de programación (paradigma?) que promueve Arrow.

La lib estándar de Kotlin incluye Result que parece una mezcla de Try y Option. Tampoco es demasiado limpio en mi opinión.

Hoy (en relación al 23 de septiembre) Alex Nedelcu ha hecho una twitter poll (ligeramente) relacionada con este tema.

Podrías desarrollar los pros/cons de usar Either en comparación con las otras opciones que existen?

Respuesta

Primero déjame establecer el contexto de nuestra respuesta, porque sin un contexto no hay explicación que se sostenga. En mi equipo en @adevintaeng desarrollamos aplicaciones distribuidas con Kotlin. Hemos encontrado valor en usar métodos monádicos en programación OO. Nos interesa la componibilidad y la expresividad de tipos como Either<L,R> y los patrones de gestión de errores que facilita, cómo mostramos en esta segunda sesión. Desarrollando sistemas distribuidos sabemos que la gestión de errores, su diseño y su evolución, es la clave para crear aplicaciones resilientes y tolerantes al fallo.

En este contexto encontramos el uso de la librería Arrow Core un perfecto compañero de viaje. Parte del trabajo de un ingeniero de software es asegurarse que las librerías que utiliza van a ser una ayuda para acelerar el desarrollo a la vez que no van a representar un problema en el futuro, como librerías no mantenidas o sin una estrategia de evolución sólida y solvente. En cuanto empezamos a utilizar Arrow 0.13.2, el tipo Try<T> ya estaba obsoleto y eliminado desde la versión 0.11. Y el tipo Option<T> estaba siendo cuestionado por los mismos creadores de Arrow. Así que recomendaban el uso de Either<L,R> desde la versión 0.13.2 para garantizar la compatibilidad total con la primera versión general de Arrow 1.0.0.

Desde el punto de vista de un programador que utiliza la librería para sus aplicaciones en producción, esta debería ser una explicación suficiente para utilizar Either<L, R> frente a las otras opciones. Pero podemos elaborar más las razones.

Try<T> fue marcado cómo obsoleto en Arrow en el mismo momento que se decidió marcar cómo obsoleto IO monad y basar la estrategia de convertir las funciones con efectos laterales en funciones puras con el uso de Kotlin suspend. Marcando una función con suspend la ejecución de esa función devuelve una descripción del efecto, es decir el efecto no se produce si no la provees con un contexto, en este caso una Coroutine. Si quieres profundizar más en el porqué, aquí encontrarás el porque del cambio de estrategia.

Bien, que pasaba con Try<T>? El primer problema es que Try no podía diferir la ejecución del efecto de ningún modo y retornar únicamente una descripción del efecto porque sus constructores "evaluaban ansiosamente" - Dios, que difícil es intentar escribir en español sobre cualquier tema de ingeniería del software - a.k.a eager evaluation . Puedes ampliar detalles sobre los tipos de evaluación en Lazy, eager and greedy evaluation.

El segundo problema es que Try<T> no es seguro. Porqué? Básicamente porque puedes capturar cualquier Throwable que desees. Y si quieres tener control sobre una computación concurrente o paralela en la que se usa, no querrás que Try<T> pueda capturar InterruptedException o CancellationException entre otros.

Y éste es exactamente el mismo problema con Result<T> en Kotlin. De hecho, Result<T> es el tipo que se debe usar en vez de Try<T> para los caso de uso que así lo requieran.

Por todo esto, en Arrow se implementó Either.catch, que es el camino a seguir para aislar nuestro código de librerías "impuras".

En cuanto a Option<T> hubo bastante debate al respecto sobre si eliminar su uso en beneficio de un más idiomático - en Kotlin - Nullable types, porque se apreciaba poca aportación de valor sobre esto tipos. Además se indicaba que Option<T>no era más que (o si lo prefieres, es isomórfico a)

typealias Option<A> = Either<Unit, A>.

Pero después del largo debate @raulraja anunció que mantendrían Option<T> en Arrow Core 1.0.0 cómo así ha sido, porque existían algunos casos de uso en que todavía aportaba valor cómo con RxJava que declara Observable<T> y no permite null.

Cómo ves, muchas de las razones se basan en cuestiones de la programación funcional cómo lazy evaluation o en cómo convertir en declarativos los efectos laterales de una función y diferir su ejecución en un entorno seguro. Nosotros todavía no estamos utilizando Arrow Fx ni estamos marcando nuestras funciones cómo suspended, pero lo haremos si le encontramos valor para nuestros casos de usos y por supuesto, lo explicaremos en otras sesiones.

Espero que haya podido aclarar un poco tus dudas. Y no dudéis en matizar o corregir algún punto que no haya explicado con claridad o que mi memoria haya hecho desviar de la verdad. Obviamente, los que mejor pueden explicar esto son @raulraja , @47deg y los contributors del proyecto Arrow, a los que de paso, les doy las gracias por esta magnífica librería.

Ofertas Backend

Discussion (0)