13 ms·
The node.js aesthetic
- gbog 15y agoHmm, seems a bit hand-waving to me, but to be fair I have never tried Node.js and would probably have hard time convincing my finger to type javascript code for server things. Javascript always seemed to me a language that you used, and tried to use correctly, because you had to. On a server I have the choice, right? So my choice is currently Python so I read this article with some bias. In the section "batteries not included": > modules in the core distribution get an unfair advantage over the libraries in userspace by virtue of availability and prominance. I would call it "unfair" if some modules had access to special backdoors and APIs, but it seem to not be the case for most modules I checked in Python. For instance, 20 mn ago, I did vim /usr/lib64/python2.6/unittest.py and could check this piece of code directly. I did see no special magic that could not be provided by other modules, like Nose or py.test. Moreover, the code was not looking like "neglected code", even if it did not look like the most modern kind. > experimenting, and iterating is much harder Well, that's what I like the most with core modules: they don't change overnight, and, while some of them like urllib(2) may be replaced by some because they have a better competitor, most of them are just good old friends, like scipy, that don't need to be put upside down every month because someone found a slightly more elegant way to call two of it's functions. > "core modules"' advantage evaporates in the face of baked-in concurrent library versioning and sophisticated package management. I have never been considered as a shy sysadmin when I was sysadmin. I am actually strongly against the "Tool X have misbehaved once therefore tool X is evil and will never put a foot again on my machine" philosophy. I know some guys who are. (I was also sound engineer before and mostly all musicians I met are this way, by the way). But still, having dealt with library version issues sometimes, I think "concurrent library versioning" and "sophisticated package management" sound awfully nightmarishly black-magic to me. I guess I would be more on the "let's understand the most of what happens and not change what don't need to" kind.
- hello_moto 15y agoMost people who just got into a new bandwagon are handwaving regardless.
- exogen 15y agoWhen is it going to stop being a bandwagon? Do we have to wait for you to start using it? James (the author) is probably the most prolific library author in the Node community and has a startup built on his libraries. Do you really think he's just handwaving and doesn't know what the fuck he's talking about? Node is just 3 months younger than Redis, software which plenty of people here use, or want to use, or at the very least respect. And yet when it comes to Node, all logic seems to go out the window for whatever reason.
- substack 15y ago> But still, having dealt with library version issues sometimes, I think "concurrent library versioning" and "sophisticated package management" sound awfully nightmarishly black-magic to me. I guess I would be more on the "let's understand the most of what happens and not change what don't need to" kind. Concurrent versioning lets you do the "not change what don't need to" part really, really, well. Versions of packages that have been proven to work well with one another can continue to do so because if you need a newer version of some library then both the old and the new version can live harmoniously in the same codebase. You don't need to be paranoid about upgrading modules anymore because node and npm are already paranoid on your behalf.
- moe 15y agobecause node and npm are already paranoid on your behalf. Yes, until npm blows up in obscure ways. Which it likes to do frequently.
- IsaacSchlueter 15y agoWhat do you mean by "blow up in obscure ways"? It generally dumps a ton of colorful errors to your terminal. If you find them obscure, please be comforted by the fact that I certainly do not find them obscure, and would love to fix whatever problem they indicate. It's actually my job. Also, npm is a software program, and not intelligent. It doesn't "like" things. To the extent that it has preferences, it loves semantic versions, accurate metadata, and especially you.
- moe 15y agoNot sure if your question is serious? Here's the obscure blowups that were filed in November alone; https://github.com/isaacs/npm/issues/1793 https://github.com/isaacs/npm/issues/1793 https://github.com/isaacs/npm/issues/1790 https://github.com/isaacs/npm/issues/1790 https://github.com/isaacs/npm/issues/1809 https://github.com/isaacs/npm/issues/1809 https://github.com/isaacs/npm/issues/1785 https://github.com/isaacs/npm/issues/1785 https://github.com/isaacs/npm/issues/1801 https://github.com/isaacs/npm/issues/1801 https://github.com/isaacs/npm/issues/1770 https://github.com/isaacs/npm/issues/1770 https://github.com/isaacs/npm/issues/1727 https://github.com/isaacs/npm/issues/1727 https://github.com/isaacs/npm/issues/1654 https://github.com/isaacs/npm/issues/1654
- Cushman 15y agoWell, that's what I like the most with core modules: they don't change overnight, and, while some of them like urllib(2) may be replaced by some because they have a better competitor, most of them are just good old friends, like scipy, that don't need to be put upside down every month because someone found a slightly more elegant way to call two of it's functions. And that's how you wind up using twenty-year-old code. Not that there's something wrong with that, if it works-- but what if there were a better way?
- untog 15y agoWhen we start thinking like that we start walking down the horrible path of changing things for the sake of changing them. Who cares how old urllib is? There really isn't a ton of functionality that has changed in URLs within, say, the past 12 months that requires us to constantly reinvent the wheel.
- ashearer 15y agoThe problem with urllib/urllib2 is that they're somewhat awkward to get started with for simple use cases, and just get worse as you get more advanced. Unfortunately, they're not quite bad enough to outweigh the standard-library advantage for most people, so they stick around. They should have been designed better years ago, but there we are: the curse of the included battery. That said, I don't agree with the OP's implication that just about everything would be better as separate libraries. Node itself has a sizable standard library, and it's generally well-designed. The start of a project is the riskiest time, and having to suspend work to evaluate multiple third-party libraries for every little feature is a huge distraction. 80% solutions close at hand could make the difference between a successful proof of concept and one that never gets off the ground. There are also positive network effects from having sample code written to a common API. Python's early failure to anoint a standard baseline web framework is a case study in the risks of avoiding a batteries-included approach. PHP later rose to take that space, and then Rails ended up being written in a different language. We can't know how an alternate history would turn out, but it was clear at that time that Python's web development community was hopelessly fragmented, hit by the double whammy of not including a web framework and making it so much fun to write your own. The OP does have a point I agree with, which is that having batteries included is less important than before, because package managers are so much better. That means we can hold built-in libraries to a higher standard. The other part of the puzzle is a way to bless a high-quality third-party library as a baseline for each common niche that isn't already in the standard library, so developers starting a project aren't spoiled by choice.
- 2mur 15y agoBut the point about project-local node_modules is that it is baked into the ecosystem. Directly contrast that with the reason that most people use virtualenv which is to not pollute the global python install with project-specific dependencies. It's just really well done. And javascript isn't that bad on the server when you're dealing with ES5 and not worrying about browser-specific js nightmare stuff.
- gbog 15y agoI have use cases for virtualenv, but on my dev machine, to emulate a prod machine setup. But on a prod machine I will have to question hard every line in the install log, and virtualenv may not stay in. For JS, I don't think it's only problem is with browser compatibility, it also has other flaws and need some patching before being usable, I've heard.
- dextorious 15y ago"""Javascript always seemed to me a language that you used, and tried to use correctly, because you had to. """ Hello, 90's called, they want their view on Javascript back.
- mikey_p 15y ago> But still, having dealt with library version issues sometimes, I think "concurrent library versioning" and "sophisticated package management" sound awfully nightmarishly black-magic to me. This isn't really much black magic to it, all the use cases are outlined in the docs: http://nodejs.org/docs/v0.6.3/api/modules.html#loading_from_node_modules_Folders http://nodejs.org/docs/v0.6.3/api/modules.html#loading_from_... The bits that NPM does, is take advantage of the way node loads modules, and process dependencies recursively. For example take a look at how a few global modules are installed on my system: $ npm ls -g /usr/local/lib ├── bootstrap-stylus@0.2.0 ├─┬ express@2.4.6 │ ├── connect@1.7.1 │ ├── mime@1.2.3 │ └── qs@0.3.1 This means that each of expresses dependencies, at the version listed, is installed into /usr/local/lib/node_modules/express/node_modules. Also, by default npm installs into the current directory, or project which uses the same package.json format that modules themselves do. I find this to actually be the opposite of "black magic" since you use the same tools to manage your project at the top level, that is used to manage all your packages and dependencies.
- jesusabdullah 15y agonumpy and scipy are poor examples because they're not core python modules. You still install them from separate people.
- gbog 15y agoTrue, let's say re, math, array ?
- zzzeek 15y ago>You don't need to reason about multiple instruction pointers or mutexes or re-entrant, interruptible execution because all the javascript you write just lives in a single thread. I see....on the other hand, when I write request-handling code using (any web framework ever on any platform), you're suggesting that we do worry about mutexes and reentrance (not to mention, handling a single request uses multiple threads?) and that these details aren't already handled by (any web framework ever) ? Interesting.
- wlievens 15y agoAs soon as you're doing anything beyond CRUD on a database, you will probably have to worry about them. Unless Erlang blablabla...
- exogen 15y agoNode is not a web framework. It's something one might use to build a web framework. So it's a bit silly to say that 'any web framework ever' already deals will this for you – well, duh, but the framework author certainly had to deal with thread safety (possibly incorrectly). And don't say no framework user has ever screwed up shared state because they didn't realize how threadlocal works or that requests might be handled in another thread...
- zzzeek 15y ago> but the framework author certainly had to deal with thread safety usually not. if your framework builds off the common web integration system for the target environment, i.e. Java Servlets, WSGI in Python, etc., you're already handed a request scope within a thread. It's only web servers and containers that really have a heavy lifting job to do.
- exogen 15y agoOkay. Clone the Rails repo and do this: git log --grep thread
- 15y ago
- sktrdie 15y agoThe way modules are looked up - localized to the piece of code that needs it, inside the /node_modules directory - is one of the greatest strengths of the node ecosystem. It's just dead simple and solves dependency conflicts like nothing I've ever seen before.
- phamilton 15y agoCould someone clarify something for me? Is http.createServer robust enough for production? It is my understanding that running it as is in production is not a good idea. You want to at least configure nginx between node and the world. If that's the case, doesn't that undermine the whole "focus on your application, not the configuration" point he's making? Sure you can call startServer multiple times, but then you would still have to focus on configuration.
- viscanti 15y agoI don't want to sound like I'm over qualifying things, but it really depends on the situation. For most applications http.createServer will be robust enough for production. There are node based solutions for dealing with load balancing, that would make nginx unnecessary in almost all cases. It really comes down to tradeoffs. If your primary concern is the most simultaneous connections, then you'll need to find a special tool, and Node or most other non-haskell web frameworks probably aren't for you. Node makes it really easy to do some things. That focus makes some other things more complicated than they should be (because it's asynchronous, you end up needing to deal with flow control, often times using queues that mitigate some of the asynchronous advantages). It's like everything else with computers. There's tradeoffs. http.createServer can be used when it can be used (which happens to cover most use cases).
- deleted 15y ago[deleted]
- jahewson 15y agoTo the best of my knowledges: yes. Using nginx in front of node seems to have originated as a non-root way of getting access to port 80, prior to node supporting setuid. A better way on Linux is just to use the kernel TCP routing, for example: sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080 However, if you're using HTTP virtual servers and you already use nginx, sure, place node behind it.
- peterbraden 15y agoit is robust enough in terms of scaleablity yes. Most people are just using nginx as a load balancer. This only addresses servers that you expose to the world though - I think one of the less publicised strengths of making creating servers easy is that it allows you to make internal servers for services trivially. And using a service oriented architecture is a great win.
- koen 15y ago> A big part of what empowers node to make these kinds of interfaces possible is its asynchronous nature. No longer do you have statelessness imposed from on high by the likes of apache or rails. You can keep intermediate state around in memory just like in any ordinary program. Should that not be: A big part of what empowers node to make these kinds of interfaces possible is its "statefull" nature. ... Really, that it is asynchronous is nice for performance (but only complicates the implementation). But the fact that you keep state in memory is indeed a big win for ease of implementation, and also performance, especially if state is not global but only relates to a single session. Of course, that is usually frowned upon by the web developer community which believes that this somehow hurts scalability (while it actually helps scalability).
- nknight 15y agoIt's frowned upon by people who need high availability with minimum complexity of hardware and software configuration. There's very little state one can reasonably store on a single web server without interrupting sessions if the server fails, and there's almost none you can store if you can't guarantee user X will always connect to server X for the duration of the session. Not everyone must solve these problems, but they quickly come to the forefront for anything beyond rather low-traffic sites.
- virmundi 15y agoI think the sessions in Node/Express are helpful when pair properly. For example, Express can use Redis as its session store. This has the benefit of making the session cross-cluster populated, while still being fast. Add to this the fact that almost everything in JS is serializable as itself and you get a pretty good replication mechanism.
- munificent 15y ago> So if a module "foo" was tested against and depends on "baz@0.1.x" and a module "bar" depends on "baz@0.2.x", then when you go to use both "foo" and "bar" in your own program, "foo" and "bar" will both use the version of "baz" that they were tested and depend against! That sounds like a recipe for disaster if I get an object from "bar" that came from "baz@0.2.x" and try to give it to "foo" which then gives it to "baz@0.1.x". I'm suspicious of silver bullets in general and I'm deeply suspicious of any silver bullet that claims to slay version hell. Versioning is hard.
- mikey_p 15y agoWhile I'm not saying that's not a real concern, I don't think I've ever seen code that would blow up from that. I think this comes from the concept of "limited surface area" that the OP outlines.
- benatkin 15y agoThe Law of Demeter applies here, even if traditional objects aren't being used. If the library that uses it encapsulates everything about it, or at least documents things that aren't encapsulated, it tends to work out just fine. http://en.wikipedia.org/wiki/Law_of_Demeter http://en.wikipedia.org/wiki/Law_of_Demeter
- MostAwesomeDude 15y agoI find the spinning in this article to be incredible. The "limited surface area" is all well and fine in JS, because there is no object inheritance in JavaScript. The author tries to emphasize usability over extensibility, which is a false dilemma in my book since it's possible to code to an interface in other languages. You define a usable interface, and then everybody codes things that fit that interface. You don't even have to care about whether your objects are inherited or composed. Of course, languages with inheritance are even more reusable because it's possible to inherit from, and extend, objects which implement the given interface. This is a key tenet of design in Java and Python. The second part of "limited surface area" talks about how namespaces and qualified imports are great. Yep. Welcome to the party, guys. You're only a couple decades late. The "batteries not included" section is a great dig at Python, but he could have bothered to actually bring up examples. It's easy; things like asyncore are so god-awful that it's trivial to point out where Python's batteries have expired. However, he's comparing apples and pomegranates here; Node is not a language! It's a framework. It has a large library of its own which doesn't come standard with JS. That library provides stuff which is built-in on other languages, like unit testing, cryptographic primitives, zlib, filesystem accessors, URL handlers, buffers, iterables, type checkers, and a REPL. To repeat: These are batteries which are native to other languages. Let's go ahead and compare with Twisted, shall we? I'll omit things for which Twisted provides protocols and Node provides streams, since those are (technically) equivalent. Node doesn't appear to contain these things which Twisted provides: Common protocols for handling lines, netstrings, and prefixed strings; non-blocking stdio as a protocol, serial port as a protocol, DNS as a protocol, a DNS server, a handful of RPC protocols like XML-RPC, AMP, and PB; and full suites for: NNTP, telnet, SSH, mail, more chat protocols than I care to remember... Not to mention powerful utilities like credential handling, and enhancements to the Python standard library like object-based file and module handling. And that's just what's included in the main tarball; there's a big community of third-party code which implements whatever you might happen to need. I didn't bother to list the reverse, because there is nothing in Node which is not in Twisted. "Core distributions with too many modules result in neglected code that can't make meaningful changes without breaking everything." Are you not aware of deprecation? Write the new code, mark the old code as broken or deprecated, wait a few years, remove the old code. This isn't hard. Of course, if Node or JS actually provided useful tools to mark things as deprecated, it might happen more often. Python's got DeprecationWarning; why doesn't Node? The "radical reusability" section is just the author realizing that modules are awesome. Again, welcome to the party.
- scubaguy 15y ago> Instead of the http server being an external service that we configure to run our code, it becomes just another tool in our arsenal. This is unfair. If I create a framework cal Java.js and make it possible to create a httpserver by running server.start(8080, aCallbackObject), does that make Java great? One day someone might make node.js "configurable" via a configuration file (that is not written in JavaScript). Will having a configuration file make node.js less useful? > Note also that the http snippet from earlier isn't inheriting from an http.Server base class or anything of the sort. That is also unfair. You typically don't use inheritance in JavaScript because you can compose objects or clone from a prototype. There is no static analysis of classes, which in the main benefit of classical inheritance. Programming via callbacks is simply the JavaScript style. This might even change when the language provides better support for classes, or when more people write their node.js code using CoffeeScript. > If software ecosystems are like economies then core libraries are at best government bureaucracies and at worst nationalized state corporations. This is very subjective and I strongly disagree. There is a great advantage in using a language and framework that has a strong core library and a common way of doing thing, especially when you start building teams or start recruiting people to maintain legacy code. If anything, Node should start including more batteries, such as a module for concurrency. PS - Here's the thing. I am really excited about the event driven nature of node.js and the community. However, I am new to node.js and I want to see quality critical analysis of its strength and weaknesses. If you are going to tell me its great, you better have pretty solid reasons. This article simply doesn't cut it.