The worst aspect of nodejs is code construction (craftsmanship).
Whereas Bill Joy said of Java "Allows you to think both In The Big and In the Small, at the same time." With nodejs, not only is there no Right Way, there's not even a Good Way. You have to mind all the details, plus quite of a few new ones.
Frankly, I'd rather just write 'C' again. If I have to care about the fiddly bits, I'd rather the language not fight back.
My team spends a lot of time mitigating memory leaks and back pressure (bufferbloat due to thread/task starvation). I haven't done this kind of troubleshooting since my 'C' slinging days.
And this is apparently acceptable.
I find the current state of affairs (emperor has no clothes) appalling and baffling.
Learn Elixir or Erlang and show that there's an alternative to Node.js that's both fun and powerful - and battle tested.
Like I said upthread, I used to dunk on JavaScript a lot, but it doesn't make sense nearly as much as it used to, to me.
>Single-threaded isn't a benefit
Huh? Of course it has some benefits. Unfortunately everything is just trade-offs. A benefit of single-threadedness is that you don't deal with the certain pitfalls of multi-threadedness.We aren't going to agree here, but you sounded like you thought your position was axiomatic or something, and that's what I disagree with. Meanwhile I am content that we may have different preferences, that's not a problem.
Can you describe a race condition that cannot be replicated on a single thread with either preemptive or cooperative multitasking/coroutines? I'm racking my brain and can't come up with one. If your coroutines are deterministically given time, then I guess you can avoid race conditions, but "are my coroutines deterministic" seems like a really difficult thing to conclusively prove in all cases (like, just add network I/O latency), and the conceptual barrier remains the same whether they're deterministic or not.
(Edit: a friend just noted the possibility of writing to memory/disk and reading halfway through, and if you don't have atomic writes that's true, but you can have preemptive, single-process multitasking that interrupts mid-write; that's why we have file system lockfiles, isn't it?)
I use node-async-locks when writing JavaScript sometimes if I have to deal with shared state, because, hey, I might have to await something and come back to this later. (Obviously I try not to, because duh, but sometimes you're stuck with it and can't immutable-all-the-things. So you define a critical section and do your thing.)
Use JavaScript.
We can say 'til we're blue in the face that that doesn't matter (and I do, as a Ruby/Grape guy for APIs), that matters. Lowered impedance mismatch is a thing. I use Ruby because I'm still more productive there--but that's a library problem (RDBMSes), not a language problem.
Node really is good-enough. I'd go for either a JVM or a BEAM-based solution if I was building things where there were significant and meaningful losses on the table if I fucked up, but for most things? Nah. Just...not important enough.
Instead, you'd rather the language be written with conscious land mines in it?
Like, I have a history of dunking on JavaScript. (Though, to be fair: ES6+ is better! It's a lot better. I kinda like it.) But C is unsafe as hell. The list of people who should be writing C is super short.
If you're running into memory links in Node, that points to bad native code or handles that are never getting removed. That's not something easier in C, unless you also like buying yourself double frees that you have to worry about. And backpressure is an architectural problem--it doesn't go away in another language, the ephemera of it just makes the problem surface in a different way.
Maybe what you're writing isn't appropriate for Node. Much of what I write isn't--if I start seeing buffers, I start reaching for another ecosystem, usually the JVM. But that's a far cry from a meaningful criticism of Node for what it's good at. Use what's good where it makes sense. Use other things where they make sense. Revisionism to have C make sense, in 2017, when we have modern, clean C++ and Rust both and Go if you really don't actually care about type systems, makes me really skeptical.
We have a handful of stupid simple http servers. We use express, redis, aws-sdk, pino, misc. Responses are mostly JSON.
The http-request module has given us the most fits. I question that any one has ever used it for more than toy problems.
The redis module is also an engineering marvel. I gave up trying to add a rate throttling shim. The goal is to limit the number of concurrent requests. Because when our app is under load, we're not processing redis responses fast enough, so redis server's outbound client buffers grow and will eventually OOM ABEND the server. So I wrote our own stupid simple redis thing using async.queue as a poor mans thread (task) pool. Trivial. Eg my REPL parser is 1/3rd the size of node-redis-parser. Works great. I keep thinking I must be missing something.
From my reading, hapi (successor to express) does an inbound backpressure thing. I'll be trying that out asap.
Much as I hate Spring, AOP, jedis, annotations, jaxrs, log4j... I've never had these kinds of nuts & bolts problems. Now I kinda miss the elephant gun approach.
PS- I can only assume the on drain event strategy was someone's idea of a practical joke. Maybe its a uvlib thing.
JS is the only language on the browser after Java and Flash were killed off.
Brendan Eich created JS.
Brendan Eich runs Mozilla.
No new browser language occurs unless the big players (including Mozilla support it)
Mozilla have killed all attempts to add new languages to the browser.
Q.E.D. - language monoculture due to one creator forcing his creation on everyone and denying anyone the chance of doing things differently.
At least Web Assembly offers some hope for a sane future where we can actually choose the right tool for the job rather than the only tool for the job.
Ran. Very briefly.
Basically, if you write in Node JS, there's no concept of a thread. The thread API is not visible or accessible to the developer.
This forces you to think from the ground up about asynchronous operations that would take some time to complete - file opening, network requests etc., and have you group all tasks dependent on that time-consuming task, separately.
In Node, you are not supposed to block the event-loop that runs in that single thread and queues the tasks.
Node JS has shown over the years that it scales well (maybe not as good as Go or Elixir, but enough for most use-cases).
Node also offers lot of great tools, that can be easily added to your project via NPM / Yarn. The Node ecosystem has a solution for virtually any task you might need to do repeatedly in a project.
Just to be clear, I am not saying Node or its ecosystem is perfect. There's always room for improvement.
What I am saying is that what appears as an obvious flaw, is not really a flaw. The language allows other approaches to solve the problem.
well, sure, but ten years ago it was already a given that one would just spawn one event loop per thread and have them communicate with messages, so why is it so hard for node ?
Backend and file systems, network and systems middleware do not need the abstraction model and overhead of a language designed to add dynamic content to fucking WEBPAGES because it can and it seems easy.
Well, file systems nobody writes in JS, so that's irrelevant.
As for "network and systems middleware" depending on what it does it can be a great fit for JS and especially Node, which is a lightweight logic layer on top of libuv.
'Lightweight logic layer on top of libuv': well if I can design, predicate and tout my language on 'event' orientation but then when it needs to do something else it becomes a thin logic layer over the hosts threading model: that's just a win!
That's not true on NUMA systems with multiple CPU sockets. You should have at least one thread per NUMA region for optimal results. Critical for example for running multiple 40 or 100 Gbit ethernet adapters.
Then again, you probably aren't going to run Node.js on those systems, at least not for handling heavy I/O.
the world doesn't revolve around making HTTP servers. Maybe you aren't writing apps that do parallelizable serial computations but please don't generalize.
This is exactly how backend Node.js development is done. The tradeoff is that processes are used instead of threads, which uses more memory but is magnitudes easier to work with than traditional threads where mutable bits of memory are shared.
Sure, Rust solves these problems but Node still has a place in the world: it is established, easy to pick up, and can share code with the browser. A decent solution to modern web development complexity.
However, I guess what made it appealing initially, was that it uses a syntax known to a lot of web developers. The callback pattern helped.
Although these days, we have been moving away to generators or async-await.
This is the key. And it reflects poorly on them for that. Syntax is the easiest part of a language to learn. The nuances of behavior is the hard part - and those nuances change as you move from the browser to the server; what makes good browser code will not make good server code.
In reality they shunned a ton of knowledge and community support to keep a particular (and particularly mediocre) syntax. Even today, years after Node has reached popularity and many lessons have been learned, developers with no experience outside the browser think they can write perfectly good server code, simply because they know the syntax. Never mind that all of the design patterns change. Never mind that the core libraries they use change. Never mind that they suddenly have to be cognizant of how much CPU time their code takes.
This is really true and it's sad, because it leads to more security problems on everyday software.
Node's success has everything to do with the environment itself in combination with the language. The node runtime, the associated stdlib, and most open source/3rd party modules have been written for a non-blocking runtime from day #1. The same stuff can be achieved in plenty of other languages/stacks (e.g. Python + Twisted), but you have much more work to do validating that every single library you use plays nice with async io, sometimes you have more event loop housekeeping responsibilities, etc...
Let's be honest: it is nothing to do with either of those and purely a matter of fashion. In a couple of years at most there will be a new new thing and everything will revert to version 0.1, keeping everyone busy but making no actual progress. Gotta soak up those CPU cycles the hardware people are giving us somehow right? Can't let the users get any of that speed for themselves!
Let's be honest: if you need "fashion" or "idiocy" etc to explain a trend in tech, you don't have an explanation.
Your explanation wouldn't even explain why it was Node+JS that got to be "in fashion" and not something else from the 20000 options.
That's the point. There is no explanation, other than the same reason that bellbottoms are in again this year. Or out, I don't actually know.
We pretend like we're "engineers" or "scientists" but there's nothing objective about what we do...
You mean you can't come up with one. Because for me, which followed the scene for 20+ years, there is a perfect explanation.
I had a homepage in 1994. I've seen them all come and go. This one's no different.
It’s as relevant as saying we don’t write apps in COBOL or Modula2 anymore.
I'm frustrated that better stuff doesn't win in the market as well, but I've been a web developer 20 years and Node's appeal was pretty obvious and exactly as the GP states. Without that it would not have gained traction to become fashionable.
The thing missing in developers that I have decried over and over in this devop/agile movement is that SAs had discipline and an ordered idea and that developers exist to perturb the norm to better effect. The two ideas are not readily reconcilable.
The real innovation that the Node environment and the Javascript language offered is one of marketing to developers who did not know better. Because there were no I/O paradigms in Javascript, one could be created to support this way of doing things, and there was no competing paradigm that people could point to in Javascript to say "Why would I do this when I could just use threads? It's not that hard."
With that out of the way, the floodgates opened, because once the first few people started adopting it because they did not understand threads, it was only a matter of time when "front end" people adopted it, because they did not know any languages other than Javascript. And thus, the current fad was born.
To me it seems that NodeJS solves a very specific problem; handling many simultaneous persistent network connections (i.e. websockets). I can't help thinking of NodeJS as fundamentally being a programmable socket server. I.e. its purpose is to solve a network problem, not a business logic problem.
The problem for me, when I work on large(r) apps that run in NodeJS, is that there is a certain "mental overhead" associated with it. NodeJS has this non-blocking IO, event driven architecture for a very specific reason which makes total sense when you solve IO problems (such as handling many simultaneous network connections) but this behaviour somehow seems to trickle down into business logic. With NodeJS I find myself writing non-blocking, event driven business logic because the environment in which my code runs dictates this. Somehow that doesn't make sense to me. To me business logic is inherently synchronous.
Now there are some really clever ways to compensate for this such as the Promise and with never versions of JavaScript there are even new language features to help battle what was originally known as the "callback soup". However, no matter how clever and admirable each of these features are, to me they seem to compensate for a fundamental problem in the run-time environment (NodeJS) that actually makes it not really suitable for anything CRUD and beyond.
The language is non-blocking, so any asynchronous tasks (DB read/writes, disc I/O, cache, http, etc) will immediately jump to processing the next request the moment it is not doing blocking computation.
Non-blocking:
[aa][bb][cc][/aa][/cc][/bb][dd][ee][ff][gg][/dd][/ff][/gg][/ee]
Blocking-threaded: [aa]------------------------[/aa][ff]----------------------[/ff]
[bb]------------------------[/bb][gg]----------------------[/gg]
[cc]------------------------[/cc][ee]----------------------[/ee]
[dd]------------------------[/dd]
Depending on how many threads you can get going at once, you may be able to achieve comparable performance doing threading, but nonblocking is basically leaving 0 time on the core wasted and limited to the speed of the event loop.And then on top of that, clustering module is used to do the same thing on every core.
You can have "non-blocking" and multiple threads at the same time.
The V8/JS thread and the C++ thread?
Doesn't the C++ part create threads in some cases when needed?
I've never written anything on node.js, but that's the only argument that's ever given me pause.
Today, I do front-end React stuff as well as back-end servers with Node JS. I have been happy with it so far.
With some type-system like Flow or TypeScript, you can manage huge projects in Node JS.
I happen to like the community, CLI tools written in Node, and the plethora of open source libraries built on top of Node.
This also has a downside. Your libraries can get outdated quite fast, you would have to keep up with new language syntaxes etc., and remember which syntax is supported by which version of Node etc.
But so far, I think Node is headed in the right direction.
To me, the fact that Node has to add a library with custom semantics just to allow a basic 'open' on a file handle is a huge warning flag to me.
You can still make it work; but you can script a web page's interactions in C as well. That doesn't make it the right thing to do.
Should we collectively eschew what's possible due to individual language gripes?
I'm sorry, is this a dig at Ryan Dahl, or of JavaScript/Node developers in general? I'm having trouble understanding what point you're addressing with this comment.
As for evaluating languages for their "best purpose", I think that's a very complex discussion that doesn't necessarily yield a best (or cost effective/productive) result. And certainly, as we've seen routinely evidenced, using a different language on the server is no panacea.
To be clear: I said js is misplaced on the 'server' side and is a wart in general when applied in that context. Any educated comment on these sentiments?
Exactly what I asked.
> Any educated comment on these sentiments?
Without clarity on the sentiments themselves there's not a lot to elaborate on without simply fumbling in the dark. If the concern, though, is that, in Node, you live and die by an asynchronous event loop, I'd say that's not a small footgun. I don't think that's in dispute. I'd also say that the presence of footguns doesn't, by itself, disqualify a language from being used in any particular context.
As for JavaScript being a wart, I don't really agree with that sentiment. I think that's attributable to some pretty strong and level-headed language evolution making what was once a very blunt scripting instrument into something somewhat reasonably suited to larger-scale applications.
It is the poster child for the "If the only tool you have is a hammer..." maxim.
Its appeal derives almost completely from its presence in probably every major browser, where it was placed for DOM manipulation and was stressed way past its design envelope over time, leading to the increasingly dystopian web development landscape we progressively inhabit.
If it is ultimately victorious, it will be in spite of its design, not because of it. Those of us who are old enough to remember will cringe at the pain we endured over the years because of the widely used Intel 808x architecture as it evolved (small/medium/large/huge memory models, and segment registers, anyone?), not because it had the greatest merit, but because of its market penetration.
History repeats itself.
All things considered, a craftsman simply uses a tool to do a job. Often it doesn't involve much fanfare. I wouldn't say that modern JavaScript is quite as blunt an instrument as a hammer, but hey, if you're good with a hammer...
https://news.ycombinator.com/item?id=15090278
TL;DR: Writing JavaScript for the browser won't really help you write good JavaScript for the server.
As far as libraries are concerned, it was never my experience that the landscape changed drastically from one to the other. Most of the libraries I look at/use for the front-end today advertise themselves as both for Node and for the browser.
What do you mean? The fs module shipped with node is pretty much just a wrapper for libc. Hell, it even links to the open(2) manpage in the docs for usage information.
What's finally got me writing way more Javascript than I'd like to is React Native. It's by far the easiest way I know of to share code between iOS and Android, it papers over a lot of Android's irritating/broken UI bits (introducing others, but overall improving the situation), and you actually can share much of your code (practically everything but the UI layer) with a web client—and even... spits... Electron. RN's performance isn't even terrible, especially compared to cross-platform mobile frameworks that have come before it (and to Electron spits)
Hopefully Webassembly will save us in another couple years, and we'll be able to do the same thing in any of several much better languages.
[EDIT] though definitely keep your sanity and use Typescript. I'd have probably jumped off a bridge by now if I were having to do all this in actual JS, of any flavor.
Also, it 'helps' if both server and client are single-threaded, because then, you can use similar solutions on both server and client (even if they sometimes aren't the most pleasant approach for solving your domain)
I hope that Web Assembly will take of and get a decent interface to the DOM, allowing developers to pick other languages in the role that JavaScript now has.
I sometimes think we could do with a bit more thanking-our-lucky-stars that the language that got entrenched on the web wasn't, say, VBScript (which IE did use to support).
For your major drawback, there's TypeScript.
dynamic typing, strong typing: python (for the most part), Scheme
dynamic typing, weak typing: Javascript, PHP
static typing, strong typing: Pascal, Ada, Java, C#
static typing, weak typing: C, Typescript, perhaps others
SPECIAL CASES:
strongly typed, dynamically typed, but with some compilers it can also be statically typed: Common Lisp
strongly typed, statically typed but can infer types: Haskell, ML family
strongly typed, can infer type with "auto" keyword: C++ (latest version)
non-typed: Machine language, assembler, perhaps Forth
I would propose "person who can only be at most half-competent," except that is too wordy and probably too charitable.
This is ridiculous from the point of view any professional developer. I know that this is your point, and I'm just amplifying it. I (and many other professionals I work with) know - and use on a daily basis - so many more than 1 language that it's sincerely baffling to grok a world that promotes "One language fits all". That's without even considering the parlous state of npm and its libraries.
If that's the primary language you are good at, from coding frontend apps, then it's pretty nice to be able to switch to writing backend code without having to do a language context switch. Muscle memory along with your memory about library methods all just continue to flow.
> It can't be that hard using a different language.
If I'm better at one language than another, it is at least somewhat harder. Why struggle when you can flow?
If you're better with screwdrivers, why struggle with a hammer?
JavaScript has a painfully slow runtime. Writing servers requires attention to performance and reliability, which javascript is very poor at. If you want to make a toy service and don't care about any of this, go ahead and use your favourite language. But when you want to make something incredibly fast and reliable (like nginx), you'll need to consider another technology.
Hammers and screwdrivers are not general purpose tools in the way that languages are.
For most things, most languages are just as fine.
It's not like JS is specialized in some very small niche by design -- like e.g. COBOL is.
>JavaScript has a painfully slow runtime.
I call BS. v8 is one of the fastest dynamic runtimes, at 2x of C or so for lots of tasks, and it totally obliterates Python, PHP, Ruby, and co in speed. And since some of the web's different properties are written in the latter 3, it's certainly not speed (which JS surpassed them far in) that's the issue.
>If you want to make a toy service and don't care about any of this, go ahead and use your favourite language. But when you want to make something incredibly fast and reliable (like nginx), you'll need to consider another technology.
Nobody writes "nginx" in JS.
They write the kind of APIs and apps and services that people also used to write in PHP, Python, Ruby, Go and whatever lang.
Uhh, what? You don't consider "programatically manipulate the DOM in the browser" to be a niche?
Whatever it was inveted to do is totally irrelevant, as the "browser API" is not Javascript the language/syntax but just an API (library/module).
In fact you could trivially implement it in all kinds of programming languages.
Anything it does related to that is just simple library code and methods on the "document", "element", etc objects -- and that's only when run in the browser where those are available (automatically "imported" let's say). Node doesn't even have the "document" object.
Any proof for this?
EDIT:
According to "The Computer Language Benchmarks Game"
JavaScript fares pretty well against Python [1] or Ruby [2] but not really that great against C [3] or Java [4] in the CPU intensive benchmarks.
1 http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...
2 http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...
3 http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...
4 http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...
Considering is a non-static, totally dynamic language, with all kinds of dynamicity in it, it does totally fine. 10x to 30x faster than Python, Ruby etc, and 3x to 5x slower than C/Java is totally fast.
JS JIT were already many times faster than PHP5. There's no comparison to the complexity, quality, resources and top-notch teams in play in JS JITs (just consider the vendors making them: Google, Apple, Microsoft and Mozilla) and PHP.
Not a great analogy. A more accurate analogy is switching from one very big toolbox to another very big toolbox. If you are used to one and know where all the tools are, and they have been used so much that the wood perfectly fits your hand, then it's just going to take some time to get used to the new toolbox. I'm not saying it's a hard rule and you should never consider another language. I just answered the question of why someone would want to use javascript on the backend. It's not the only factor, but it's a factor.
Imagine we have carpenters and brick layers. Two distinct jobs that maybe have some overlap of tools.
We decide that we have a lot more carpenters than brick layers, so we'll take a carpenters' toolbox and add a few brick layer inspired tools to it (but they're not necessarily the same, and some of the tools that can overlap maybe aren't quite as specialized, nuances, nuances, etc.).
Now, we can tell our managers that our problems are solved. All of our carpenters can now do masonry work.
The root problem of all of this mess is that both of these domains are different. Problems and solutions in the front-end tend to be different than in the back-end.
Management is sold on this "everyone is an interchangeable cog now" fantasy they have been chasing for decades and crappy decisions are made. We end up with most developers not really learning at least one of the areas of the full stack very well (and not learning both if they are really striving to under-achieve...).
Note: This same thing happened in Java before NodeJS, but in reverse. Back-end developers refused to really learn web development and so we ended up with misguided solutions like GWT and virtually every other high level Java web framework/library.
Perhaps I haven't run into the right people, but mostly my experience with other JavaScript devs is they don't even know the fundamentals really (they don't understand scope rules in JS, they don't really understand weak typing, they don't understand JS is single threaded, they don't understand closures very well, etc.). I don't know if this lack of understanding is due to a lack of experience programming at all, or just not really learning JavaScript (many non-JS devs are forced to learn enough JS to get the front-end working -- or at least seemingly working).
The thought of lowering the bar on development even further is frightening (Johnny did some web development last year, I'm sure he can transition to writing our back-end API since he knows JS). I'm all for anyone learning and improving as a developer -- and sharing in my passion. What I hate is this false confidence more and more people seem to have with everything and the problems it causes (they don't bother to learn the tools they have or the tools that came before them, they are too lazy to learn a new language/framework/library, and they have extreme NIH syndrome).
As I mentioned PHP: In PHP each worker is single threaded, too, but you can scale by having more workers in isolation.
Some addition, subtraction is fine. But Array iteration, JSON encoding-decoding and similar CPU bound tasks could block the event loop.
You can perform them asynchronously, or forward the request to some remote service that's better at doing these computations for you and return results (maybe some service written in Python or a database)
Sure, JavaScript (and Ruby and Python) are usually fast enough with modern hardware - but we can't pretend there's no cost.
If my apps were that way, i could have replaced my team with 20 well-fed monkeys.
Does HN think putting 2-15KB JSON blobs in a Postgres DB running on Docker on a router is a good idea? Oh, and the table stores log data, so there's about 2 million rows after 5 days uptime. What do you think?
EDIT: This was not entirely related but it goes to the notion that it seems like a lot of myopic decision-making has somehow become even more acceptable and I would say this leads to dumb situations as above, and Node.
Making a full API on nginx via lua sounds crazy but it appears that people do it.
Things like getter/setters and object initializers. And don't even get me started on Web Workers, which basically seem to be dead on arrival. The Web Workers design is so shockingly bad and not fit for purpose that I don't understand how anyone signed off on it.
Some bits of the new js are in the right direction, and those are the things that people talk about and are getting used, but lots of things were definitely not.
So, like Nginx's model? Or 99% of Python servers?
You can still run multiple processes...
https://nodejs.org/api/cluster.html
There are a lot of knowledgable people commenting, but it's starting to seem like they haven't familiarized themselves with the tools available within the NodeJs base.
To another point, I could put the time into writing a server and back end application in Go or Rust or C++ or whatever, but it would take (at least me) 10x as long to build out the application I need as it does to pull express into a project and build out a server, back end computations, file manipulation, authentication, and roll a MongoDB store with a fully-fleshed out front end (even if it's not so stylish).
Mind you I work in an enterprise environment where these kinds of things are required to serve maybe twenty people and run on a single multi-cored machine at any given time and not tens of thousands users.
It's a fantastic tool that works from small to mid-large projects, and would serve as an excellent prototyping and MVP-dev environment for even the naysayers who are probably more skilled than I am in other areas.
The problem with Node is it's unsuitable for a whole class of server applications - you're going to run into trouble whenever you need to maintain serial access to a single resource. Whereas in Java you'd have some sort of token that gets "taken" by different threads, there's no clean way to do this in a multiprocess Node environment.