logoalt Hacker News

staticassertionyesterday at 8:40 PM1 replyview on HN

I don't think it's the same tbh. In Rust I can often just `rg '\.clone'` and immediately see wins. Allocations are far easier to track statically. I don't have a good sense for "seeing" allocations when I look at JS, it feels like it's unfair to expect me to have that tbh. As for profilers, yes I could see things like "this code is allocating a lot" but JS hardly feels like a language where it's smooth to then fix that, and again, frameworks are so common that I doubt I'd be in a position to do so. This is really in contrast to systems languages again where I also have profilers but fixing the problem is often trivial.

> You think about threading, concurrency, etc: JS is even a little easier than many backend languages because it is (almost excessively) single-threaded. A lot of concurrency issues cannot exist in current JS designs unless you add in explicit IPC channels to explicitly "named" other threads (Service Workers and Web Workers).

My issue isn't with being able to write concurrent code that has no bugs, my issue is having access to primitives where I have tight control over concurrency and parallelism. The primitives in JS do not provide that control and are often very heavy in and of themselves.

I think it's perhaps worth noting that I am not saying "it's impossible to write fast code for the browser", I'm saying it is not surprising that people who have developed skillsets for optimizing backend code in languages designed to be fast are not in a great position to do the same for a website.


Replies

WorldMakeryesterday at 10:37 PM

> I don't have a good sense for "seeing" allocations when I look at JS, it feels like it's unfair to expect me to have that tbh.

I still think that's a training/familiarity problem more than a language issue? You can just as easily start with `rg \bnew\b` as you can `rg \.clone`. The `new` operator is a useful thing to start with as in both C++ and C#, too. (Even though JS new is technically a different operator than both C++ and C#'s.) After that the JSON syntax is a decent start. Something like `rg {\s*["\.']` and `rg [` are places to start. Curly brackets and square brackets in "data position" are useful in Python and now some of C#, too.

After that the next biggest culprits are common library things like `.filter()` and `.map()` which JS defaults to reified/eager versions for historic reasons. (There are now lazier versions, but migrating to them will take time.) That sort of library allocations knowledge is mostly just enough familiarity with standard library, a need that remains universal in any language.

> JS hardly feels like a language where it's smooth to then fix that

Again, perhaps this is just a familiarity issue, but having done plenty of both, at the end of the day I still see this process as the same: move allocations out of tight loops, use object pools if necessary, examine the O-Notation/Omega-Notation of an algorithm for its space requirements and evaluate alternatives with better mean or worst cases, etc. It mostly doesn't matter what language I'm working in the basics and fundamentals are the same. Everything is as "smooth" as you feel comfortable refactoring code or switching to alternate algorithm implementations.

> frameworks are so common that I doubt I'd be in a position to do so

Do you treat all your backend library dependencies as black boxes as well?

Even if that is the case and you want to avoid profiling your framework dependencies themselves and simply hope someone else is doing that, there's still so much in your control.

I find JS is one of the few languages where you can somewhat transparently profile even all of your dependencies. Most JS dependencies are distributed as JS source and you generally don't have missing symbol files or pre-compiled binary bricks that are inscrutable to inspection. (WASM is changing that, for the worse, but so far there are very few WASM-only frameworks and most of them have other debugging and profiling tools.)

I can choose which frameworks to use based on how their profiler results look. (I can tell you that I don't particularly like Angular and one of the reasons why is I've caught it with truly abysmal profiles more than once, where I could prove the allocations or the CPU clock time were entirely framework code and not my app's business logic.)

I've used profilers to guide building my own "frameworks" and help proven "Vanilla" approaches to other developers over frameworks in use.

> The primitives in JS do not provide that control and are often very heavy in and of themselves.

Maybe I'm missing what primitives you are looking for. async/await is about the same primitive in JS and Rust and there are very similar higher-level tools on top of them. There's no concurrency/parallelism primitives today in JS because there is no allowed concurrency or parallelism. There are task scheduling primitives somewhat unique to JS for doing things like "fan out" akin to parallelism but relying on cooperative (single) threading. Examples include `requestAnimationFrame` and `requestIdleCallback` (for "this can wait until you next need to draw a frame, including if you need to drop frames" and "this can wait until things are idle" respectively).

> I'm saying it is not surprising that people who have developed skillsets for optimizing backend code in languages designed to be fast are not in a great position to do the same for a website.

I think I'm saying that it is surprising to me that people who have developed skillsets for optimizing backend code in languages designed to be fast seem to struggle applying the same skills to a language with simpler/"slower" mechanics, but also on average much higher transparency into dependencies (fuller top-to-bottom stack traces and metrics in profiles).

To be fair, I get the impulse to want to leave it as someone else's problem. But as a full stack developer who has done performance work in at least a half dozen languages, I feel like if you can profile and performance tune Rust you should be able to profile and performance tune JS. But maybe I've seen "too much of the Matrix" and my "it's all the same" comes from a deep generalist background that is hard for a specialist to appreciate.

show 1 reply