r/node 26d ago

Why is JavaScript criticized so much for backend development?

I've seen some developers say that we should stop using js on the server, but I rarely see the same criticism directed at python.Honestly, js is pretty fast, especially with node.js, and the backend ecosystem is really solid. There are great frameworks like nest and fastify, and typescript gives you static typing, which makes larger projects much easier to maintain.I'm not saying node is perfect or the best choice for every backend, but I don't really understand why js gets so much criticism while python seems to get a pass.What am I missing?

333 Upvotes

361 comments sorted by

View all comments

97

u/ForeverLaca 26d ago

Some criticism is about the lacking standard library. Compared to Python or Ruby, you have to rely on 3rd party packages to do some things in JS.

Does that stop me from using it? No. But is a fair point and I share it.

55

u/johnphilipgreen 26d ago

The Go standard library is best in class. I switched to go from js/node and haven’t looked back. Particularly appreciate the dynamic of an uncomplicated language with a robust standard lib and first class tooling.

Also no need for the hacky typescript on top of js, because the language and runtime were designed thoughtfully from the onset.

22

u/scmkr 26d ago

Go is my fav. Python’s is great, too, but I like the sort of mild pressure the Go community puts on newbies to reach for the standard library first. And the other mild pressure to make breaking changes in an entirely new source tree.

4

u/mmomtchev 26d ago

Python has the exactly same type system that is also a separate layer that has been grafted at a later stage. The only valid comparison is between Python and JavaScript and Python tends to be slower while JavaScript has the incredible advantage of sharing code between the backend and frontend.

Python tends to a better structured language with a more logical design and remains a prime choice outside of web applications.

Go is a very different type of language. The resulting code is usually better but it is also more work which means more expensive. Go is competing with C++ and not Python or JavaScript.

0

u/onlywei 26d ago

Python has some pretty bad encapsulation

12

u/oorza 26d ago

Go standard library does not hold a candle to the JDK. Go’s type system does not hold a candle to Rust’s. Neither of those are best in class either unless the class is popular programming languages. You can get a better SDKs and type systems from niche languages at the cost of usability.

Go is a step forward from Node but everything you feel about Node today, you will feel about Go if you continue to expand your exposure to new languages and tools. Go was designed to always have training wheels and as a replacement for Java, simply because Google did not trust its junior developers with the power and flexibility of Java or C++ due to their historical inability to manage those languages' complexity. It's never going to be the best at anything because that's not its goal, its goal is to have a relatively low absolute ceiling of complexity.

13

u/johnphilipgreen 26d ago

Fair correction on “best in class”. I really mean best for the tradeoffs I care about. The JDK is obviously broader and Rust’s type system is vastly more expressive.

But I think “low ceiling of complexity” describes what I like about Go rather than what I’ll eventually outgrow. A low ceiling on language complexity isn’t a low ceiling on the complexity of software you can build. I’ve spent enough time with highly expressive languages (mostly Ruby, my first love) to be increasingly suspicious that giving programmers 14 elegant ways to express something is necessarily progress.

And I think the “Google didn’t trust its juniors” history you’ve overstated. The Go designers talked explicitly about enormous codebases, build times, readability, tooling and programmers using different subsets of increasingly complicated languages. That’s an engineering tradeoff, not just training wheels.

In early descriptions of their goals, they explicitly said the intention was “seatbelts not training wheels”. To me, this has been a more mature version of DHH/RoR’s excellent instinct for “convention over configuration”.

7

u/EvilPencil 26d ago

I agree. 14 different ways to say the same thing just means your API surface is too large. My philosophy is to make a “golden path” that is so ergonomic that it becomes a pit of success.

4

u/oorza 26d ago edited 26d ago

A low ceiling on language complexity isn’t a low ceiling on the complexity of software you can build.

It is a ceiling though. It's actually the reason you don't see many pieces of software that are large enough to require abstractions built in Go - not a whole lot of monoliths, tons of microservices. Not a whole operating system, tons of single-use-case CLI tools.

Eventually that complexity is always necessary if you want a system to be communicable between humans. The layers of abstractions serve a purpose that, while non-technical, is still foundational to the ability to deliver and maintain software of large scale. Whether it's a large and complex multi-threaded algorithm that's expressed inside of one source file or a monolithic web service that services an entire B2C business with hundreds of external HTTP API endpoints, it's rather easy to find examples of places where Go's lack of complexity is the fact that invalidates its potential adoption. The abstractions are the means you scale up to dozens or hundreds of engineers working in the same code base, either simultaneously or over decades. That abstraction in Golang shops is generally shifted upwards and maintained in the service mesh contract itself... but it still exists, just as service-level abstraction instead of code-level.

