When and how to use Result?

I love the idea of Result.
I love having encapsulated try/catch.

But I’m a little confused about how and when to use Result.

I currently use it like this:

My adapters and services return a Result. Failures and stacktraces are logged but do nothing else

runCatching{
.... // do something cool 
}.onFailure {
    logger.error("Something bad happened ", it)
}

My Resource classes fold and handle the Result

return service.method().fold(
    onFailure = {
        Response.serverError().entity("Oops").build()
    },
    onSuccess = {
        Response.ok().entity(doSomethingWith(it)).build()
    }
)

Is this really the correct way to use a Result? Or is there a more idiomatic way to code in Kotlin?

2 Likes

I think once I read a comment by a person from the Kotlin Team that Result is not meant to be used for application services. And that we should create our own result type(s), specific to our application/service.

I can’t say I fully understand the reasoning behind this, but I personally use Result only for very generic tools. Like for example we create a service for scheduling external tasks on it and then results of tasks are returned as Result. So the service doesn’t really understand, what it executes, it just wraps the result.

1 Like

In my own company, I have made a policy of avoiding try/catch blocks unless there was no other way.

We’ve made a similar structure to Result and all services/adapters and whatnots that can fail return this structure, which is checked on the spot, leveraging optionals as well. Our controllers on the other hand return http entities.

It looks something like this:

val result = doAction().assertOK(errors) ?: return anotherError()

The point of it is to let execution work as usual, while catching failures and collecting the failure reason (in the errors array above) without the added overhead of exception handling. You can always exit early and keep history of the issues that caused the exit.

1 Like