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 Callista medarbetare Andreas Tell

From Coroutine Confusion to Award-Winning Cache — An Interview with Anders Asplund

// Anders AsplundAndreas Tell

Earlier this year, our colleague Anders Asplund completed the five-week deep-dive course Kotlin Coroutines Mastery, led by Marcin Moskała of Kt. Academy — and he didn’t just pass. His certification project, the async caching library KoCache, was recently selected as one of the top projects of 2025.

Naturally, we had to sit him down and ask how one goes from coroutine confusion to award-winning cache — and whether blocking a thread really is a sin. Here’s what he had to say.

The course is a five-week deep dive with daily lessons and mandatory exercises — on top of a full-time consulting job. How did you actually fit it in, and what kept you going through week three?

The format did a lot of the work. New lessons dropped every day, each around one to two hours including the exercises, but you were free to schedule them yourself. That flexibility mattered, because it let me stack the whole week’s material into a single “competence Friday” — one day where I did nothing but the course. At Callista we get a competence program that sets aside a certain amount of time each year for a topic of your choosing, so I had somewhere to put those Fridays without stealing from the client. It also made it easy to get my client on board.

As for week three — the Friday ritual is honestly what carried me. Motivation is unreliable, but a standing appointment with yourself doesn’t ask how you’re feeling. It helped that the course was built to compound: each week ramped up the difficulty, but always on top of what came before, so the harder material kept making the earlier material click. That forward pull is a hard thing to walk away from.

You got to attend live Q&A sessions with Marcin Moskała and guests like Roman Elizarov — the man who basically built Kotlin coroutines. Did you dare ask him anything, and did the answer surprise you?

Honestly, this is the one part I have to plead guilty on. My whole setup ran on those competence Fridays, and the Q&A sessions landed earlier in the week — so the same structure that got me through the course is exactly what made me miss every single live session. I’ve made my peace with it, though I suspect Marcin and the guests fielded a few questions I’d have loved to hear the answers to.

For your certification project you built KoCache — and then it got picked as one of the top projects of 2025, ahead of visualizers, telemetry libraries and full-blown apps. What do you think made a “humble cache” stand out?

I didn’t pick a cache because it was impressive — I picked it because it was the right size for the assignment, and because a cache happens to be one of the clearest ways to show what coroutines are actually good at. That turned out to matter more than I expected.

From the outside a cache looks trivial — everyone’s written a map with a timeout at some point. The part that isn’t trivial is what happens under concurrency: ten thousand callers hitting the same missing key while only one loader call goes out, or one caller cancelling without breaking the entry for everyone queued behind them. Those guarantees are completely invisible if you just describe them in a README. So that’s where I put the effort — documented tests over virtual time, and a small demo program that actually shows the thundering herd collapsing into a single call.

If I had to guess why it landed, that’s probably it. Not that the cache was clever, but that you could see it working. A lot of the harder-looking projects keep their best behaviour buried inside. This one put it on screen.

The “thundering herd” problem sounds like something out of a nature documentary. Explain it to a non-developer — and how KoCache tames the herd with a single Deferred.

Picture a popular café. A single customer orders a slow pour-over that takes four minutes to brew. While the barista is making it, ninety-nine more people walk in and order the exact same thing. The naive café puts ninety-nine more pour-overs on the go — same coffee, brewed a hundred times over, and the kitchen grinds to a halt. That’s the thundering herd: the moment a cached value expires, every request that misses tries to recompute the same expensive thing at once, and your database gets a hundred identical queries in the same breath.

KoCache’s trick is to cache the promise of the value rather than the value itself — a Deferred. The first request to miss starts the computation and immediately stores its Deferred under the key; every subsequent caller finds that Deferred already in place and simply awaits it. No locks, no queue — just one in-flight computation whose result a hundred callers share. And because they’re coroutines, those hundred awaiters suspend rather than block: they cost almost nothing to keep parked, where a hundred blocked threads would not. So is blocking a thread a sin? Not quite — it’s just waste, and suspending is how you stop paying for it.

They say there are only two hard things in computer science: cache invalidation and naming things. You built a cache and named it KoCache — so you took on both. Which one was harder?

Naming, hands down — KoCache cost me a full business day and a dozen rejected names. Joking aside, invalidation is where the real design decisions live. The approach I settled on was to give every entry its own coroutine that sleeps for the entry’s TTL and then evicts it — so expiry is active rather than something that only fires the next time someone happens to read the key. It’s an unusual way to spend a coroutine, but they’re cheap enough that you can, and the number of them is bounded by the cache’s max size anyway. Layer a straightforward LRU cap on top for when the cache fills up before anything expires, and that’s the whole invalidation story — which, compared to the naming, was the easy part.

What’s the takeaway for Callista’s clients — when should a team reach for coroutines, and when is it over-engineering? And what’s next: more features for KoCache, or a new deep-dive course on the horizon?

The question to ask isn’t “should we use coroutines” — on Kotlin that’s rarely the hard part. It’s “does this even need to be concurrent.” Coroutines are cheap, but concurrency never is: the second two things run at once, you’ve signed up for races, cancellation, and things half-failing. So if a job runs start to finish down one path, leave it sequential and boring — that’s a feature. Reach for coroutines when the concurrency is real: lots of calls in flight, work you need to cancel, results to coordinate. That’s where they earn their keep. What you don’t want is a custom scope and three flows wrapped around something that was a for-loop.

As for what’s next — no grand roadmap. KoCache does the one thing it was built for, and I’d sooner leave it small and correct than start bolting on features for the sake of it. A new course is the likelier bet; five weeks of having my assumptions taken apart was the most useful thing I did all year. I just need to recover first.


Anders Asplund is a Senior Solution Architect/Developer at Callista. You can read his in-depth technical write-up of KoCache and the Coroutines Mastery course on our tech blog, and you can find the KoCache source code here.

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