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

Boosting performance and functional style with ...

Boosting performance and functional style with Project Arrow from a practical perspective … with Spaceships

Project Arrow may be unknown to some, but It is a project that covers many important aspects of functional programming to build resilient and performant services. I want with this talk to share my experience but instead of talking about Telecom, I want to include this talk in the context of a spaceship and data transmission throughout all the operating systems. I cannot of course show the code of any company I have worked for and so, to share my knowledge and experience I will create a spaceship scenario. For that, I will use the Ktor as an example for services completely implemented in Kotlin, with Exposed for database access and completely reactive. You should come out of this session knowing all the major aspects of Project Arrow, including foundation knowledge, some advanced features, and a few extras.

More Decks by João Filipe Sabino Esperancinha

Other Decks in Technology

Transcript

  1. Boosting performance and functional style with Project Arrow from a

    practical perspective … with Spaceships João Esperancinha 2025/04/03
  2. About me João Esperancinha he/him/his • Java • Kotlin •

    Groovy • Scala • Software Engineer 10+ years • JESPROTECH YouTube Channel Kong Champion/Java Professional/Spring Professional
  3. Introduction • Challenges in Data Transmission • Why Functional Programming

    for Spaceship Data Transmission? • What is Project Arrow? • Why it works?
  4. Challenges in data transmission • Handling Transmission Failures • Ensuring

    Message Delivery Order • Encoding and Decoding Data • Handling Missing or Corrupted Data • Asynchronous Command Execution • Coordinating State
  5. Why Functional Programming? • Immutability for Safe Data Handling •

    Error Handling Without Crashes • Resilience & Automatic Recovery • Concurrency with reduced complexity • Mathematical Guarantees for Safety • Declarative & Composable Pipelines • Pure functions
  6. What is Project arrow? Project Arrow is a functional programming

    library for Kotlin that provides tools for typed error handling, concurrency, resilience, optics, and functional data structures. It helps developers write safe, composable, and declarative Kotlin code by leveraging functional concepts like Option, Either, and Optics. Key Features: • Typed Error Handling: Either Option • Functional Concurrency: arrow.fx.coroutines for structured parallelism • Resilience Tools: Retries, Sagas, and Circuit Breakers • Immutable Data Manipulation: arrow.optics for Lenses & Prisms
  7. Functional Data Modeling with Arrow Core Option (Nullable Handling) Either

    (Error Handling & Modeling Alternatives) Data Validation & Error Accumulation NonEmptyList (NEL) Optics (Lenses)
  8. Domain (TransmissionNgDto) @optics @Serializable data class Message( val id: Int?

    = null, val purpose: String, val message: String, val messageBcc:String? = null, val messageCC: String? = null ) { companion object } @optics @Serializable data class MessagePackage ( @Serializable(with = NonEmptyListSerializer ::class) val messages: NonEmptyList<Message>, @Serializable(with = LocalDateTimeSerializer ::class) val timestamp: LocalDateTime = LocalDateTime.now() ) { companion object } @optics @Serializable data class TransmissionNgDto ( val id: Int? = null, val sender: String, val receiver: String, val extraInfo: String? = null, @Serializable val messagePackage : MessagePackage , @Serializable(with = LocalDateTimeSerializer ::class) val timestamp: LocalDateTime = LocalDateTime.now() ) { companion object }
  9. Functional Data Modeling with Arrow Core NonEmptyList @optics @Serializable data

    class MessagePackage ( @Serializable(with = NonEmptyListSerializer ::class) val messages: NonEmptyList<Message>, @Serializable(with = LocalDateTimeSerializer ::class) val timestamp: LocalDateTime = LocalDateTime.now() ) { companion object } Custom Serializer Validates if the list is not empty
  10. Error Handling fun validateTransmission(): Either<String, TransmissionNgDto> = either { ensure(sender.isNotBlank())

    { "Sender cannot be blank" } ensure(receiver.isNotBlank()) { "Receiver cannot be blank" } TransmissionNgDto(id, sender, receiver, extraInfo, messagePackage, timestamp) }, Runs a computation block using Raise, and return its outcome as Either. Just simple validations left right Ensures that the condition is met; otherwise, Raise.raises a logical failure of type Error.
  11. Error Handling operator fun invoke( id: Int? = null, sender:

    String, receiver: String, extraInfo: String? = null, messagePackage: MessagePackage, timestamp: LocalDateTime = LocalDateTime.now() ): Either<NonEmptyList<String>, TransmissionNgDto> = either { zipOrAccumulate( { ensure(sender.isNotBlank()) { "Sender cannot be blank" } }, { ensure(receiver.isNotBlank()) { "Receiver cannot be blank" } } ) { _, _ -> TransmissionNgDto( id, sender, receiver, extraInfo, messagePackage, timestamp) } } Accumulates all errors, or the right value
  12. Optics for Data Transformation (installation Gradle) plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.ktor)

    alias(libs.plugins.kotlin.plugin.serialization) id("com.google.devtools.ksp") version "2.1.20-1.0.32" } implementation("io.arrow-kt:arrow-optics") ksp("io.arrow-kt:arrow-optics-ksp-plugin:2.0.1") build.gradle.kts KSP plugin KSP activation Optics Dependencies
  13. Optics for Data Transformation @optics @Serializable data class Message( val

    id: Int? = null, val purpose: String, val message: String, val messageBcc :String? = null, val messageCC: String? = null ) { companion object } @optics @Serializable data class MessagePackage ( @Serializable (with = NonEmptyListSerializer ::class) val messages: NonEmptyList <Message>, @Serializable (with = LocalDateTimeSerializer ::class) val timestamp: LocalDateTime = LocalDateTime .now() ) { companion object } @optics @Serializable data class TransmissionNgDto ( val id: Int? = null, val sender: String, val receiver: String, val extraInfo: String? = null, @Serializable val messagePackage : MessagePackage , @Serializable (with = LocalDateTimeSerializer ::class) val timestamp: LocalDateTime = LocalDateTime .now() ) { companion object } TransmissionNgDto.messagePackage.messages TransmissionNgDto.messagePackage @optics annotations for code generation Lenses!
  14. Optics for Data Transformation (retrieving data) post("/messages") { val transmission

    = call.receive<TransmissionNgDto>() call.respond(HttpStatusCode.OK, messagesLens.get(transmission)) } val messagesLens = TransmissionNgDto.messagePackage.messages TransmissionNgDto.messagePackage Lenses!
  15. Optics for Data Transformation (retrieving data) val transmission = call.receive<TransmissionNgDto>()

    val modified = messagesLens.set( transmission, listOf( Message( id = 0, purpose = "phantom purpose", message = "phantom message", packageId = 0 ) ).toNonEmptyListOrNull() ?: throw RuntimeException("Invalid phantom") ) val messagesLens = TransmissionNgDto.messagePackage.messages TransmissionNgDto.messagePackage Lenses!
  16. Resilient Communications with Arrow Resilience suspend fun registerUserById(id: Int, request:

    FleetUser): : Either<AppError, FleetUser> = either { saga { val originalUser = extracted(id, true) ensure(originalUser != null) { raise(NotFound) } saga({ val user = extracted(id, true)!! println("User with $id has clearance to proceed with telephone ${request.telephone}") updateUser(user.copy(telephone = request.telephone)) }) { nullable { updateUser(originalUser.bind()) } } saga({ val user = extracted(id, true)!! println("User with $id has clearance to proceed with bank account ${request.bankAccountNumber}") updateUser(user.copy(bankAccountNumber = request.bankAccountNumber)) }) { nullable { updateUser(originalUser.bind()) } } saga({ val user = extracted(id, true)!! println("User with $id has clearance to proceed with department ${request.department} and chamber ${user.chamber}") updateUser( user.copy( department = request.department, chamber = request.chamber ) ) }) { nullable { updateUser(originalUser.bind()) } } }.transact() } Saga Saga Builder Saga actions runs the Saga turning it into a suspend effect @Serializable data class FleetUser( val id: Int, val name: String?, val email: String, val telephone: String? = null, val bankAccountNumber : String? = null, val department : String? = null, val chamber: String? = null, )
  17. Asynchronous Data Streaming with Arrow Fx val messages = messageService.getMessages()

    val senderMessageDetails = messages.map { nullable { parZip ( { transmissionService.getTransmissionByPackageId(it.packageId.bind()).bind().sender}, { messageService.getMessagePackageById(it.packageId.bind()).timestamp} ) { sender, timestamp -> SenderMessageDetail(sender, timestamp) } } } Runs fa, fb in parallel on Dispatchers.Default and returns results
  18. Consistent State Management with Arrow STM Domain data class DockingBay(var

    occupied: Boolean = false) data class FuelStation(var fuel: Int)
  19. Consistent State Management with Arrow STM (retry) suspend fun requestDocking

    (spaceship : String) { atomically { val bay = dockingBay .read() if (!bay.occupied ) { println("$spaceship is docking..." ) dockingBay .write(DockingBay( occupied = true)) println("$spaceship has successfully docked!" ) } else { println("$spaceship must wait. Docking bay is occupied." ) } } } suspend fun refuel(spaceship : String, requestedFuel : Int) { atomically { stm { val station = fuelStation .read() if (station.fuel >= requestedFuel ) { println("$spaceship is refueling with $requestedFuel units..." ) fuelStation .write(FuelStation( station.fuel - requestedFuel )) println("$spaceship successfully refueled! Remaining fuel: ${station.fuel - requestedFuel }") } else { println("$spaceship cannot refuel, not enough fuel available!" ) } } orElse {} } } lateinit var dockingBay: TVar<DockingBay> lateinit var fuelStation: TVar<FuelStation> suspend fun initialize() { dockingBay = TVar.new(DockingBay()) fuelStation = TVar.new(FuelStation( 100)) } Transactional Memory variables Run a transaction to completion. Run atomically independently Provides fallback
  20. Consistent State Management with Arrow STM (fail) suspend fun refuelWithRollback

    (spaceship : String, requestedFuel : Int) { try { atomically { print("----- Start of atomic transaction \n") val station = fuelStation .read() if (station.fuel >= requestedFuel ) { println("$spaceship attempting to refuel with $requestedFuel units..." ) fuelStation .write(FuelStation( station.fuel - requestedFuel )) if (requestedFuel == 20) { throw IllegalStateException( "$spaceship encountered a system failure!" ) } println("$spaceship successfully refueled! Remaining fuel: ${station.fuel - requestedFuel }") } else { println("$spaceship cannot refuel, not enough fuel available!" ) } } } catch (e: IllegalStateException ) { println("⚠ Transaction failed for $spaceship : ${e.message}") println("$spaceship will retry later..." ) } } lateinit var dockingBay: TVar<DockingBay> lateinit var fuelStation: TVar<FuelStation> suspend fun initialize() { dockingBay = TVar.new(DockingBay()) fuelStation = TVar.new(FuelStation( 100)) } Run a transaction to completion. Throws an error
  21. Conclusion • Saga: Enables robust, transactional workflows in distributed systems

    by handling compensations and rollbacks. • Nullable: Provides safe handling of optional values without unnecessary null checks. • Either: Models computations that may result in success (Right) or failure (Left), avoiding exceptions. • Optics: Provides functional access to deeply nested immutable data structures. • zipOrAccumulate: Accumulates errors instead of failing fast, improving resilience. • STM: Provides safe, composable concurrency without locks.
  22. About me • Homepage - https://joaofilipesabinoesperancinha.nl • LinkedIn - https://www.linkedin.com/in/joaoesperancinha/

    • YouTube - https://www.youtube.com/@jesprotech • Bluesky - https://bsky.app/profile/jesperancinha.bsky.social • Mastodon - https://masto.ai/@jesperancinha • GitHub - https://github.com/jesperancinha • Hackernoon - https://hackernoon.com/u/jesperancinha • DevTO - https://dev.to/jofisaes