Do’t let complexity scare you – the case of the Ladybird browser

11-2-2024

In order to understand complexity, a good strategy is always to take something apart and try to rebuild it. This is exactly what a few volunteers, lead by a former Safari developer, set out to do. They are building SerenityOS, a full-fledged operating system, and Ladybird, a web browser, from the ground up (so: no borrowing an existing module for e.g. reading a JPEG file). Like true engineers, they are doing this for fun. That’s all well and good, but you can’t really build a serious web browser with all its complex features this way, right? Right? This is a story about how engineers approach complexity.

The complexity called ‘browser engines’

While twenty years ago you would hand-write the HTML for your website or maybe generate it with PHP, today’s websites are much, much more complicated. As an example, the recently launched website for Dialogic requires about 700 JavaScript-modules, and has about 19.000 lines of code of its own. There is however a staggering amount of complexity hiding beneath: just this website alone depends on (potentially) another 1.3 million (!) lines of code in modules it uses. This is excluding the browser engine and operating system underneath – that is, the software that is actually doing all the heavy lifting of making a website work. Just consider what these engines need to do: read HTML and CSS, decide what parts go where, decode a dozen image and video formats, parse and execute JavaScript code, deal with secure connections and much, much more. Modern browsers took decades and massive effort to develop, driven by companies like Google (Chrome) and Apple (Safari).

Being curious, I tried the Ladybird browser myself to see if it was any good. Surely these hobbyists have no chance of even reaching 1% of what the big guys can do, right? Setting it up takes a bit of fiddling as they don’t offer any downloads for Ladybird – the project is aimed at nerds to have fun, remember – so you need to download the source code and build it yourself. This looks more complicated than it is and a short while later, this Dutch news website showed up on my screen just fine:

If you know what to look for, you will immediately notice this is far from a hobby project anymore and actually quite a bit closer to being an actual browser than the makers are suggesting:

  • The site loads over HTTPS without issue. This means there is a substantial amount of cryptography and networking code is involved.
  • This site looks and works pretty much the way it should. This means that a fair bit of CSS is actually implemented, and probably a bunch of JavaScript. Just this front page downloads 103 files on load and the browser appears to deal with all of them!
  • The fonts are all looking as they should. This means that this browser can actually read fonts (WOFF format) and render them correctly. The fact that there is text at all also means this browser deals with Unicode.
  • There are JPEG images, so they got that sorted out (this is more involved than it seems: decoding the image, resizing it to fit, and a lot more tasks to do before anything can show up on screen)
  • The browser itself looks a bit like Safari – with tabs and an inspector no less – and a native macOS app. This means that not only did these people build a browser for their own hobby operating system, they actually also built a whole macOS app and the required compatibility layer (they call ‘Lagom’) to run this browser on other operating systems than their own.

So wait a minute, why are you not testing that super shiny new Dialogic website you were talking about earlier, you ask? Well…

It crashes, so: time to complain to the developer! Or, not so fast, this project was supposed to be fun remember, so these guys probably want to work on much more interesting things than this little issue. Instead, let’s see how deep the rabbit hole goes and attempt to fix it myself. The first step is to try and cause the same issue with the minimal amount of code possible. The error message hints it has something to do with the grid layout used on the site, which I happen to know is a bit complicated. My first guess was that the engine did not support dynamic CSS calculation (using calc(…)) but it turns out it can do that just fine. After adding some print statements to the code to see which grid the engine was actually trying to process right before the crash, I eventually figured out it was some other grid on the site causing the issue. This grid had the following CSS associated with it:

.four {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        grid-template-rows: repeat(auto-fit, auto);
}

With this I could reproduce the issue, at which point I decided to raise an issue with the developers, asking them to point me to where I should look to fix the issue (in open source they generally like it when you provide a clear description with a reproducible test case, but they love it when you help actually fix the issue!). Within a few minutes they pointed me at the CSS spec, and I figured out that my CSS was actually non-compliant – the ‘auto‘ is not allowed in ‘repeat(auto-fit, auto)‘. Had I looked at this in the Safari inspector, I would have noticed that it too had ignored that specific line. To fix the issue in Ladybird, all that would be needed would be to let it too ignore the invalid CSS rule. So, this is what I did and, let the result speak for itself:

While the layout is still not what it should be (some SVG icons are not showing up, the page is too wide, and there are these annoying dashes breaking words), the browser does not crash and the website is actually usable. I am very curious how far this fun project will be in a year from now.

For me personally, the takeaway from this story is this. Huge complexity does not mean that it cannot be understood nor that the ‘take it apart and rebuild it’ approach is futile – if you are motivated and skilled, you can single-handedly get very far as evidenced by this project. Truth be told, we are not all the 10x programmers these people are – I certainly am not anyway – but the story shows that it is still possible to meaningfully contribute. If tearing it apart and rebuilding from scratch is out of reach, try and contribute a tiny little piece to someone else’s effort – it is very satisfying and indeed, fun.

Update: apparently, with this small contribution I became the thousandth contributor to the SerenityOS project. Impressive milestone for the project!