I 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.
> Let's go ahead and compare with Twisted, shall we?
Oh goodness, yes.
How about an echo server. This one is from the twisted home page, so I am not knocking down a strawman.
from twisted.internet import protocol, reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
reactor.listenTCP(1234, EchoFactory())
reactor.run()
Versus in node you can do:
var net = require('net');
net.createServer(function (stream) {
stream.pipe(stream)
}).listen(5000)
This is what I mean by limited surface area. I shouldn't need to define 2 classes to write an echo server. An Echo class AND an EchoFactory? And on top of that I need to mess with a reactor? How does that pass for good API design?
The reactor is explicit. "Explicit is better than implicit." You don't have to always be in the reactor, if you don't want to. It lets people use Twisted to build GUIs and other things, without always being in the reactor's context. Twisted is a general-purpose networking library, not a tiny-web-servers-only networking library.
An example used to illustrate and educate does not necessarily result in the shortest code sample. That sample does not use twisted.protocols.wire.Echo, because it was decided that things should be explicit and obvious in the samples on the front page.
The reason for separating protocols and factories is simple: Sometimes you need to store per-connection state, sometimes you need to store per-server state. The separation permits developers to store things in factories instead of in global objects. Node doesn't have this distinction, and as a result, things like tracking all connections currently made on a server are cumbersome.
Another thing is testing. How should a person test the Node example? Every bit of the Twisted example is trivially instrumentable; I can access the protocol, the factory, the reactor. I could, if I wanted, replace the reactor with something mocked. There's no place to do that in the Node example.
I was gonna type out an IRC bot, the favorite exercise of novice coders, but I felt that would be petty, since there's no IRC library included in Node.
In javascript, as with other languages, you can totally use inheritance (prototypal in js) when making things. But, it's usually better to expose an object than a constructor (imo) when it comes to exports. Being expected to do something like:
var Foo = require('foobar').Foo;
var Bar = function (opts) {
Foo.call(this, opts);
this.baz = "biff";
}
require('util').inherits(Bar, Foo);
This sort of behavior is all well-and-good, but it should be contained because it's boilerplate-y. In javascript, at least, it's not a very good pattern, and I suspect this carries over to other environments (to an extent).
I also think that standard libraries have to strike a balance between "batteries included" and "not cluttered with a bunch of crap that was relevant in 1995", and that different standard libraries attempt this in different ways. I think python neglects the latter to supply the former, while node swings the other way and compensates by having a really nice package manager. Time will tell which is a better approach, but I'm betting on Node's model.
> The "radical reusability" section is just the author realizing that modules are awesome. Again, welcome to the party.
Modules are awesome! You sound like a python guy, meaning your module system is actually pretty good when it comes to qualified imports. Compare python imports to ruby's require, or browser-side script tags sometime, and I think you'll find that there's an awareness problem when it comes to qualified imports. :( That said, the package management side is kinda shitty for python (at least when compared to npm).
Seek to the next paragraph and try again. Paragraphs are atomic; if there's a read error or other corruption on that first paragraph, the second one should still be readable. You should be able to get the entire message out if you use the error-correction channel to compensate.
JavaScript is prototyped, not inherited, and doesn't permit the creation of new types. 0/10; troll using facts next time.
perhaps you guys are arguing semantics. i think it's fair to say javascript does not have traditional inheritance or classes. crockford seems to agree [0], perhaps i don't understand the argument.
What is a "class" in this context? Let's define it.
As a rough strawman to move forward, let's say that a "Class" is a programming object consisting of:
- A constructor method.
- A set of properties and methods
- Optionally, a parent Class from which it inherits properties and methods, which may be overridden.
And that, when invoked, a "Class" returns an Object which is said to be an "instance of" that Class. The constructor method is called in the context of the instance, and the properties and methods are inherited by the instance.
JavaScript has those things that I'm calling "Classes". In fact, every single function is a "Class" if it's just invoked with "new", and every single object can be a prototype. It's so full of classes, the only excuse for missing them is that you weren't even looking.
Please see almost any JavaScript tutorial ever for an explanation of the "new" and "instanceof" operators, or any from the last 5 years for an explanation of the "Object.create" method.
Or better yet, just sit down with the ES5 spec, and actually read it before you talk about what this language does and does not have.
Additionally, if you mean something by "object inheritance" other than "objects can inherit from objects", then I don't even think we're on the same planet. That's actually something that JS has which most other "object-oriented" languages don't have.
I'm done being trolled for now, I think. Have fun, kids.
i don't even know what you're arguing with to be honest- i merely suggested you and MostAwesomeDude have different definitions for class. which is exactly what your reply suggests.
classes create new types. this is precisely why MostAwesomeDude said "JavaScript is prototyped, not inherited, and doesn't permit the creation of new types". if you want to omit that from your definition of class then fine. but you're no longer talking about the same thing as MostAwesomeDude.
We're not actually at ES5 yet, and to be honest I have not read it completely.
I have read ES3 though, and I believe what they call "Classes" are the Array and the Number and the Date and the Boolean and most other globals that start with a capital, and you can find out the Class of a value by calling Object.prototype.toString on it. If you believe "Classes" to be these things, then yes, javascript has classes. It does not, however, allow you to create them yourself.
For what I have seen from ES5, which is not much, it is pushing Object.create, instead of the new X notation, which you were talking about (as the functions all being classes). According to your definition, things using Object.create are no longer classes, as they do not posess constructor functions (although you could still provide one and make it call Object.create). In this fashion, javascript is moving away from whatever classes it had, and into fully prototype-based inheritance.
Whether we think javascript has classes or not is mostly related to your definition of a 'class'. Personally, I think the "Classes" are not actually classes, just names for some native types, and the classes (which are actually classes) javascript does have (using the new X notation) should be abolished as soon as possible, as they look like a confusing attempt to make javascript less confusing for new people coming from Java or C++, by providing them with their familiar concept of classes. They merely guide people away from the powers of prototypical inheritance, instead of driving them closer.
By your definition, javascript is full of classes, but most of them are not intended to be classes, and they probably should not have been. (ever tried forgetting new when instantiating a class? that clobbers your global object massively, unless you use a detection-method to prevent it, further explained on the top answer at http://stackoverflow.com/questions/383402/is-javascript-s-ne... )
but it has prototypal inheritance, which is an equally valid inheritance scheme, which allows any object to act as a class.
It's a pointless argument, but many people like the way javascript inheritance works. Discounting it because it doesn't act how you want is not a fair judgement.
Its not about language syntax, its about culture.
You can do monolithic frameworks in nodejs if you want, but the majority of nodejs programmer (and substack is one of the better examples) just implement tiny modules with "limited surface area".
This is why nodejs is great. Its not because of js (although it helps), its about people.
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.