Stop Using Result Wrappers In Your Reactive Return Types
Tags: android, androiddev, softwareengineering, mobile
Published: 2023-09-22 08:57:50

In modern day Android projects, it’s typical to see a Repository , UseCase or xyz abstract component exposing a business logic like

```kotlin
interface SomeRepository{

    fun getSomeData(): Flow<Result<List<Bruh>>>
}
```

Where Result looks something like this

```kotlin
sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Failure(val error: Error) : Result<Nothing>()
    data object Loading : Result<Nothing>() // This is a UI state, why would domain care about this anyway ? 
}
```

You’ll have some issues when you want to use this wrapper in your reactive return types, mainly

- You will write a lot of boilerplate checks ( where you ignore the cases except Success most of the time )

- Your return types become awkwardly long like and hard to read, like Flow<Result<List<FinallySomeData>>> — which I’ll use in examples to make it look even worst. Is there any worse ?

- Instead of a simple collection logic, you need to do a type check every single time you need a value.

- Reactive operations become cumbersome due to unnecessary when statements and such. Stop shooting yourself on the foot.

As a simple example, let’s compare two methods from each to see what we end up with. Imagine we have following class

```kotlin
interface FancyRepository {

    fun provideFoos(): Flow<Result<List<Foo>>>
    fun provideBars(): Flow<Result<List<Bar>>>
}
```

Oh boy, aren’t you in for a treat !? Let’s say you simply want to combine these two lists into some other data:

```kotlin
fun simpleCombineOperation(fancyRepository: FancyRepository): Result<List<Baz>> {
    fancyRepository
        .getFoos()
        .combine(fancyProvider.getBars()) { foo, bar ->
            when (foo) {
                is Result.Failure -> { /* Ignore or rethrow */}
                is Result.Loading -> { /* Extra line */}
                is Result.Success -> {
                    val foos = foo.data

                    // Time to check for bar !
                    when (bar) {
                        is Result.Failure -> { /* Keep ignoring or rethrowing */}
                        is Result.Loading -> { /* Yep, again */}
                        is Result.Success -> {
                            val bars = bar.data

                            // Oh my god finally I can do stuff with the data
                            // Now time to create a Result from result of results
                            val thingINeedtToProvide = Result.Success(...)
                            ...
                        }
                    }
                }
            }
        }
    }
}
```

Wow.. This code is even less maintainable if you’re on a business layer.

Imagine trying combine two UseCases that return Flow<Result<Data>. You need to check Result cases for both UseCases, then generate a new Result and then check that Result again on the UI layer. This paragraph is shorter than that.

Well, somebody has to maintain this !


![Sad :(](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yj9g7f6cd9xzc1suore.jpg)

Now let’s take a look how it is when we don’t wrap the objects

```kotlin
interface FancyRepository {

    fun provideFoos(): Flow<List<Foo>>
    fun provideBars(): Flow<List<Bar>>
}
```

How do you feel reading the following code ?

```kotlin
fun simpleCombineOperation(fancyRepository: FancyRepository) = 
    fancyRepository
        .getFoos()
        .combine(fancyProvider.getBars()) { foo, bar ->
             // Where's my wife ? (￣ω￣)
             foo + bar
        }
        .catch { /* Handle errors, or let the collector handle */ }
```

Try, fail, improve !

Don’t keep doing things that doesn’t make sense just because its mainstream or in official docs. It might be very well this stuff is useful in your project and business logic. But if it doesn’t, nuke it.

P.S. I’m writing another article about using Hexagonal Architecture in android, and wrote this shorty since it didn’t seem like the right place to explain it.

Follow me on twitter where I randomly tweet my awkward ideas about mostly android stuff then disappear for long periods of time or github where I have projects that I did all these stuff I just advocated against .

(ﾉ◕ヮ◕)ﾉ*:･ﾟ✧.