Future[Either[AppError, Option[User]]] in Scala
functional-programming, scala
Solution
Let's have a look at the solution space:
Success(Right(Some(user))) => Everythig OK, got an user
Success(Right(None)) => Everything OK, no user
Success(Left(AppError)) => Something went wrong at app level
Failure(Exception) => Something went wrong
This looks very expressive, but things get ugly fast when you try to compose such nested structure with other calls (see Converting blocking code to using scala futures) for an example of composing`Future[Option[T]]`)
So following the principle of the least power, we ask ourselves: Are there less complex alternatives that preserve the semantics? One could argue that `Future[User]` could be sufficient if we make use of the full potential of exception (and exception hierarchies).
Let's check:
Everythig OK, got an user => Success(user)
Everything OK, no user => Failure(UserNotFoundException) (Application level exception)
Something went wrong at app level => Failure(AppException) (Application level exception)
Something went wrong => Failure(Exception) (System-level exception)
The only limitation of this approach is that the users of the API will need to be aware of the Exceptions, which is not self-documented in the interface. The upper-hand is that having an API based on `Future`s will allow expressive monadic compositions with other `Future`-based APIs.
Problem
As mentioned in the title, does it make sense to use such data structure? Let me explain one by one: - Future - to represent async computation - Either - to communicate known errors - Option - to communicate that the value may not be present I am a little bit scared when looking at this. Is it a good practice to use such type combination?