hack news

Lichess will get a large upgrade. It doesn’t chase as deliberate

Lichess is a 100% beginning-offer/free-application chess web place of residing, extinct by millions of avid gamers to play billions of video games.

I made the selection to write down it the use of the scala language a long time within the past, and never looked back. It has the functions that matter to me:

  • Form security: the compiler as a copilot
  • Purposeful programming: functions as building blocks
  • Performance and ecosystem: the JVM as a solid basis

Enters Scala 3

Lichess being constructed on Scala 2, when Scala 3 changed into as soon as launched closing 300 and sixty five days, I changed into as soon as very infected to upgrade.
Yet I selected to help a paunchy 300 and sixty five days for the language to stabilize, and for the library ecosystem to purchase up.

Last month I made up my thoughts the wait changed into as soon as over, and that it changed into as soon as time for Lichess to gather a large upgrade. May per chance I in actuality have faith waited for longer? Sure, but I didn’t take into fable a motive, and let’s be factual I changed into as soon as craving for basically the most modern functions.

Scala 3 original functions

It be now not so great an evolution of the language, but somewhat a entire overhaul, because the compiler changed into as soon as rewritten from scratch. Yet compatibility changed into as soon as preserved wherever conceivable, easing the migration.

Here are some of my current Scala 3 functions:

Opaque kinds

Stronger typing with zero runtime rate, what’s now not to take care of? Strings (love user IDs) and utterly different primitives will also be changed with genuine kinds that the compiler understands.

opaque type UserId = String

def find(id: UserId) // this function doesn't accept any String, just UserId values

I in actuality came across and mounted some extinct vague bugs that have faith been due to the the use of Strings, while changing them to opaque kinds.

Cleaner syntax

Most indispensable indentation and elective braces kind our code glimpse love python, which is serene. Fortunately the comparison stops right here 😉

object Chess:
  def turnColor(ply: Int) =
    if ply % 2 == 1 then White else Black

Improved kind inference

We desire kinds, now not boilerplate. Most regularly it be easiest to let the compiler settle out what issues are by itself. I’ve been ready to spend a form of kind annotations right by arrangement of the Scala 3 migration, and it elated my code-golf inclinations.

Better contextual abstractions

implicit has been changed with in actuality expert key phrases using, given, and extension.
It makes the code more straightforward to label, because the intent is plenty clearer than when the use of the generic implicit key phrase.

Enumerations that glimpse genuine

Extra of a code sugar thing, but I continuously take care of concision and expressiveness:

enum DrawReason:
  case MutualAgreement, FiftyMoves, ThreefoldRepetition, InsufficientMaterial

It doesn’t glimpse love great, but it certainly comes with batteries incorporated.

Contemporary export key phrase

It in actuality works love import, but to bid functions and values. It makes composition more concise.

// before:
def rating = glicko.rating
def deviation = glicko.deviation

// after:
export glicko.{ rating, deviation }

If better composition ability much less inheritance, then rely me in.

Contemporary inline key phrase

While the extinct @inline annotation changed into as soon as a easiest-effort thing, the original inline key phrase guarantees inlining right by arrangement of compilation.
It be a ambitious application that desires to be dealt with with care.

And heaps of more functions

The checklist could presumably presumably chase on and on; there’s so arrangement more to Scala 3! This put up is already getting too long, so I will lower down on the fanboism.

The migration

Lila is a big program, serving 2000 HTTP requests per second, playing 5000 chess moves per second, while doing A LOT of OTHER THINGS that I better now not open enumerating right here.

So yeah, migrating it changed into as soon as provoking, and I fully anticipated a anxiousness of some form. Let’s take into fable the arrangement in which it went.


Fortunately metals and bloop are handling Scala 3 very wisely, which gave my code editor paunchy language toughen. It changed into as soon as a extremely overjoyed experience.

All we need now is for some mettlesome soul to toughen Scala 3 toughen for treesitter, so that we can all gather pleasure from genuine code coloring for the original language syntax.

Updating my code

That changed into as soon as the easy and relaxing allotment, in particular since the compiler did loads of the work for me. I in actuality rewrote more code than I had too, because I could now not withstand changing some implicits to given right here and there, and the use of opaque kinds.

Someday I needed to rewrite the Glicko2 ranking system from Java to Scala 3, because the compiler changed into as soon as complaining about having Java in my undertaking. No-one noticed broken scores, so I whisper it labored.

Third-celebration libraries

That is where issues bought a tiny bit hairy. Lila is constructed on Play Framework which is never yet ported to Scala 3.

So I forked it and butchered it to spend all the pieces we gather now not need – which is in actuality loads of the framework.

Once Play changed into as soon as reduced to a handful of small libraries (HTTP/netty server, routing, and kinds), it changed into very easy to migrate to Scala 3.

Most utterly different dependencies, such because the MongoDB driver, the template engine or the serene functional cats, have faith been already upgraded to Scala 3. As for the libraries coming from the Java ecosystem, love our redis driver, wisely, they lawful work as traditional.

Going to manufacturing

When all the pieces compiled, I shipped it. And to all americans’s surprise, besides about a bugs I had created while rewriting hundreds of traces of code… it labored. It lawful did. No explosions, no vague bugs, no memory leak, no efficiency degradation. That changed into as soon as somewhat sudden.

With Scala 3 working in manufacturing, I changed into as soon as free to rewrite the code even deeper, to incrementally kind use of Scala 3 functions.

JVM tuning

Until one morning, as an quite quite a bit of of deploying the changes from the day earlier than, I let it run an extra 24h. Then we saw the JVM CPU utilization upward thrust to alarming heights, with unprecedented patterns. And no obvious culprit within the thread dumps…

I could now not kind sense of it, and at closing called for attend – learn all about it in my outdated blog put up.

The avengers assembled and saved Lichess: it changed into as soon as lawful the JVM that wished some tuning. The HotSpot compiler changed into as soon as running out of code cache, and when we gave it some more, issues went great better.

Ludicrous bustle

Which ability that, Lichess is now sooner than it ever changed into as soon as. The outdated version running Scala 2 changed into as soon as also throttled by the shortcoming of JVM tuning. The outcomes weren’t as spectacular, but peaceable: we have faith been fundamentally running Lichess with the parking brake on.

Lichess is now running with Scala 3 and with out the parking brake, and it be plenty sooner. In an effort to bid if Scala 3 itself is sooner, we would have faith to rollback to Scala 2 and defend a peek at it with the genuine JVM tuning. I’m now not exciting to enact that, sorry! While you have faith tried Scala 3, there’s no going back.

Last words

I’ve been both scared and severe about this migration, ever since Scala 3 changed into as soon as announced. Given the size of our codebase, I changed into as soon as looking ahead to a anxiousness, but as an quite quite a bit of all we bought changed into as soon as about a bumps on the road. And we’re now serene crusing, all contemporary and future proof, which feels kinda immense.

It only took a month to fully migrate Lichess, from the significant code change to being determined that it runs in manufacturing completely (most modern uptime: 7 days).

As with every refactoring or migration, the success and bustle are largely due to the static typing and compiler quality.


10/10 would migrate again


Large thanks chase to the Scala 3 crew, who did an fabulous job at this original version of the language. Changes are barely darn wisely documented too.

I am also forever grateful to all americans who works on Scala tooling, and to the amazing crew of developers who helped me, guided me, and in most cases outright wrote the complicated code for me after I needed it.

Thank you to all Lichess avid gamers, and to all americans who helps this barely undertaking with a donation!

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button