After a year of using Node.js in production
geekforbrains.com
geekforbrains.com
Not all tools are appropriate for all niches. The author made it clear they don't have an issue with Javascript as a whole or even with Node.js necessarily, but rather the use of Node.js as a major server platform or as a platform for large applications.
These things aren't pain points in the browser the way they are in Node. I have never felt the need for an ORM in the browser. I have never dealt with client-side code that was using so many libraries I had to worry about whether exceptions would be handled via exceptions, or the first argument of the callback, or rejected promises. No one (at least, no one I know) is installing node modules like isArray to use in the browser.
Yes, these things _could_ technically apply to the browser, but it's not commonplace. In the node world, these are all things you deal with consistently.
Erm, well, considering the adoption rate of Browserify and Webpack, I'm going to disagree with you there. Especially considering React's momentum practically requiring some form of module builder.
Webpack doesn't bundle at runtime, it doesn't add any amount of code overhead per module that I can easily measure, and it doesn't trash startup speed.
It's something like tens of bytes (minified), FWIW, for the closure that each module gets put into.
Node has support for the built in isArray, and you only need that "micro module" if you want to support IE8
Things like long term support, stability and security rate in how mature different technologies are for production. Considering a lot of the problems the author ran into with node.js aren't secret, I think he might actually have liked it quite a bit to go on to try it in production for a full year.
I agree that when programming mostly alone one can get by very nicely in any reasonably popular language since its popularity necessarily means that it's workable in the areas where it's typically used. I disagree that languages can not get in your way if you know what you're doing once you're not doing it alone.
[1]: At least, not for long.
[2]: created in the past thirty/forty years
For example the OP got fed up with Python and switched to Node. Now he is fed up with Node and switching back. I can say that focusing on the downsides of the tool I am currently using and the upsides of the tool I am not using is a fairly common thought pattern for me too. Of course the way to combat it is to remember that it is very rare for some tool to be strictly superior to others and just focus on the task at hand.
Choice is a very dangerous thing. When reading the book "Coders at work" I was struck by how primitive some of the old computing environments were. But that did not stop those people from doing amazing things with them. I now think that was partially to their advantage because they were freed from choosing the language/framework and so could concentrate on doing, you know, actual stuff.
Sure. If you're a good novelist you can write something great even on a keyboard with a broken 'e' key (btw, your 'I' key is about to break; you should replace it asap).
But novelists don't have deadlines and when the novel is done, they usually don't take reader requests to change this or that part of the story.
"The advantages and limitations", what works and what doesn't, "areas to avoid" are precisely the point of that kind of review.
I hate to "well actually" you :) , but a great number of authors have contracts that demand one or two novels a year over a fixed period of time. I know Iain Banks did with his publisher, he mentioned it at a one of his readings of a new but yet unpublished novel I was lucky to attend back in 2007'ish.
> they usually don't take reader requests to change this or that part of the story.
Even well known authors are reigned in by their editors and proof readers, and sometimes things have to be changed.
haha - touché, point taken :-)
Deadlines seem like a great excuse for compromising quality. Sure, life is complicated, the boss is demanding, the mortgage has to be paid, the children need to be supported etc. etc. but compromising quality and enthusiasm (they usually are correlated) because of the "terror" of a deadline will just leave you at the mercy of the next "terror", only this time you'll even have even less enthusiasm to fix the spaghetti. Doesn't sound like an enjoyable existence.
Of course, very few people have the privilege of never having to compromise, but it's never black or white and there are many more degrees of freedom to choose the path with more quality than are implied.
>"The advantages and limitations", what works and what doesn't, "areas to avoid" are precisely the point of that kind of review.
The "area to avoid" in the review is Node.js and considering that large and impressive projects have been written in it, it seems that this is another case of throwing the baby out with the bathwater.
I agree with one of the commenters: Lessons already learned by older engineers (who went through similar woes with other languages/tools) are being re-learned again and again.
The software industry is in a sorry state.
Unless you are a very disciplined team with a very strong sense of writing modular code, don't use Node.js for any larger project. And even then, the single-most useful function in an IDE 'Show Call Hierarchy' will never be available when using a dynamically typed language.
That is not an issue for smaller projects. However, long before you even get close to the the million lines of code project size, your tools will fail you. Your debugging/refactoring times will explode and adding a new feature will seem unsurmountable.
Instead, let's just re-write everything from scratch because the cool hipster that wrote your backend a year ago has left for greener pastures...
I won't even try to guess the amount of technical debt produced with Node.js and the likes each day in the bay area.
And, yes, I just used Node.js to write a Slack-bot. It was fun, took me two hours and got me up and running quickly. That's the beauty of it. Just be aware of the dangers.
If a particular library doesn't have one, you can write it yourself. In that case theres no need to model the entire library - you can only model the subset of functions / methods that you use.
If only that were true! I think the JS (and more generally web development) ecosystem today is more a case of those who do not learn from history being doomed to repeat it. The thing is, if you actually are Google or Facebook or Microsoft or Mozilla or Apple, you can throw huge amounts of resources at problems and produce sufficiently useful solutions regardless, and then you can do the same again a few months later if you need to. These are the kinds of organisations that set the tone for the whole community because of their sheer size and influence. However, their goals are not necessarily aligned with the rest of the web development community, nor will their approach necessarily work well for someone else.
> Younger engineers are ignoring lessons learned
Why ignoring them? Beyond the 'youth' factor directly, the signaling from the larger companies mentioned (google, etc) is that those lessons don't necessarily matter, and... look, google did XYZ, you can too (ignoring that they threw potentially 3-5x as many people at problem XYZ than you even have, much less justify).
Maybe neither of you meant that, but that was the connection I just saw between your two comments.
Every time I see some young developer posting on HN about how the code we write today only has to work for a year or maybe two at most, or how 10,000 lines of code is a large program, or how some high profile company's web site that is still fundamentally just forms and tables and an API for talking to a database is a complicated UI, I weep a little for the future of our industry and our lack of ambition. Of course things like performance and stability and standardisation and portability don't matter very much if all you ever do is hop from one small throwaway project to the next every few months.
I think the culture around HN is unfortunate in this respect, because from a commercial point of view, it is an alluring idea to build some sort of trivial MVP, try and get crazy amounts of funding, and then if (and only if) you succeed, to throw it all out and start over. As a business strategy for building the next WhatsApp or Instagram, that's rational and perhaps quite effective. But it also contributes to the everything-is-expendable mindset that plagues our industry, and since the overwhelming majority of software development projects don't have the luxury of starting over every five minutes, I think it breeds a lack of respect for professional programming and the skills required to build good software without the benefit of an effectively infinite funding source from benevolent investors (or from the goose that keeps laying golden eggs elsewhere in the organisation).
That might be OK for Facebook or Google, but I wonder how many other startups that fail could still have been very successful, albeit not in unicorn territory, if their developers had paid more attention to some of these issues. I wonder how much time humanity collectively wastes today just because software quality and reliability aren't taken seriously by too much of the industry.
You would never let a software engineer build a house, would you? For some reason, the discipline of architecting and building houses is far more advanced than building software.
Why is that? We keep inventing new programming languages to tackle various aspects of making software better (safe concurrency, preventing memory leaks, etc. etc.), but we keep introducing 5 bugs per Function Point and the rate of finding and removing bugs has stayed pretty much the same the last 20 years.
There needs to be a fundamental change in how we create software.
But more generally, the modern web development world is only just waking up to the idea that if you want to build software sensibly beyond a very small scale, you need tools for modularity and composition. Separation of concerns is important to preserve developer sanity and keep maintenance manageable. It is helpful to have well-defined, stable interfaces, whatever the current underlying implementation. Having an expressive language is good, but having an expressive language built on sound foundations and with consistent patterns and clean semantics is much better. Standards for protocols and formats are important. Performance matters, in many different ways. Quality matters. Portability and standards compliance matter. Longevity and stability and backward compatibility matter. Having a few good tools that work well and offer substantial benefits is much more valuable than having a million tiny things that change or become unsupported within weeks. Frameworks can be useful for getting going quickly, but you lose flexibility down the line if your requirements evolve beyond what the framework was designed to support and that can hurt. Libraries offer more flexibility, but you often incur overheads converting to and from their conventions and those overheads need to be reasonable if the library is going to be useful. Reuse is good but not always the best choice.
These and many other lessons in real world software development were brought to you by the words "developers older than", the number 30, and experience of programming outside the JS bubble. :-)
late reply, but something occurred to me to say more as a (hopefully funny) witticism than an actual talking point:
if we approximate usage in terms of a poly sum w/ coeff derivatives wrt time (Taylor series is the word, I think) then one might estimate lisp to be a very much used language
However, having witnessed (different shapes of) the wheel being reinvented over the past 2 decades, my take is slightly different: each language/environment has its strengths. If you have the luxury of having a senior team that's decently versed in several environments, then you can have your cake and eat it too: for each tool, micro-service, component... use the right language for that. Then tie it all together on the network. Since the system as a whole is likely to be a network product anyways, embrace it to your advantage.
Joe Armstrong wrote a good post[1] about connecting programs a few months ago, that's quite relevant.
Node.js is a great environment for many microservices. Got a task to do which is 80% done in some npm module? Make a node.js service around it. Same idea for Perl & CPAN, C libs, Java tools, etc.
[1] http://joearms.github.io/2016/01/28/A-Badass-Way-To-Connect-...
What I want is free-form records and structural types by default, nominal types only when necessary. I get more than half of that with TypeScript (it does lack nominal types but there are ways to get around that), and honestly its the half I prefer having.
And I hate to say it, but Go doesn't qualify as a serious statically typed language. No language without generics does.
I imagine a lot of these issues will settle down in the next few years as one or two sets of conventions become de facto standards.
> 'Show Call Hierarchy' will never be available when
> using a dynamically typed language.
True when "never" = "40 years ago". Smalltalk IDEs have had features for displaying call hierarchies statically and dynamically since essentially forever. And of course, in a dynamic environment the IDE vs. program distinction doesn't matter, so if you want to really know what's going on, just insert a self halt. and check in the debugger.
Smalltalk also introduced automatic refactoring, another canard of the "impossible to do in a dynamic language" variety. Really weird when "impossible in" = "invented there".
Yes, we can talk about how static type information can make some of this easier, but it also makes other parts harder (and the RB guys did talk about this, so the information is out there).
Please: if you want to diss JavaScript, diss JavaScript, don't say "dynamic languages". If you want to diss dynamic languages (please do!), inform yourself first.
I've started with Allegro Common Lisp, so i kinda know a thing or two about that.
The success of Smalltalk then speaks for itself?
There's always a multitude of ways to get something done, and it's up to you to decide what tool will do it best. Don't treat any one language as an end-all-be-all and you might find yourself much happier and more productive. Of course, YMMV.
Well said.
By the way, what is Netflix's take on Promises vs RxJS?
That said, we do make heavy use of Rx on the API layer (RxJava/RxGroovy). My team isn't currently using RxJs, but I expect that to change in the future. There are a lot of Observable fans here :)
We've been doing tons of research into the Netflix methodology and teams are highly compartmentalized (albeit communicate richly). This means that when you ask "What do you do at Netflix?" you should really be asking "What does team X do at Netflix?" or "Does any team at Netflix do X?"
For instance, unless things have changed or I have the story wrong, JVM is used for the streaming because that's the tool which that team chose. The other teams merely communicate with it over an API (regardless of client language).
What are your thoughts on that? When you're developing a service at Netflix, does it feel like you're building a single large application? Does the mentality of micro-services change how you approach code and therefore the validity of the original posts arguments?
1. I think the learning curve to doing good work with Node is really shallow at first, and then it quickly gets almost vertical.
2. I think that ALL of the other server-side language/framework combos (Ruby/Rails, Python/Django, C#/.NET, PHP/Symfony, etc.) make it significantly easier for a "merely-good" dev to make really good Web applications.
3. I think the kinds of devs that work at, say, Netflix are often the kinds of devs that can do amazing things with almost any dev stack, but that leads directly to my last point:
4. I think that most junior devs are making a tactical mistake with their growth, and with their careers, when they choose Node for their first forays into Web app development. The relative chaos and churn, and questionable suitability of Node for many-maybe-most use cases, make Node more trouble than it is worth for someone still struggling to make sense of the basics.
All of those frameworks are threaded/synchronous - they are maybe 10 times easier to use and potentially 100x slower (less concurrent) than Node. The ruby equivalent isn't rails, its eventmachine. Moving from django to twisted is probably just as hard as django to Node. 9/10s of the python ecosystem assume synchronous code so you end up with threads, processes, and callbacks.
If they would switch to more efficient languages, they could probably run on half of their current servers.
But there's the huge cost of rewriting something you already have. Will that affect your total cost significantly, if you can run on less servers.
I.e. it's too late to switch now. There needs to be a significant business reason to switch. "Stuff-that-kinda-works but needs more hardware thrown at it" is probably not a good reason.
Or is it remotely common to just have a single node process and never use more than one core?
But there are usecases that have to crunch numbers or do other CPU intensive algorithms that can be parallelized on the algorithm level. This is where node.js just falls apart. Additionally, if an algorithm requires quite much memory (multiple gigs), node.js performs very poorly.
Most companies that do actual CPU intensive work have services written in other languages to handle this, and "we're using node!" mostly means that they just serve results or do other IO-Tasks with node. But not the actual work.
You're getting downvoted because some of those frameworks had generators (some specifically built for concurrency) before the concept of ES6.
"Threaded" and "synchronous" are orthogonal concepts that don't deserve being lumped together with a slash. They can have significantly different effects on performance depending on the scenario. C#/.NET isn't explicitly threaded (or single-threaded) or synchronous, and it's right in the middle of your list. It has more in common with Java than with the other three. Keep in mind that there are node packages for threads, too.
Node evangelists often don't seem to get that non-blocking behavior isn't a Node exclusive. You can do asynchronous non-blocking code with C#. You can do an event loop and play node all day long with any number of threads you want. It's not that opinionated about how you run your code. There is a lot of old code that is synchronous. All languages have significant amounts of old code hanging around that drags us down. But things like the TPL, async/await and IOCP can make C# code perform significantly faster than Node. And it's in the middle of a serious public overhaul.
Java and the JVM can do this as well. Java itself might be a bit behind on language features, but it tends to outperform the CLR (also uses more memory). And libraries like Netty and Vert.x are seriously impressive. You can do incredibly amazing things with the JVM, and it's been one of the leaders in performance among GC-ed environments for a long time. You've also got the option to use languages like Scala and Clojure on the JVM.
I'll give you that Node applications might outperform Ruby and Python apps when running on the default environments. But those also can run on separate runtimes which can significantly boost performance. And we're ignoring less common server languages like Erlang which are quite suitable for certain situations.
You should also note that Javascript (and node) performance will be a bit questionable for a while, anyway, as the recent ES6 support has introduced a lot of performance wrinkles (https://kpdecker.github.io/six-speed/) that will take a while to iron out. ES6 adds some really attractive features, so expect node performance to drop (albeit perhaps only temporarily) as your package dependencies start adopting ES6-isms.
Just as there are hundreds of people jumping on the Node train, there are hundreds jumping off. Javascript tends to prototype rather quickly, which has huge drawing power. The constantly shifting ecosystem and the weak tooling, among other things, can affect its staying power. Some people are leaving due to code maintainability, others are leaving because of performance concerns, others are leaving because of ecosystem things like left-pad. There's a lot of variables involved in choosing a language, Performance is only one of them and no languages is a silver bullet.
We can pick on other languages all day, but there's always something to make fun of about our own language/ecosystem. So let's let people pick the tools they want and maybe critically evangelize a lot less. If they pick something ill-suited to their requirements, they'll just have to switch later. It's a pain, but it's not the end of the world.
And a big advantage of threaded is that it is (obviously) easier to scale to multiple CPUs, and I don't have to worry about one connection taking more than a handful of milliseconds and jamming up my server.
Node is fine, but I feel many of the speed benefits come from V8 vs cpython, rather than threaded vs async
And if you leverage parallelism of those languages they become 100x faster since they can do multi-threaded processing unlike Node.
Hope this doesn't come off as "I could do this in a weekend", just questioning how big the actual webapp is.
There are a number of different "UI areas" in Netflix.com -- homepage, titles, signup (multiple flavors of this, depending on how you're signing up), onboarding, member browsing/viewing experiences, account management, numerous partner integrations, etc... not to mention all the work that goes into per-user customization, AB testing, and internationalization.
No offense taken on the question. IMO, if you look at the site and view it as simple then we've done our job correctly. :)
The end result is they get frustrated and go back to their old language.
The trouble is that while you can do this for yourself to some extent, you can't necessarily do it for the people you have to work with. I've worked on a project where one guy came in to do a simple database back-end for an embedded system and decided Node and its ecosystem were appropriate. He seemed to have some experience with those tools, so the rest of the team went along with his decision. A year later, there was still little useful code actually running on the required platforms. One of the other guys got fed up and wrote the basic case using C and SQLite in less than a day. That guy did have some relevant experience and had been questioning the use of Node for that project from early on, but because the Node hype was so high-profile, management hadn't known which developer to believe. This is why it's useful to have articles like the one we're discussing, where people who have actually tried a tool in real life for a significant period of time share their experiences, even if those experiences weren't quite what they'd hoped for at the start.
The difficulty of getting Node itself up and running on the various platforms involved was a significant part of the problem. These weren't Linux boxes built around Xeons. It turns out that as soon as you go outside of the mainstream, the tools and documentation for building and running Node are awful compared to a lot of other languages.
The lack of standardisation and stability and the relatively poor dependency handling within the Node ecosystem were also major factors. Way too much time was spent just trying to make sure different machines really did have identical packages installed, figuring out how to pin everything down to make reproducible builds, and so on. Again, if you're happy just to shrinkwrap, npm install on your local machine, and wait if the repository is unavailable, that's one thing. However, as soon as you start talking about preserving exact configurations within 100% local build environments or building images to install on different machines, all kinds of problems crop up that have been well addressed by now within a lot of more mature language ecosystems but not so far with Node.
Another problem was that Node and its ecosystem are just so heavy overall, and this one is nothing to do with the variety of platforms in use. It's just a big runtime, and a lot of overhead because of the way libraries and dependencies are handled. This would be an issue for anyone operating with limited resources, whether it's trying to run something on a Raspberry Pi or trying to keep costs down by using the smallest possible instances of cloud-hosted virtual servers.
There did also seem to be an element of wanting to use the shiny new toys, and of stubbornly sticking with those toys for far longer than should probably have been allowed, so in that sense there were issues with the developer as well.
But there was also a willingness among the wider team to trust that developer, at least to begin with, because with Node's high profile and large ecosystem, no-one expected it to be as immature as it turned out to be as soon as you left the mainstream. For comparison, porting code written in traditional systems programming languages like C and C++ was done routinely, but even among the dynamic/scripting family, the more established server-side languages have caused far fewer problems than Node.
Can you be more specific?
> It's just a big runtime, and a lot of overhead because of the way libraries and dependencies are handled.
Compared to what exactly? I don't see any mainstream dynamic language except Lua doing better. Ruby? Python?
If you don't need native modules (which is actually the case in a surprising number of situations) there is no build process, except making a tarball of node_modules and the project. If you do need native modules, the situation is slightly worse than C or C++, but not significantly: you generally need to build on a machine with the same architecture (Setting up cross-compilation with C isn't very easy either)
> A lot of overhead because of the way libraries and dependencies are handled.
This has some truth to it, but in my experience its overblown. Being just a little bit careful with your dependencies goes a long way.
The Raspberry Pi 2 is a speed monster for node. Plenty of RAM. Here is a basic 2012 benchmark on the Pi 1: http://guidogarcia.net/blog/2012/09/13/node-js-on-my-raspber...
On the other hand, if you want to run node on something like this: https://www.olimex.com/Products/OLinuXino/iMX233/iMX233-OLin... that will definitely be a problem. Thats about the lowest specced hardware that can (barely) run it, but 64MB RAM just isn't enough, really.
P.S. Based on what you said, I have a hunch that most of your troubles came from this module: https://github.com/mapbox/node-sqlite3 - is that right?
Sorry, it wasn't my part of the project so I can't offer much detail. I know they never got as far as a Node build that passed the full test suite on some platforms. Many of the problems seemed to be around how floating point is handled on different types of CPU.
Compared to what exactly? I don't see any mainstream dynamic language except Lua doing better. Ruby? Python?
The total footprint for Node and supporting packages was taking up a few GB more than the equivalents for some of those other languages you mentioned. If you're working on a system where your non-volatile storage is something like a microSD card or flash chip, "a few GB" can be a huge difference.
If you do need native modules, the situation is slightly worse than C or C++, but not significantly: you generally need to build on a machine with the same architecture (Setting up cross-compilation with C isn't very easy either)
Sorry, our experience has been very different on both counts. Building on a machine with the same architecture isn't necessarily a reasonable option if you're targeting platforms that aren't general purpose computers, and at best probably means jumping through a lot of hoops and figuring out a lot of the details for yourself. In contrast, cross-compiling a language like C is straightforward and reliable, the tools for doing it are mature and well documented, and many developers who have worked in embedded systems are familiar with the techniques.
P.S. Based on what you said, I have a hunch that most of your troubles came from this module: https://github.com/mapbox/node-sqlite3 - is that right?
No. The person doing the Node version was trying to use some of the NoSQL tools, and seemed to be spending much of their time documenting and implementing things you get as standard with a SQL database. The person who wrote the C based alternative just used SQLite as a demonstration of how much easier and more robust everything could be using a different database instead.
One of the striking ironies of the project was that although in principle a dynamic language like Node doesn't need a compilation step, just the JS source, while C code has to be compiled for every target platform, the reality was that getting the C code running was dramatically easier. A well-made C library like SQLite could be installed, cross-compiled and running on all the required platforms within literally a few minutes, while Node and several major packages were so flaky that the equivalent level of real world functionality was never achieved even after several months of work. Again just for comparison, some of those other dynamic languages you mentioned were in between but much closer to the shorter end of the spectrum. The Node ecosystem, in our experience, proved to be an exceptionally bad choice for this sort of work.
I might concede that the node ecosystem does have a disproportionate number of people with this mindset though :)
By the way, cross-compilation is also an option, although I haven't personally tried it:
https://github.com/mapbox/node-sqlite3/issues/249
A plus would be that only native modules have to be compiled, and only once. After that its possible to set up downloading them as binary blobs.
You got me curious about the application, by the way. If you let me know what it does, it might be fun to try and implement a prototype in node (with sane dependencies and easy to deploy on a RPi)
(Edit: That said, the difficulties with size, portability and dependency management in the Node ecosystem that were exposed by this particular project are more general flaws with that Node ecosystem and not specific to this particular developer.)
You got me curious about the application, by the way. If you let me know what it does, it might be fun to try and implement a prototype in node (with sane dependencies and easy to deploy on a RPi)
It really wasn't anything very complicated by database standards, just storing some settings in a central place. Those settings were a bit more complicated and inter-related in this case than you could conveniently store using something as simple as a plain text file, so a lightweight database was the next logical step. As mentioned before, it was the kind of thing where you could implement the basic infrastructure required within a few hours using more suitable tools.
So honestly, I really can't relate to most of what you said here :)
"Choose your own tools" is advice for experts, and literally nobody else. It smacks of the cowboy attitude, and that attitude is wildly unhelpful to almost anybody doing professional work in software. Frameworks and coding standards exist for a reason: not to be unreasonable strictures, but to provide guidance and sanity in a staggeringly complex field of endeavor.
Many new devs and junior devs are flocking to the JavaScript ecosystem, and it is one of the most troubled and chaotic ecosystems in all of software right now. Anyone who is not a complete JS badass is simply not going to find Node to be even a decent choice for learning best practices pertaining to the larger world of application development. And I feel I'm stating that politely.
So: yet another JavaScript Pro tossing out the "choose your tools like a Pro" advice-morsel is part of the problem, as I see it. I don't want to work with people who toss the kids into the deep end and hope a few can learn to swim real quick. I think people deserve a helping hand and a reasonable set of expectations.
The JavaScript ecosystem has become self-parodying. Anyone who is oblivious to that fact is inherently NOT a trustworthy witness. That is not to say that the whole thing is rotten and worthless, but it IS messy as heck, and refusing to acknowledge that is a sign that one is in denial about some pretty blatant facts.
Isn't that the case basically all the time? Which is a perfectly suitable reason to avoid it at all costs except for the bare minimum required for front-end..
No, ES5 to ES2015 is a HUGE leap. ES2015 to ES2016 is a very minor jump as it only adds 2 new things to the spec.
> Which is a perfectly suitable reason to avoid it at all costs except for the bare minimum required for front-end..
And honestly, that is not my job to tell you not to do. If you want to avoid Node.js go ahead. I feel Java is something I should avoid at all costs. Doesn't make Java any worse or better. Same with Node.js.
Others don't have that luxury and just can't afford that.
And if your software needs to be around for more than 5 years, you want to keep your costs low.
How long would it take you to find a bug given a stack trace from a Node API with close to no clue which part part of your app registered that callback that isn't called because of the error?
Chances are, you don't even measure the time spent in code archeology as I like to call it. The time probably is not significant right now as you kinda know your way around your code base...yet.
I've been using the same tools for the last 7 months outside of switching from Angular 1.5 to React because I'm not a fan of Angular 2.0.
> Others don't have that luxury and just can't afford that.
Then don't? What is this sense of needing to change everything because something else comes out, that developers have?
If your current toolset works, why change it? Why rewrite a monolithic app in another fancy language or tool just because someone wrote a blog post boasting about that new tool/language?
Promises let you throw errors normally. They will propagate up the call stack in a similar manner. With bluebird, you will also get full stack traces in development mode and the performance penalty for that isn't too bad.
> The last thing that I found frustrating was the lack of standards. Everyone seems to have their own idea of how the above points should be handled. Callbacks? Promises? Error handling? Build scripts?
Promises are in ES6 (i don't think it gets more standard than that) and have well defined semantics, including error handling, shared between libraries: https://promisesaplus.com/
I know that Bluebird's promisifyAll might seem like a bit of a hack, but just try it out. It works surprisingly well, and its really painstaikingly tuned for near-zero performance loss. It will probably be both less painful to do and more performant than any manual attempt to wrap a callback based API into a promise one.
http://bluebirdjs.com/docs/warning-explanations.html#warning...
If it doesn't do that for your case then its likely that it needs some fixing - you should probably open an issue and we'll try to reproduce it...
Also, thenlint might work for you: https://www.npmjs.com/package/thenlint
https://github.com/pjungwir/node-errors-talk
At the time the solution was "use domains", but I think domains are deprecated now. It was painful enough that I have stuck with Rails since then. I'm glad to hear that Promises are an improvement!
* V8 needs to optimize try-finally
* Node core needs to add try-finally at every single place where callbacks are invoked and make sure all state and resource cleanup is properly done to support domains
* Popular libraries need to also add try-finally handlers for the above.
As to why this is a problem in node and not so much in other languages, its because with node callbacks, the call stack goes both ways. In other languages, libraries mostly call their dependencies' code. In node's CPS style, you call the library but the library also calls your closure code. The semantics for the 2nd part aren't well defined in node - the loose law basically says: I wont call you twice, I'll try not to call you synchronously, and you wont throw (and if you do the behavior is undefined).
With promises there is a contract and its enforced by the promise implementation. Since Promises actually have error semantics, you can build resource management strategies on top of them. http://promise-nuggets.github.io/articles/21-context-manager... - and consequently there is no reason to crash your server on errors.
Perhaps that is the reason that people have become more conscious of making _drastic_ changes -- rust and go are examples.
On a related note, it seems like every time you find something that doesn't quite work correctly or conveniently in Node.js there is a "fix". Don't like callbacks? Force Node.js to look more like other "normal" code and use Promises. Having trouble getting Node.js to concentrate on one thing at a time? Force Node.js to look more like other "normal" languages and use the "async" library. And it just goes on and on and on. If I have to use all of these other pieces and parts to be productive in Node.js I may as well just use some other language.
I really wanted to like and use Node.js, but Javascript and the community are holding it back.
The js world is very unique in its ability to evolve quickly and things have improved massively over the last few years. Now, apart from the churn itself and precisely because of that rapid evolution, front end and backend development in javascript is amazing compared to most other options (especially on the front end). So while you do have to be realistic about the cost of the evolving ecosystem, it is just a tradeoff for rapid progress, not a flaw.
If you crave stability, agreed, this rollercoaster probably isn't your ride. But the evolution of node, the emergence of react/redux, es6, etc is amazing and beautiful IMO and I'm totally enjoying every bit of it compared to the staid mediocrity of my Rails, C/C++, and Java history.
If you are comfortable with the constant change and evolution in a platform/language/framework, then by all means continue to use it. Just don't disparage people that come forward and point out the pains they have and say that everything is fine. Just my $0.02.
As you've pointed out some of these libraries make things behave a lot more similarly to other languages. And in such a case you may be better off just using one of them. However you're giving up on a lot of the power and benefits javascript provides, so of course you'd want to use something else.
For all of its pitfalls and annoyances, javascript is too powerful a language to ignore. Asynchronous operations and streams are just too good. They are difficult to balance but once mastered you can really do a lot with them.
My recommendation would be to skip libraries where possible. Use raw ES6, or Typescript. Something javascript has been suffering from for a long time is bloat from external libraries. You don't really need to use them, especially now that the language has more or less settled down.
All of the best libraries were used to normalise things and that's not really needed anymore.
I'm sure there's one other language out there that does it too but I don't know what it is.
Event based programming effectively means that as long as it has something to do it's doing it. You tell it to wait? It says great I've got all this other stuff to do.
Streams you may have me there, I didn't realise those were so widely used in other languages. Javascript works pretty well because you can run it on the whole stack. Share code between the front and back end. Stream from one place to another and around the corner.
It also allows you to mix in worker threads that are allowed to block (for I/O, for example).
You can develop in JavaScript, Java, Ruby, Ceylon, Groovy.
It's fast, async and robust.
That means that if you are using a 3rd party library, it will be async from the start.
In something like python you need to work to get a fully async app, but in node you should file bugs if something blocks on IO.
And I think exception handling is much worse than passing errors up through callbacks. It forces you to think about edge cases. Not sure how python handles this, but I can't tell you how many times I've seen Java or C# code swallow exceptions which is much harder to debug IMO.
People really seem to have a problem with there not being "the one true path" in Javascript, but it's not something that gives me much anxiety. Javascript is incredibly moldable, which is part of what makes it so powerful.
Author actually wants to use Python. Used Node.JS regardless, for whatever reason.. It did not work the way Python works. Author is frustrated. Complains that JavaScript is not Python.
It's like saying
"JS is stupid because people use braces and whitespace to denote flow control"
Adopt the paradigm and see how well the technology fits it
Although couched as a criticism this is actually the community fixing itself. The evolution from Grunt > Gulp > npm scripts is movement away from needless complexity towards simplicity. Npm scripts are effectively just Bash commands that build and manage your project, which sometimes employ small, unixy tools written in Node.
This self correction was pretty quick, it happened within a few years.
> Unfortunately, there isn’t any one “standard” (like everything else in Javascript) for implementing or using Promises.
Yes there is. It's called the Promises/A+ spec, and its built into ES6.
https://twitter.com/sindresorhus/status/724259780676575232?l...
https://github.com/ReactiveX/rxjs/blob/a3ec89605a24a6f54e577...
Already people are coming up with new "solutions" to this problem that looks more like Grunt. It's a repetitive circle. Personally I just use Make.
Npm scripts are really just shell scripting, which means all the real progress happens in the unixy Node tools that do the heavy lifting, where it should be. It's a future proof and scalable approach for the vast majority of projects imo.
> Npm scripts are really just shell scripting, which means all the real progress happens in the unixy Node tools that do the heavy lifting, where it should be.
That's fine, but you're missing critical features that Make provides; make won't even rebuild a target if no files have changed.
>then you separate your "test" into one for the browser, one for Node, one for CI,
For the love of God why. Don't turn every language into Java
>then you separate your "test" into one for the browser, one for Node, one for CI,
For the love of God why. Don't turn every language into Java.
Plenty of tools will not rebuilt a project if no files have changed, but the dumb, quick and easy way that requires no deendendencies is simply to delete and rebuild.
The fact that this functionality is served so well by a simple dependency shows that you don't need overly complex monolithic tools to accomplish small tasks.
> That's fine, but you're missing critical features that Make provides; make won't even rebuild a target if no files have changed.
WebPack does this for me too. Also my ava tests don't rerun for files that haven't changed while watching.
Genuinely curious, what scenarios precisely do you find this feature of Make useful?
Also, Make isn't truly cross platform ... and since I sometimes work with Windows devs this would be a problem.
And the Promise/A+ spec is so bare-bones, it is laughable. And the actual issue is that not every module is embracing it yet.
Sure, it will all be fixed. For freeeee :)
Interested in sharing more model logic between our front- and backends, I also investigated writing some new backend features using Node (we're currently developing with Rails). But after days of research and playing around with the available options, I came to a conclusion similar to Gavin's -- any reasonably complex backend requires you to either roll your own everything, or try to cobble together literally hundreds of tiny dependencies that weren't built to go together, and then somehow keep track of all of their regressions and breaking changes.
Node's fantastic performance and unique ability to share logic between client and server are enticing, but I just don't trust the community and "best practices" around it enough to bet the farm on it for now.
Its much easier to do your own research and find the best module to solve a particular problem you are having then to shoehorn into some larger monolithic framework.
Also its a lot more fundamental then that - Node.js has prolly the fastest iteration cycle for any platform out there since its so easy to create your own module - it leads to some sort of Cambrian explosion of innovation and experimentation.
EDIT:
Also OP seems to think callback hell and async programming is bad. The important thing is those things are problems for python/.... too !
Its just that python doesn't have a good programming model to even begin to address those concerns.
JavaScript at-least tries to say - "hey this is a problem we need to deal with - concurrency is a issues we all face "
So when devs complain about callback hell - its just that they have never tried to use python to do async in a neat way.
This isn't even close to true. Anything JavaScript has to express logic in the face of asynchrony, Python has too. There are a half-dozen asynchronous web servers written in Python.
There's not as much of a culture of writing APIs that way in Python because it's generally a terrible way to program, and threads/OS processes are good enough for basically everything except HTTP servers with absurd numbers of concurrent connections.
I would love to see evidence for you making that statement. Almost every programmer would put out their fav programming language as the 'right' way to program.
> everything except HTTP servers with absurd numbers of concurrent connection
Once you introduce async operations in your code - you need to follow the execution path through. http request can be async - but then what if the http request results you doing a db lookup or some form of file handling ? you need to make the whole thing event driven.
Both nginx and Apache's event MPM handle HTTP connections with events while the app backends are still using preemptive threads for running the HTTP handler code, so it's clearly not the case that "you need to make the whole thing event driven." You just need programmers who don't think, "well since the browser doesn't expose threads to JavaScript programmers, clearly they are useless."
Things I like:
* Async libraries make it easy to make things high performance.
* I like Sequelize as an ORM, once I figured out how the async everything works.
* The testing support is pretty good, both mocha and e2e testing using selenium
* The angular-fullstack generator was really helpful for getting started and setting up the deploy to Heroku.
* everything is open source. If I get confused with what a library is doing while I'm debugging I can just stick a print in the lib temporarily.
Things I don't like:
* "undefined is not a function". When something goes wrong. This is the error I get 80% of the time.
* async stuff silently swallows exceptions unless I put try{} catch(err) { console.trace(err) } everywhere
* There's a bit of a learning curve with promises.
* Needs a lot more automated testing than a really strongly typed language like Scala.
* Single Threaded. I know how to program using threads, so I view this as a disadvantage.
* No types. I have a lot of type checking asserts at the beginning of dao functions.
If I did it all again and my teammates would oblige, I would have probably chosen Play/Scala. I actually reimplemnted things from a Play/Scala project I did a while back (login/signup/forgot password/confirm account) and it took less time in Play/Scala, even without passportJS and friends. I have about a years worth of experience learning Scala before I started that project, so it would probably take longer for a new Scala developer.
There's no need for that:
process.on('unhandledRejection', err => console.trace(err))I don't know why people keep saying node.js is "high performance", the numbers I've seen basically put it in the same ballpark as similarly architected apps in other languages, as long as the other language has a reasonably performant toolchain. Perhaps people are used to old Ruby on Rails performance problems?
Huh? That's not how async errors work in Node. Try/Catch is not async, the catch block will not magically transfer to your callback function.
You check for the error as the first parameter in your callback, that's the standard way of error handling. Throwing errors in Node is considered by most to be an anti-pattern.
Sequelize is painfully slow unfortunately, I don't mean a bit slow like most ORMs I mean really really slow. It shouldn't be used in production.
The majority of established companies that say they use Node in production are doing so as a fancy proxy. All the "serious" stuff is done on backend services written in other languages.
Moreover, asynchrony is a concept far more advanced than most people think.
We will likely continue to leverage Node as a fancy proxy. Adding Typescript will only help. But it's likely that as Node grows into a mature platform, other platforms will continue to fill in the gaps that Node filled.
See for example Node constantly adding [foo]Sync versions of methods, while Python adds first class sync support.
The whole async situation needs to settle down, it's completely unacceptable to write code with callbacks, promises, etc. This is because they are not just challenging to deal with, but intrinsically wrong in concept. I have to wait for a database query to complete, then pass the next thing to do to the callback of the query? That can't be right.
Interesting article I found: "Async/Await: The Hero JavaScript Deserved" https://www.twilio.com/blog/2015/10/asyncawait-the-hero-java...
Use Promises for things that happen once, event streams for things that happen 0 to many times.
I find you run into trouble when you start mixing them. If you use observables for 0-N events and promises for 1 time events you're always converting between the two.
If one uses mongodb (popular on node.js), and one needs multiple queries to 'join' several documents, the cascade of callbacks is an obstacle to readability, let alone debugging.
I'm not calling it a Panacea but Promises are idiomatic Node Javascript now and there's almost no reason for mutliple levels of nested callbacks anymore.
$username = get_username();
echo "Hi, ".$username;
do_other_things();
In Node, using promises, you have to write: get_username().then(function(username) {
return res.send("Hi "+username");
}).then(function() {
do_other_things();
})
And if you're using regular callbacks, forget it: you'd have to nest do_other_things in the callback of get_username(!). It just makes things very awkward.I understand what you mean about sync vs async calls. I won't pretend I have a better solution. I don't mean to say callbacks are illogical, just a bad way to write programs. So maybe not 'wrong in concept', I can concede that. But I think async/await can make things more readable again, i.e.:
var username = await get_username();
/* carry on... */ var username = getUsername();
var resultSent = username.then(username => res.send("Hi "+username"))
var otherThings = doOtherThings()
return Promise.all([resultSent, otherThings])In the programming model used by most other mainstream languages today, if you've got some work to do that interacts with some external system and might take a while, you'd probably start another thread for that task. You'd write the required logic in the usual linear fashion, and just let the thread block if and when it needs to. Modelling this using fork/join semantics and techniques to co-ordinate access to shared resources from different threads are reasonably well understood ideas.
Because there is no general support for concurrency and parallelism in JS, you only get one thread, and so in most cases you can't afford to ever block it. Consequently, you get this highly asynchronous style that feels like writing everything manually in continuation passing style, just so you can carry on with something else instead of waiting. That in turn leads to callback hell, where you start to lose cohesion and locality in your code, even though usually you're still just trying to represent a simple, linear sequence of operations.
Async/await help to bring that cohesion and locality back by writing code in a style that is closer to the natural linear behaviour it is modelling. However, even those feel a bit like papering over the cracks in some cases. Async/await kinda sorta give us some simple fork/join semantics, but as the blog post linked from the parent shows, we have a lot of promise-based details remaining underneath.
Fundamentally, the problem seems to be that JS is increasingly being used to deal with concurrent behaviours, but it lacks an execution model and language tools to describe that behaviour in a natural, systematic way as most other widely used languages can. Being strictly single-threaded avoided all the synchronisation problems in the early days, when the most you had to worry about was a couple of different browser events firing close together and it was helpful to know the handler for one would complete before anything else started happening. I'm not sure it's still a plus point now that we're trying to use JS for much more demanding concurrent systems, though.
Writing thread-safe code is anything but easy in languages that support threads.
Dealing with shared state is not always easy when you're working with multiple threads. If you can't reasonably avoid that sharing because of the nature of your problem, and if your choice of language and tools only provide tools on the level of manual locking, then I agree that writing correct, thread-safe code has its challenges.
However, there are plenty of scenarios where you don't need much if any state to be shared between threads. That includes almost every example of JS promises or async/await that I've seen this evening while reading this discussion and the examples people are linking to.
There are also plenty of more sophisticated models for co-ordinating threads that do need to interact, from message passing to software transactional memory. These are hardly obscure ideas today, and I don't think anyone could reasonably argue that for example message passing makes things complicated but async/await/promises make things simple.
Look at the following code: https://paste.ee/r/LJnhg
I have function requestFromService and another readFromDB. On a single thread, I issue one request to a service and one to the database server, and you think it makes sense for the thread to just wait around? In javascript, the second I issue those two requests, the thread is available to now serve the next incoming request or do literally anything else while those services take as long or as little as they need.
The code itself could not be more clear as to what will happen, except for maybe the syntax Promise.join(), which was only there to illustrate how easy it is to do concurrent, asynchronous tasks.
You don't have to think twice about what to do while those requests carry out, and it's not like you had to write your code in a complex manner to take advantage of the asynchronous nature of JS, it just inherently works that way. Maybe I have gone and served 5 more requests while the db server was responding, and I didn't have to even be aware of the concurrency whatsoever.
My personal sentiment is to just use Promises, like everywhere. ES7 async/await will really help with this too.
Very well-designed and thought-out, fast, productive. Leans functional and immutable rather than object-oriented and mutable. It's kind of like Rails but without most of the problems.
For error handling, bluebird's typed error catching (http://bluebirdjs.com/docs/api/catch.html) is working well for me and I'm finding it analogous to my experiences with Java and Ruby.
I'm rather used to using ORMs as well and I use Bookshelf (http://bookshelfjs.org) on top of Postgres for this as well. It definitely has room to grow, but it's also fine.
I've also gained a dependency injection container (Bottle.js, see my write up here: https://blog.boldlisting.com/declarative-dependencies-for-un...), which I sorely missed in my Rails days and which gives a lot of structure to the application.
I think the biggest concerns on which I'd agree with the author are the pace of the community and lack of agreement on things which are well-decided in other, more well-established development environments.
That being said, there's huge potential with Node because of that. There are more coders in the world than ever (I'm assuming) and Javascript is a great low barrier to entry language that encourages people to explore various runtimes. In 20+ years of coding, I've not seen this level of excitement and engagement in a development environment. While it may be rocky for another few years yet, I suspect we'll end up with a very productive platform, simply because of the amount of involvement. Of course, it's totally understandable to want to wait for that before jumping in. :)
As a relatively new Node developer, I'm much more concerned about the single-threaded nature than the development environment, but so far even that hasn't been a problem.
But Node has been around since 2009. 2009 JavaScript was missing a lot of features. It was basically a runtime only advanced users should use. The Node maintainers had to make a lot of decisions that now conflict (to some degree) with fixes that have come later to the language. They chose their callback style; now we have Promises. They chose to throw in methods rather than return an error in the callback (this makes it awkward to use fs with Promises without a wrapper library). They chose to implement their version of CommonJS, now we have the .mjs issue arise.
JS has evolved a lot in the past few years, and with it came all the new shiny tools that left us confused.
I think a year was too short for the author. Sounds like they were chasing after every cool thing to make life easy.
Error handling is a pain yea, I've seen amateur folk try catch this and that, I think that lends itself to being terrible.
One of the things I appreciate the most about JS is JSON. Crafting tens of classes in Java irritates me. I find Python sometimes tricky also when dealing with structs VA lists.
I've always stuck to the basics when I was learning how to JavaScript with Node. I used only callbacks for 2 years until I understood what my code was doing. Granted, I'd have spaghetti at the end of complex async queries, but I understood what was going on. I moved to caolan::async and have been using async whenever necessary. I barely use promises as I got confused by the early adoption craze.
I learnt how to use Backbonejs, and a bit of Angular+React+Ember, but I found myself comfortable using vanilla JavaScript. Only thing I use is Underscore templates. I know I could benefit from shadow DOMs etc, but I'm content where I am.
I think a good way to learn is to take things at bite sized chunks. I've started using RxJS recently, and I'm loving it! I'll keep using JS as my primary tool, but I'm slowly moving to Kotlin.
My recommendation is to just use songbird (which exposes the forthcoming promise API from core, built on bluebird), async/await and the async `trycatch` library so you don't have to worry about a 3rd party package's choice of asynchrony. It also comes with optional long stack traces.
> Songbird adds promise to Object.prototype
Eek
in my experience, async/await is a great way to layer indirection and obfuscation over what is still callback hell. it may look better in the editor, but it's hell to debug.
EDIT: Oops, I misread the parent. You're right, async/await isn't easy to debug, but it's getting better, and it's a tradeoff. For now, I recommend debugging the compiled code (using generators) without source maps to avoid some of the quirks of source maps. In my experience, the tradeoff is worth it for new node.js developers because it offloads the asynchrony contract (e.g., calling a callback OAOO) to the language.
Here's a good article on promises that helped me, especially since I had seen a lot of misuse in JS land before I started using them:
https://pouchdb.com/2015/05/18/we-have-a-problem-with-promis...
Despite the sounds of this, I do like the idea of having an experimental platform with which to gain experience using wildly different approaches to the wildly changing world of web apps. I don't take it for granted that old language concepts will turn out to be the most useful for the web platform.
So, I'm okay building a website for the PTA or ceramics club with this, and I'm very interested in the experiences of others using a wide variety of technologies and approaches, but I'm not sure Node.js would be a sensible foundation to build a business on.
javascript is not new, it's been around since before most of the web devs out there started working in computers.
nodejs supports multiple CPUs.
nodejs is stable.
JavaScript is retarded fast, and it's not c or c++ or any Compiled language, and shouldn't be compared to them because that's unhelpful as a measure.
it is the only language for the web which enables you to work in the same language on both fronts.
frameworks aren't JavaScript.
nodejs isn't JavaScript.
JavaScript is so flexible that it can be changed to suit the needs of those writing it, so much so that you get whole new dsl's like typescript.
there are more conversations on the internet about JavaScript than any other language being used today.
oh and nothing scales if you don't know how to write scalable software, that's on you, not the language.
We switched our backend from Python to Node almost 2 years ago now and it was a great decision for us. If you handle a code base that deals with a lot of async requests Node is definitely a top contender.
As so often said, it was true for me that the abundance of modules and choices in node was at first very confusing.
I eventually figured out that keeping things as simple as possible was my best approach. What I came up was a server relying on very few module dependencies and written using consistent if not so elegant components. Sure it's kind of verbose and far from totally DRY but fairly easy to understand, modify and extend.
Key issue was node's "callback hell" style of async programming. Of course, it's not just node, other languages (Scheme, FP, etc.) can be mind-bending in a similar way.
The callback "inside-out" locality inversion was initially hard to grasp, but once I caught on it was possible to get the server working the way I needed it to. The more recent development of promises, etc., certainly provides reasonable ways to reduce the high barriers implicated in using the nodejs style of async programming.
Tooling has never been more important to my productivity with a language as it has been with JS. I constantly search for tools to paper over the warts and potholes.
Reading his "Why I’m switching from Python to Node.js", doesn't seem like he was having an issue with that. And I don't really buy into the "same language everywhere" argument because come on, how hard is it to learn python, ruby, etc enough so that you can be productive? Not hard at all, unless you have hundreds of cubicles filled with drones.
Anyway, it's good to see that he made some reasonable conclusions after the experiment. That's a good sign :)
Also can make it easier to write in SPA style but offload rendering to the server when you need it (particularly first-page or reloads).
Whether or not tooling is good enough to allow this (either with JS or compilers) is another issue.
Promises are standard in ES6 and it is "the way" to handle errors. At least if you want to stay sane.
What I really enjoy is jumping into new community and getting to work with tools that have built. Choosing the right ones can make or break an experience. I personally enjoyed working with Express and Bookshelf.js/Knex.
I appreciate the authors perspective, but I also don't think this should deter anyone from trying out Node. I personally have no overwhelming preference to using a Python or Javascript stack.
After ruby orms, Bookshelf felt very, very underdeveloped. Anything I tried to do beyond "hello world" only brought me pain, especially dealing with associations, but honestly just about everything. I guess I've been spoiled, but getting anything done in express/bookshelf combo seemed like a chore.
Callback hell and error handling are no longer issues in node if you just embrace generators or async/await.
We use Koa in production and serve billions of requests just fine.
If I had to go back to Express I'd say no.
For instance multithreading should be handled by languages and frameworks 99.9% of the time. Take reading a file (something that should be handled by the language/ framework). Read it asynchronously, structure any dependant code clearly (which JavaScript does pretty well), if any problems are detected they display/ log the appropriate error. You shouldn't be kneck-deep in callbacks.
I want to write a quick script doing some busy work , I now have to think about synchronicity even though the script does not need to be non blocking. Of course in these circumstances, I want to move back to Ruby or Python, which actually let me code the thing I want to code without forcing callbacks on me.
So when you have to do 20 i/o operations in sequence, using nodejs becomes really tedious.
I had similar experiences to the OP. I had lots of code written in JS that I was happy with to some extent, but all of it would have been easier / cleaner / more maintainable in a less crap language.
It's not even about Node. It's about anything that isn't Python, and doesn't have the Python community's strong "there is exactly one way to do it" tradition. I'm glad OP has realized that's what works for him. It's a shame he lacks the perspective to understand that it's about him.
I hate that JS trys to be this OO-FP hybrid. Jack of all trades, master of none.
while JS is far from perfect, his problem was he was a little bit ahead of time- babel, standard promises & sequelize solve most of the problems. I think Python is still superior for serverside, but JS isn't as bad as portrayed in this post, if you slowdown for a couple of weeks to learn how to use it properly (just like any other popular language or framework).
https://medium.com/@yoooodaaaa/reflections-on-node-698abecce...
tips: Always throw errors! Use named functions!
Is it the right tool for X or Y? I can't say, I'm not a dev. But it does require a lot of hand-holding and keeping current with the zeitgeist.
I feel so lucky to have avoided the whole disgusting web stack.
I really think it is setting the programming world back a lot. Not to mention what a thoroughly shitty language JavaScript is. Being able to code your web app in one language is a neat trick, and the ability to talk back and forth between client and server so seamlessly does kind of feel like magic, but otherwise, this is a meaningfully worse language/platform that Visual Basic.
- The fact that the ecosystem is evolving quickly is a good thing. Node.js is still one of the fastest growing software development platforms according to Google trends so you should expect it to change faster than other ecosystems.
- ORMs suck (in every language) - They always sucked; ORMs are a massive hack intended to fix the impedence mismatch between relational DBs and RESTful APIs. If you used a NoSQL DB with Node.js (such as RethinkDB), your life would be much easier. Nobody in the Node.js community except your grandma cares about ORMs because they're considered legacy technology. If you don't like it, then you can stick to your COBOL and Oracle database.
- Node.js lets you choose how you want to handle errors. JavaScript offers an Error class which exposes a name property (which you can overwrite for each error type) and you can also attach custom properties to Error objects (to carry back more detailed info specific to each Error type). JavaScript is really easy to serialize/deserialize so you can even design your error handling system to be isomorphic (same error handling on the client/browser and server). I really enjoy error handling in Node.js/JavaScript - You just have to put some thought into it.
- The way of writing async logic is changing. The fact that Node.js is keeping up is a good thing. There is no single right way to handle async logic. Most well-maintained libraries will keep slowly evolving to use the newer features of the language but it's mostly backwards compatible (many libraries support both callbacks and promises).
- The standards are not bad; they're evolving and you can choose your own styleguides for your projects. Most JS developers will adapt to new styleguides as they move between companies/projects.