News for hackers. Stuff that matters.
Re:To boldly go where Node man has gone before by kbd on Wednesday May 16, 2012 @02:34PM (#3983354)
So does Go's net/http module really provide basically exactly the same programming model as Node? If so, why use Node?

One thing the author didn't mention is that Go will use multiple cores in this example, whereas Node is single-threaded. Right?

Re:To boldly go where Node man has gone before by zemo on Wednesday May 16, 2012 @07:48PM (#3984672)
No, the model is completely different. In Node, you pass in a callback to establish what should be done following the return of a longrunning I/O operation. In Go, you use goroutines to manage the concurrency.

Basically if you say this:

    fn()
The Go runtime will execute the function in its entirety and wait for a return value.

If you say this:

    go fn()
The Go runtime will execute that function in a new goroutine (the return value is discarded) and then immediately proceed to the next line in the current goroutine.

So if you have some callDB() function that performs some long-running i/o, in node, you might do something like this to perform that operation without blocking the surrounding code:

    ...
    callDB(someparam, otherparam, function (result) {
        // do something with result here
    })
    ...
while in Go, you would do something more like this:

    ...
    go func() {
        result := callDB(someparam, otherparam)
        // do something with result here
    }()
    ...
which winds up being more like this

    func superGreat() {
        result := callDB(someparam, otherparam)
        // do something with result here
    }

    go superGreat()
With the benefit being that if you want superGreat to run concurrently, you use the go keyword, and if you want it to be run in a synchronous style, you just call it normally.

The problem with Ruby/Python/etc is that it is awkward to take something that is blocking and make it nonblocking. The problem with node.js is that node.js says "blocking is bad; therefore, never block". Go takes a different approach, in that it makes it obvious to know how to write something so that it does or does not block, so that the developer is free to use whatever I/O paradigm fits the problem at hand.

The net/http package allows you to register a handler, which is a function that takes and http request and writes a response. There is a main request loop that, when receiving a request, will create a new goroutine for each request and execute its handler in its own context. So within your handlers, you mostly just write blocking code, because you're already in your own isolated goroutine, and the only thing you'd be blocking is the processing of the current request. If you want to do something in the background, you run it in a new goroutine. goroutines are very cheap, so you can be quite cavalier about their usage.

If you want to use a callback-passing style, you can do that in Go (because it has function literals and closures and first-class functions and all that), but that's not idiomatic by a longshot.

The absolutist position that node.js takes by saying that "all i/o must be nonblocking" is no better than our previous options of "all i/o is blocking". Sometimes the simplest and most readable solution is simply to block. There is a yin to the yang of blocking.

Re:To boldly go where Node man has gone before by densh on Thursday May 17, 2012 @04:19AM (#3985987)
Important point there seem to be missing from your goroutine description is it's scheduling with respect to system calls -- all interactions with underlying OS is asynchronous in Go even though it looks like a blocking API. E.g. networking internally uses polling specific to given OS. So if one goroutine is waiting for a system call to complete it will not block the rest of goroutines.
Re:To boldly go where Node man has gone before by samdk on Wednesday May 16, 2012 @02:57PM (#3983472)
I don't program in Node very much or in Go at all, but I think there are reasons to use Node that aren't "Node is fast". I think the "Node is fast" mantra was originally really meant as a comparison to Ruby/Python/PHP, not as a comparison to lower-level languages like Go. (I personally wish Node would just abandon speed as a selling point altogether--I think it'd lead to many fewer misunderstandings.)

In any case:

Node lets you reuse the same code on both the client and server. This can be very valuable if you're writing a JS-heavy webapp. In my experience, the most useful bits of code are the in-code data representation (models in an MVC world). Being able to have identical functionality client- and server-side can save a lot of time.

Node also has Socket.IO, which is very useful if you want to use websockets. (Go has a library for it, but it hasn't been updated in a long time.) The vast majority of the Node ecosystem revolves mostly around building interaction- and communication-heavy webapps. I don't know Go or its community at all, but I don't believe they have the same kind of single-minded focus that Node has. If you're trying to do the things Node does well, you will likely benefit from the community support.

There are, of course, many downsides to Node as well, but much as I dislike Javascript, I still think it's one of the best choices for writing highly interactive webapps right now.

Re:To boldly go where Node man has gone before by jay_kyburz on Wednesday May 16, 2012 @03:21PM (#3983567)
Yeah, I agree, I'm using node right now to build a big web game and there are huge benefits to being able to run the same code on the sever and client.

I wouldn't use node if it wasn't for this because I don't particularly like javascript.

All my other games have used Python on the back end and you can really feel how clunky and painful javascript is when you have to switch between the two five times a day.

Re:To boldly go where Node man has gone before by jgrahamc on Wednesday May 16, 2012 @02:38PM (#3983373)
It's true that Go can use multiple cores, but I was doing these tests in a Ubuntu VM that was restricted to using a single core so that Go's inherent 'multicore' advantage was dialed down. I'll add a note to the post.
Re:To boldly go where Node man has gone before by kbd on Wednesday May 16, 2012 @02:43PM (#3983394)
That's a(nother) pretty big real-world advantage for Go then, no? I know the solution for Node is to just run one instance per-core, but it's automatic with Go.

I'd love to see a second set of benchmarks of the same code on multiple cores.

Re:To boldly go where Node man has gone before by _ak on Wednesday May 16, 2012 @05:27PM (#3984104)
Yes, Go will do that automatically. Plus, you can write your code in a completely linear fashion, instead of the typical Node.js code with lots of callbacks.
Re:To boldly go where Node man has gone before by chc on Wednesday May 16, 2012 @02:49PM (#3983428)
> So does Go's net/http module really provide basically exactly the same programming model as Node? If so, why use Node?

Well, for starters, Go is much more awkward for working with JSON than JS is (which is to be expected since JSON is literally a subset of JavaScript). More importantly, Go lacks the ridiculously vibrant ecosystem for Web development that Node has — no NPM, no Connect, no Jade, no Stylus, etc.

Re:To boldly go where Node man has gone before by paufernandez on Wednesday May 16, 2012 @03:01PM (#3983486)
'npm' is covered by the Go tools themselves. You can import packages using their github/bitbucket/code.google.com URL.
Re:To boldly go where Node man has gone before by chc on Wednesday May 16, 2012 @03:05PM (#3983500)
That is really interesting. Thanks for pointing that out. Can you specify specific version dependencies like you do with a full-blown package manager?
Re:To boldly go where Node man has gone before by BarkMore on Wednesday May 16, 2012 @04:07PM (#3983764)
After 'go get'ing the package, you can use git/hg/bzr to checkout the specific version you want. From there, all of the Go build tools will work as normal.
Re:To boldly go where Node man has gone before by paufernandez on Wednesday May 16, 2012 @03:58PM (#3983726)
I don't think so, but I could be mistaken. (btw, someone pointed that out as a drawback on another thread.)

What I've done sometimes is just clone the repo within a directory that appears in the GOPATH, maybe checkout a specific revision, and that solves the problem.

Re:To boldly go where Node man has gone before by _ak on Wednesday May 16, 2012 @05:31PM (#3984123)
So what exactly do you think is awkward about Go's way of working with JSON? Here's a code example from one of my current projects:

    type UploadProgress struct {
        Progress int `json:"progress"`
    }

    //...
    // variable progress is of type Progress
    if json_data, err := json.Marshal(progress); err == nil {
        w.Header().Set("Content-Type", "application/json")
        w.Write(json_data)
    }
json.Unmarshal works the same way. IMHO, not exactly more awkward than using JSON.parse and JSON.stringify.
Re:To boldly go where Node man has gone before by chc on Wednesday May 16, 2012 @06:04PM (#3984286)
Unless there's something I missed, json.Unmarshal works the same way iff you have a struct that matches the JSON data very closely. If the JSON data is a little more free-form, you're stuck with a map of interface{}. Having to muck about with types is just a little tedious compared to JavaScript where there aren't really any types and anything can concisely be converted to a string. (I did a little project involving JSON a while ago in Go, but I'm hardly an expert at the language, so if I missed something, I apologize for the misinformation.)

In retrospect, I think I may have overstated it a little bit, and I doubt this problem would crop up too often for most apps.

Re:To boldly go where Node man has gone before by zemo on Wednesday May 16, 2012 @07:28PM (#3984618)
If your json doesn't represent something that already follows some known structure, you have an opaque data structure that you have to hand write a parser for in any language.
[deleted]
Re:To boldly go where Node man has gone before by zemo on Wednesday May 16, 2012 @09:42PM (#3984947)
>you need a number but an external datasource might hand you a number or a string containing a number.

http://stackoverflow.com/questions/9452897/how-to-decode-jso...

the label on the field lets you denote when that will happen, so... it's not quite as difficult as it may seem; you don't have to write a single method for that case.

The type system is a feature, not an obstacle. Yes, you have to specify a type, but as a result, the compiler can perform a lot of checks that, in dynamically typed languages, would either be something you'd handle manually, something that would cause undefined behavior, or something that you would write a unit test to test for. Yes, you could just wing it, unmarshal some data, have an unsafe reference to some field and hope that it performs the way you want it to, but the reality is that things like that are easy in JavaScript because they're wrong. All data inherently has some kind of type, and different languages deal with that in different ways.

but yes, that particular type of thing does come up a lot, and the topic of handling bad json is one that has woefully too litter literature surrounding it (I've had it stump me before on my own projects). Things like "they're using the wrong format for the timestamp" or "that is sometimes string, sometimes null" are stumbling blocks when coming from dynamically typed languages (I'm coming from Python/JavaScript), but in my experience writing Go, the way the language works makes writing bad code much more difficult, and my Go programs have been much more stable, easy to refactor, and easy to maintain forward progress on over a long period of time. After using it for some time, I've come to the conclusion that these types of tradeoffs have been worthwhile. The significant reduction in runtime errors that I've seen in my Go applications compared to my Python applications have more than outweighed the amount of time I would normally spend debugging and testing my Python code, which is tedious and boring.

Re:To boldly go where Node man has gone before by jff on Wednesday May 16, 2012 @04:44PM (#3983933)
Writing http servers with Go really is pretty easy; here's one I wrote while at SC11: https://bitbucket.org/floren/goblog

It's for an older version of Go, and has only been tested on Plan 9, but it shows a static content + blog server, with JSON config files and templated HTML for the blog pages.

Re:To boldly go where Node man has gone before by kitsune_ on Wednesday May 16, 2012 @04:00PM (#3983737)
I doubt it does. net/http looks like a basic http listener? As such, the comparison looks biased to me. Mind you, I don't know much about node.js or Go.
Re:To boldly go where Node man has gone before by chc on Wednesday May 16, 2012 @06:07PM (#3984296)
Isn't Node's http.Server also a basic HTTP listener? What's the distinction you're trying to draw?