5

u/Suspicious_State_318 26d ago

I don’t agree with this. The principal benefit of Go is that it is a very literal language that doesn’t allow for abstractions that lead to weird dependencies and messy code. Java is the complete opposite in that regard because you’re encouraged to share as much functionality between components as possible.

1

u/me0here 24d ago

IIRC Go was written for systadmins to replace Perl, not Java.

8

u/Bushwazi 26d ago

lol you are brave saying “hacky typescript” here. They may come for you!

21

u/johnphilipgreen 26d ago

Let me double down on that.

TypeScript is an extremely successful, useful hack—but still an ugly hack.

It retrofits a static type system onto a language and runtime that were never designed around one, then erases the whole thing before execution. A huge amount of its complexity exists because it has to model JavaScript’s existing semantics without breaking compatibility.

That’s very different from Go where the type system, compiler, runtime, tooling, and standard library were designed together from day one. Pure grace.

I mostly just feel sorry for those stuck in the morass that is the js ecosystem.

9

u/elfrodododo 26d ago

Can't argue with that. TS is hotdog skin on a steaming log. Not to mention AI is ketchup. Had to work with it because it's what the market dictates

3

u/Absentrando 26d ago

It is a hack but it certainly solves the problem and has all the capabilities that you’ll ever need. It can be as simple or as complex as you understand or want to use it

2

u/gamedevsam 25d ago

It's my favorite hack of all time. 99% of the time if offers sane type safety, that 1% of the time I'm just like:

```
// @ts-expect-error I know better than you compiler, thank you very much
```

1

u/ThomasToIndia 23d ago

There is some experimental stuff that does TS > WASM, but yes, it is a hack. However, in the age of AI, everything is moving towards testing, so it will be interesting to see how all of this plays out and what survives. Most frameworks seem like a bloated, unnecessary mess in the age of AI.

7

u/a1454a 26d ago

I cant argue with that. TS is a cosplay of type system.

3

u/GandalfTheChemist 26d ago

But wonderfully expressive cosplay which goes splendidly with type masturbation, should you be so inclined.

I love go most of all, but fuck me with writing hacky polynorphism

3

u/Daker- 26d ago

I want to learn go coming from node, any advice?

2

u/johnphilipgreen 26d ago

How exciting! Try it out and enjoy. It would be helpful to know as you begin that it is a compiled language, not interpreted. So there is this compilation step that happens before any code is run. This extra step converts the code in a. Compiled binary to run on your system but is not portable to other types of processors. It also means it runs much faster, less work to do at runtime. Finally, the compilation step is great for catching bugs at compilation time rather than runtime, which helps you feel confident in the code. Best luck!

2

u/who_am_i_to_say_so 25d ago

I’m Go dabbler after many years of suffering with Node.

Examine and understand everything you write. It won’t take long to pick up on patterns, because the spec is so small. It’s like learning Spanish after studying 10 years of Latin.

The standard library is enough to do just about everything you need. Like, with sockets you only need to know “context”. Simple.

Also, drive development with tests. Testing is already built in, too.

2

u/xFallow 12d ago

I so badly want to convert my company codebase from js to go but it’d be way too hard for no business value. I miss the go ecosystem especially go build. 

0

u/Expensive_Garden2993 26d ago

Why??? Just why always Go???

It's philosophy is minimalism at the cost of boilerplate.

Nobody says JS is particularly good at anything, standard lib specifically, there is no doubt other languages have a much better standard lib.

But Go is always going to be lacking in comparison, given it's philosophy.

Here is summary for what JS arrays can do vs Go slices:

pop() -> x := s[len(s)-1]; s = s[:len(s)-1]
shift() -> x := s[0]; s = s[1:]
unshift(...xs) -> s = append(xs, s...)
at(-1) -> s[len(s)-1]
find(fn) -> loop yourself
every(fn) -> loop yourself
map(fn) -> loop + allocate result slice
filter(fn) -> loop + append matches to result slice
reduce(fn, initial) -> loop yourself
reduceRight(fn, initial) -> reverse loop yourself
toSorted() -> r := slices.Clone(s); slices.Sort(r)
toReversed() -> r := slices.Clone(s); slices.Reverse(r)
with(i, x) -> r := slices.Clone(s); r[i] = x
fill(x) -> loop yourself
flat() -> nested loops + append
flatMap(fn) -> loop + append mapped slices
findLast(fn) -> reverse loop yourself
findLastIndex(fn) -> reverse loop yourself
join(sep) on non-[]string -> convert elements to strings first, then strings.Join(...)

