Blogg

Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn

Callista medarbetare Anders Asplund

From Confusion to Mastery - My Journey with Kotlin Coroutines and Building "KoCache"

// Anders Asplund

Kotlin Coroutines have become the standard for asynchronous programming in the Kotlin ecosystem. While I might not reach for them in every single task, they remain one of the most powerful tools in my developer toolbox. However, using them effectively requires more than just knowing syntax, it requires understanding the underlying mechanics of concurrency.

Introduction

To bridge the gap between basic usage and deep understanding, I decided to join the Coroutines Mastery course by Marcin Moskala. As part of the certification process to verify these new skills, I built a final project: KoCache, a coroutine-native caching library.

Here is a summary of the course and a look under the hood of my final project.

The Course: Coroutines Mastery

The course, hosted at coroutinesmastery.com, is a 5-week cohort-based deep dive. It’s not just a collection of videos; it’s a structured journey designed to take you from “I use coroutines” to “I understand how coroutines work.”

How it Works

The structure is intense but rewarding. For five weeks, you get:

  • Daily Lessons & Exercises: Every day covers a specific topic (e.g., Exception Handling, Context, Flow) followed by practical exercises that you must solve.
  • Live Q&A: Weekly sessions with Marcin Moskala (and guest experts like Roman Elizarov) to clarify doubts.
  • The Certification: To get certified, you need to finish 80% of the exercises and have your final project approved.

The Curriculum

  • Week 1 & 2: The Foundation & Advanced Mechanics. We started with the basics of suspension and moved quickly to Structured Concurrency. Learning how Job hierarchies work, how cancellation propagates, and how to properly use CoroutineContext and Dispatchers changed how I write code.
  • Week 3: Synchronization. This was crucial. We learned how to manage mutable state safely without blocking threads, using primitives like Mutex and understanding the role of Actors and Channels.
  • Week 4: The Power of Flow. A deep dive into Flow, SharedFlow, and StateFlow. We covered reactive programming patterns that are essential for modern UI development.
  • Week 5: Real-world Application. We wrapped up by applying everything to real Android and Backend scenarios, focusing on testing and best practices.

The Final Project: KoCache

For my certification capstone, I built KoCache (available on Codeberg).

The Motivation

Why build another cache? Most caching solutions in the Java/Kotlin ecosystem are thread-based. They rely on blocking synchronization (like synchronized blocks) which stops the thread while waiting for a lock. In the world of Coroutines, blocking is a sin.

I wanted a cache that was:

  1. Suspend-native: It should never block a thread, only suspend execution.
  2. Concurrency-aware: It should handle multiple concurrent requests for the same key efficiently.
  3. Memory-efficient: It should automatically manage its size using an LRU policy.

The Architecture

KoCache implements the advanced patterns I learned in Weeks 2 and 3 of the course.

1. Mutex over Synchronized

Instead of standard Java locks, KoCache utilizes Mutex. When we need to read or write to the internal map, we lock the Mutex. If the lock is busy, the calling coroutine suspends rather than blocking the underlying thread. This allows the thread to go off and do other work (like handling UI events) while waiting for the cache.

2. LRU (Least Recently Used) Eviction

A cache without limits is dangerous. KoCache implements an LRU eviction policy to keep memory usage predictable.

  • The Logic: The cache relies on a LinkedHashMap configured with access-order. Every time a value is read or written, it is moved to the end of the collection.
  • The Eviction: When the cache exceeds its configured maxSize, the item at the start of the collection (the least recently used one) is dropped.
  • The Synchronization: Crucially, this reordering is a mutation of the map. Because we wrap our map access in the Mutex mentioned above, this complex state change happens safely across multiple coroutines without race conditions.

3. Request Deduplication with Deferred

A common caching problem is the “thundering herd”: when two coroutines request the same missing key at the same time, both might try to fetch the data from the network. KoCache solves this by storing Deferred values. When a request comes in:

  • Check: Is there a Deferred job for this key?
  • If yes: await() its result.
  • If no: Create a new async job to fetch the data, store it, and return the result. This ensures that the expensive fetch operation happens exactly once, and all concurrent requesters get the same result.

Conclusion

This was a fantastic course for mastering coroutines. The pacing and the difficulty level of the exercises were just right. I particularly appreciated the daily lesson structure, which allowed me to fit the work in whenever I had free time. If you want to understand the machinery behind launch, async, and Flow, I highly recommend it.

Certified Coroutines Developer Certificate

Tack för att du läser Callistas blogg.
Hjälp oss att nå ut med information genom att dela nyheter och artiklar i ditt nätverk.

Kommentarer