As mentioned in the title, does it make sense to use such data structure? Let me explain one by one:
I am a little bit scared when looking at this. Is it a good practice to use such type combination?
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 composingFuture[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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With