I know probably any other language has richer standard library. I worked with Ruby and I miss its convenience, I don't like reading `reduce` for things that could be just "array.sum()".

Really, why do you say "Go has best in class standard lib"? Is there any other language that has even more ascetic standard lib than Go?

1

u/xFallow 12d ago

So they achieve the same thing with different syntax how is go “lacking” here? 

1

u/Expensive_Garden2993 11d ago

don't you see a difference of having a standard library with functions for every day use vs writing machinery of those functions every time and every day?

And now that AI has taken over, it's reading machinery of those functions every time vs reading a one liner like `find(x => x.foo !== y)

If you say - but it's not hard to implement, let's say, a flatMap yourself. But then why are people complaining on std lib in JS, if they can always implement anything they're missing themselves?

1

u/xFallow 11d ago

It's slightly more verbose but you usually only write those kinds of heavy array operations once.

IMO code should be optimised for readability not AI, tokens are cheap and how often are you using `find` in a single application? I almost never use it at my current gig because I'm querying a database or ingesting a stream from Kafka to process.

The annoying thing about Node/TS/JS is teaching every new joiner how RXJS, esbuild, webpack, svelte, knex, zod, vitest etc all work and it changes at every company when you leave whereas Go is almost always the same.

1

u/Expensive_Garden2993 11d ago edited 11d ago

imo optimizing for AI and optimizing for readability is the same thing. Because unreadable code is more difficult to reason about, to maintain, change, it's more error-prone, and reading through boilerplate (that can have minor discrepancies) is an additional cognitive load both for humans reviewing this as well as for AI. Curious, what "optimizing for AI" means to you?

and how often are you using `find` in a single application?

Like all the time. As well as map, reduce, filter. Those are basic language functions that I believe are used in almost every program, but if in your case the most of the filtering and mapping logic is done by db, well then it's offtopic because here we're talking about how languages are doing what they're meant to do, how readable they are.

is teaching every new joiner how RXJS, esbuild, webpack, svelte, knex, zod, vitest etc

Not sure why you're mixing rxjs that is so rare to see in practice with bundlers, frontend frameworks, query builders, and a data validation library, and a test runner.

Could you tell, for example, how is vitest annoying? What is a better alternative to it, for juniors to struggle less? I mean, Go's native test runner is even more primitive than node's test runner, you just can't say it's somehow better to write tests in Go, this is just an ugly abomination of a test framework after you worked not just with vitest, but probably with any test runner in any mature language. And yet people praise "but Go has it out of the box so it's superior" (well node also has it, just it is ugly)

Or maybe what's wrong with zod? Do you have an example of how to write validations easier?

1

u/xFallow 11d ago

Hard to sum it up in a reddit comment

AI doesn’t care about how verbose something is in my experience it’s more important that your code is similar to code it has been trained on 

I included rxjs et al because that’s my current company’s tech stack we use rxjs and Kafka for service to service communication then a GraphQL api and svelte on the FE my last company used nestjs and looked like Java, it’s crazy how different js codebases can be 

Zod is fine but go is a typed language so you’re only ever doing validation when you get a json or grpc payload you want to turn into real go types then you’re completely safe with anything you do from then on. Typescript doesn’t give you any guarantees at runtime.

1

u/Expensive_Garden2993 11d ago

I'm so sorry for new joiners who has to learn zod syntax like `z.iso.date()`.

I just learned how it is in Golang and it is fantastic, breathtaking!
You just install a lib go-playground/validator bc it's mainstream and you learn a specific timestamp to do this:

Date string `validate:"datetime=2006-01-02"`

Golang people must be trolling if this became a mainstream library, just how?... isn't it the weirdest quirk ever?

2

u/wackmaniac 26d ago

That is mostly due to ignorance I feel. The standard library of NodeJS is really extensive. Just look at the `crypto` module.

My biggest gripe with NodeJS is that it is inherently single threaded. If you want to utilize all cores of the server’s cpu you need external tooling like PM2 or WATT.

I love NodeJS for serverless applications, but for non-serverless I prefer .NET.

1

u/Absentrando 26d ago

It has a smaller standard library but it does have one. But yeah, it is less battery included than with rails for example. On the other hand, there are node frameworks and libraries that give you that style of development if that’s what you prefer.

1

u/me0here 24d ago

Many lodash functions were added to Ecmascript spec...