In 2018, I practiced Advent of Code (here you can see streams of my solutions). Every day in December, they post a small problem, and you have to write a program that solves it. It usually takes anywhere from a couple of minutes to a couple of hours and is quite fun, I recommend you give it a try. When a task is completed, it is always available, not only in December.
I realized that there are two types of solutions: those that can calculate the answer in a couple of milliseconds, and those that will take the answer for several years. If you get the second option, you are doing something wrong. There is no point in waiting, although, technically, that might be correct too.
Another interesting observation is that it doesn’t matter what hardware you use to launch. If the solution is fast, it will be fast both on a laptop and on a pumped workstation. Of course, it could be two or three times slower, but the difference will be between 10ms and 30ms. You will get your answer anyway, so it doesn’t really matter.
On the other hand, if the solution is slow, you can use any processing power, and it still won’t be enough. This could cut the runtime from three years (on a laptop) to one year (on the most powerful computer I can build). What’s the difference? It’s too long anyway.
Now let’s move on to the software. It is easy to call Advent Of Code solutions wrong when they are slow, since we know that a fast solution must exist. With real problems, no one guarantees it.
Except in some cases.
Quite often, actually.
Let’s see. I have a library called Datascript… It is a persistent data structure / database and it just so happens that it is implemented for two platforms: JS and JVM. Moreover, it is actually written in Clojure and most of its codebase is used by both platforms. This means that we know that both versions always do the same thing. There is a small layer that covers platform-specific details such as data types and the standard library, but the rest is generic. It’s not that one version is original and the other is an inefficient port. They both play the same game.
You might be thinking that if they behave the same, their performance should be the same, right? It would be logical to think so.
Let’s take a look at the actual time it takes to compile the codebase and run the full suite of integration tests. We’re talking about a codebase that is just over 9000 LOCs, of which 4000 are tests:
Clojure 1.10 on JVM:
- REPL boot time: 1.5 sec
- Compile time: 6.5 sec
- Tests time: 0.45 sec
ClojureScript 1.10.439 with advanced compilation:
- Compile time: 78 sec
- Tests time: 1 sec
ClojureScript 1.10.439 without Google Closure compilation:
- Compile time: 24 sec
- Tests time: 1.3 sec
So what do these numbers tell us? Basically, you can take ~ 8 seconds, 24 seconds, or 78 seconds to process the same code. The choice is yours. Also, by running the same program, you can get the result in half a second, one second, or almost one and a half seconds.
“But wait, Tonsky, they can’t be compared! These are two big differences! They are designed to do completely different things! One of them works in a browser! “
You can of course get results. Let me remind you: we are compiling the same code, built to do the same thing, using the same algorithms and running on the same hardware. The end result is the same in both cases: you will receive a response to your query in the data log in a short time or over a long time. You either spend half your day waiting for the compiler, or you spend it playing the REPL, building something.
What have ClojureScript / Google Closure compilers been doing for so long? They’re wasting your time, that’s what. Of course, no one is to blame, but in the end the whole decision is simply wrong. We can do the same thing much faster, we have evidence, we have the means to do this, but it just so happens that it is not. But we could. If you wanted to. This huge overhead that you pay, you pay in vain. You get nothing from JS other than doubling the runtime and astronomical build times.
The same is true for all languages with awfully long build times. It’s not that they couldn’t be faster. They just choose not to. Does a C ++ or Rust program take too long to compile? Well, OCaml could probably compile an equivalent program in less than a second. And it will still be fast at the car level.
“Wow, wow, slow down! This is even more unfair! Now it’s not just two big differences, now it’s like toothbrushes and spaceships. You completely ignore what each language provides. There is a reason why they spend so much time compiling, you know? “
I know. But still, I think you can compare them. After all, they are all general-purpose languages, and in the end, what matters is whether you have a working program on hand and can provide an answer within a reasonable time frame. It doesn’t matter how the developer got there. You can calm down thinking that it is, but nobody cares about it.
Imagine: an airplane flies from Moscow to Novosibirsk, the heart of Siberia, which covers 2,800 kilometers in 4 hours. There is also a train that covers the same distance in three days. There is no shower on the train, bad food, beds you cannot sleep on. And an airplane is a comfortable modern airplane. Which would you choose? The same price. The only difference is your comfort and your time.
If we take this as a software development metaphor, you’d be surprised that programmers happily take the train. They even argue to the point of hoarseness that there are irrefutable reasons for choosing a train. No, they don’t mind if the compiler is in no hurry to “work”. There are faster ways to get to the same destination though. It’s easy to get confused when arguing over details, but remember: we all end up in one place, no matter what language we speak.
Browsers? The same story. HTML is a rather inefficient way to position pixels on the screen. A computer that could display millions of polygons per frame can have a hard time loading a web page. As with Advent of Code solutions, this does not depend on the power of your computer. And even highly optimized web code based on Canvas and WebAssembly (Figma) makes my Macbook fans spin in complete silence when I launch my own Sketch.
– * pats on the cover * This PC is capable of running Crysis 3 in 4K at 144fps.
– But can it run Atom?
There are simply limits to how far this wrong decision can go. Text editors on Electron cannot resize the window in real time and sag in frames when you simply move the cursor. Slack on the iMac Pro will be as slow and memory intensive as on a 12-inch Macbook.
The whole solution, “web stack”, in general, mistakenly… The same could be done faster and more efficiently – there is so much wasted potential. It’s time to admit it and start over. There are fast text editors and communication programs that are readily available for even the weakest netbooks.
I can go on and on. Keep in mind this: Think about what you get from it. Are the problem and the resources spent on it comparable? It is easy to find excuses for why things are the way they are. They are all probably valid, but these are excuses. We know that faster programs are possible and that makes everything else just go wrong.