Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Functional Fix: Kotlin Error Handling Made ...

The Functional Fix: Kotlin Error Handling Made Elegant

Error handling in software design often devolves into procedural code riddled with nested conditionals and complex workflows, making systems hard to test, maintain, and scale. Railway Oriented Programming (ROP - https://fsharpforfunandprofit.com/rop/) offers a structured, functional paradigm that clearly separates success and failure paths, enabling developers to simplify workflows and build more maintainable systems. This talk takes a step-by-step approach to refactoring procedural Kotlin code into a declarative, functional style using Kotlin and Arrow KT.

Drawing from my experience with Kotlin in Specmatic, we will explore real-world examples that highlight how Kotlin’s type system, extension functions, and immutability features can simplify error handling and empower developers to build maintainable, predictable systems. A special focus will be placed on the practical application of the Either monad in this context. Attendees will walk away with actionable steps to refactor procedural code into functional pipelines, improving readability, testability, and maintainability.

HariKrishnan

January 24, 2025
Tweet

Video


Resources

More Decks by HariKrishnan

Other Decks in Programming

Transcript

  1. © 2025 All Rights Reserved Http Request Problem Statement {

    "URL": "/items", "method": "POST", "body": { "id": "1", "name": ”item 1", "price": 19.99 } } Http Stub Http Request { "URL": "/items", "method": "POST", "body": { "id": ”2", "name": ”item 2", "price": 29.99 } } MATCH
  2. © 2025 All Rights Reserved Http Request 1 { "URL":

    "/items", "method": "POST", "body": { "id": "1", "name": ”item 1", "price": 19.99 } } Problem Statement – Match HTTP Requests Http Request 2 { "URL": "/items", "method": "POST", "body": { "id": ”2", "name": ”item 2", "price": 29.99 } } Result: Failure, Message: Body did not match
  3. © 2025 All Rights Reserved Solution: As per our mental

    model matchUrl matchMethod matchBody
  4. © 2025 All Rights Reserved Solution: Procedural Code class HttpRequest(private

    val url: String, private val method: HttpMethod, private val body: String) { fun matches(anotherRequest: HttpRequest): Result { if (this.url != anotherRequest.url) return Failure("URL did not match.") if (this.method != anotherRequest.method) return Failure("Method did not match.") if (this.body != anotherRequest.body) return Failure("Body did not match.") return Success("everything matches") } }
  5. © 2025 All Rights Reserved Solution: mental model vs conditional

    code matchUrl matchMethod matchBody !(matchUrl) !(matchMethod) !(matchBody) Failure Failure Failure Success
  6. Functional approach to error handling The Railway Analogy “Many examples

    in functional programming assume that you are always on the “happy path”. But to create a robust real world application you must deal with validation, logging, network and service errors, and other annoyances. So, how do you handle all this in a clean functional way? This talk will provide a brief introduction to this topic, using a fun and easy-to-understand railway analogy.” Blog Post - https://fsharpforfunandprofit.com/rop/ NDC London 2014 - https://vimeo.com/113707214 Scott Wlaschin Attribution - https://ddd.academy/scott-wlaschin/
  7. © 2025 All Rights Reserved Monadic Curse A Monad is

    just a monoid in the category of endofunctors “The monadic curse is that once someone learns what monads are and how to use them, they lose the ability to explain them to other people” - https://old.arrow-kt.io/docs/patterns/monads/#the- fallacy-of-monad-tutorials
  8. © 2025 All Rights Reserved An oversimplified way to understand

    Either Wrapper around raw values that allows a bind transformation Raw values • Right – Http Request • Left – Error Message Bind transformation • FlatMap
  9. © 2025 All Rights Reserved FlatMap – The bind transformation

    • Input – Function that accepts unwrapped value of Either • Responsibility – Apply this function on wrapped value of Either • Output – Another Monad Example:
  10. © 2025 All Rights Reserved Why take all this trouble?

    matchUrl(request).flatMap { matchBody(it) }.flatMap { match... }... The ability to compose functions is simply too good to resist. How does this even work? • Either Monad is Right Biased • FlatMap in Either only applies the function on the right (yes that function which accepts the unwrapped value of Either)
  11. Sounds familiar? f >=> g >=> h Right Fish Operator

    or Kleisli Composition - >=> It allows chaining functions that return a monad (e.g., Either, Option, Result), effectively composing functions of type A -> M<B> Heinrich Kleisli Attribution: Konrad Jacobs, GFDL <http://www.gnu.org/copyleft/fdl.html>, via Wikimedia Commons
  12. © 2025 All Rights Reserved FlatMap and Fold Wait, but

    what about errors? Either.Fold takes two functions • ifLeft • ifRight Applying it to our use case matchUrl(request).flatMap { matchBody(it) } .fold({ Failure(it) }, { Success(it) })
  13. © 2025 All Rights Reserved Putting it all together matchUrl(anotherRequest).flatMap

    { matchMethod(it) }.flatMap { matchBody(it) }.fold( { Failure(it) }, { Success(it) } )
  14. © 2025 All Rights Reserved Machinery Business End A minor

    change in formatting matchUrl(anotherRequest) .flatMap { matchMethod(it) }.flatMap { matchBody(it) }.fold( { Failure(it) }, { Success(it) } )