7 ms·
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 t
by kbd 14y ago
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?
- jgrahamc 14y agoIt'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.
- kbd 14y agoThat'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.
- _ak 14y agoYes, 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.
- chc 14y ago> 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.
- paufernandez 14y ago'npm' is covered by the Go tools themselves. You can import packages using their github/bitbucket/code.google.com URL.
- chc 14y agoThat is really interesting. Thanks for pointing that out. Can you specify specific version dependencies like you do with a full-blown package manager?
- paufernandez 14y agoI 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.
- BarkMore 14y agoAfter '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.
- deleted 14y ago[deleted]
- _ak 14y agoSo 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.
- chc 14y agoUnless 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.
- zemo 14y agoIf 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 14y ago[deleted]
- zemo 14y ago>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-json-with-type-convert-from-string-to-float64-in-golang 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.
- samdk 14y agoI 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.
- jay_kyburz 14y agoYeah, 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.
- kitsune_ 14y agoI 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.
- chc 14y agoIsn't Node's http.Server also a basic HTTP listener? What's the distinction you're trying to draw?
- jff 14y agoWriting http servers with Go really is pretty easy; here's one I wrote while at SC11: https://bitbucket.org/floren/goblog 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.
- zemo 14y agoNo, 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.