
Why I went from Python to Go (and not node.js) - zemo
http://orel.li/QMeEXk
======
juddlyon
"... as a Python programmer, I was the member of an elite cabal of superhuman
ultranerds, smarter than those childish Rails/JavaScript/PHP/whatever
developers that couldn’t write a bubble sort or comprehend even basic
algorithmic complexity, but more in touch with reality than the grey-bearded
wizards of Lisp/Haskell/whatever that sat in their caves/towers/whatever
solving contrived, nonexistent problems for people that don’t exist, or those
insane Erlang programmers who are content writing sumerian cuneiform all day
long."

This made me laugh, thank you.

~~~
IsTom
"Everyone less nerdy than me is stupid and everyone more nerdy than my is a
no-life". I think it's pathetic, not funny.

~~~
jonathansizz
It's actually kind of bizarre that so many Pythonistas actually have the kind
of attitude that the article mocks, since Python is a thoroughly mediocre
language. I can only attribute their patronizing disposition to a lack of
genuine awareness of the broader programming world.

~~~
slurgfest
How many Pythonistas? I would like you to substantiate this claim. I would
assume that you actually don't have that much contact with the Python
community because otherwise it is pretty unaccountable how I have never
encountered that attitude all these years. and I am a grumpy person, and not
without my own axes to grind about the Python community.

~~~
3amOpsGuy
I can relate to what he said, like the grandparent here it made me laugh.

I wouldn't say i espouse the view presented (have too much respect for what's
been achieved in the other camps such as Ruby and even PHP), but internally
yeah i think i do view the world that way.

I don't think it's any different from the common "anyone driving slower than
you is a doddler, anyone faster is a maniac" - a patently absurd view to hold.

The enlightening part for me is that other pythonistas think this way, because
as you said, i have also never experienced this view expressed publicly by the
python community.

------
ak217
Lots of sentiment, not much substance.

Concurrency support is possible in Python, without gevent-style monkey
patching (or callback madness). Have a look at concurrent.futures and
<http://www.dabeaz.com/coroutines/index.html>. It really needs a lot more work
before it's part of the language's DNA, though. Also, pypy needs much wider
adoption as quickly as possible, to address the speed problems (and its STM
branch holds huge potential).

For me, Go's major shortcoming is its community's lack of focus on readability
as compared to Python.

~~~
georgemcbay
"For me, Go's major shortcoming is its community's lack of focus on
readability as compared to Python."

Can you be a bit more concrete here? Because whether you like the code styles
enforced by gofmt and the compiler itself or not, Go is the most consistently
readable language I've ever used (once you adapt yourself to the language).
IMO, this seems like an especially odd problem for someone to have with Go.

~~~
wonderzombie
Agreed.

I think we, as a profession, have a tendency to focus on what's "easy" (syntax
and constructs we're already familiar with) to the exclusion of other,
potentially more important factors. I am and have been guilty of this myself,
so I'm not claiming any sort of sainthood, just making an observation.

Often people pick on the use of single-letter variable names as "unreadable."
This is mostly a matter of keeping the code light on the page, as they put it.
If you're dealing with a package centered around Foo, especially methods on
same, it's customary to just abbreviate it to f. That clashes with a lot of
people's instincts even though, once you get used to it, it works well.

"Once you get used to it" is key -- this is true of _any_ language with
substantially new or different syntax/semantics from what a programmer is used
to. _All else being equal_ , familiarity ought to be orthogonal to merit; the
mere presence of a learning curve ought not be a deal-breaker.

Anyway, Go is one of the most readable languages I've ever seen, given that it
is not a scripting language. Among other things, type inference and literals
make the code very clean, to the point where you can in short order read the
standard library code and expect to understand it.

~~~
dantotheman
I think the issue with single-letter variables goes deeper than it just being
unreadable (although its that too for someone that isn't "used to it").

For example there are issues with scope (what happens when I need a second or
third "f" variable" and maintainability too (6 months from now I have to
remember if "f" stands for "foo" or "file").

~~~
lambda
Generally, I try not to use single letter variable names in any scope that
doesn't fit into a single screen in my editor. That way, I don't need to
remember what "f" means, it's right there in front of me. And I shouldn't have
too many variables in that scope, so conflicts aren't all that important; if I
really do, I just start using multi-letter names again.

~~~
viscanti
This is a good heuristic. For me, single letter variables are almost always
iterators in places where space is at a premium (i.e. one line list
comprehensions in python). If I'm breaking a loop out over multiple lines
(which is almost always the case), I prefer a longer, more informative
variable name.

------
stcredzero
If someone created a debugging environment for Go based on a VM, which also
let one recompile source _from within the debugger then continue execution,_
then it would be, for all intents and purposes, as productive and immediate as
the old Smalltalk environments. You'd have the same small-grained cycles of
inspecting state, modifying code, rewinding the stack to the place of your
choosing, then getting immediate feedback.

Source code changes could be saved as log-structured patch files, which could
then be thrown away or applied to the source tree as desired. One could also
steal some ideas from the Smalltalk Change Log tool by adding similar editing,
search, and filtering commands.

With tools like this, one could recompile for "interpreted debug mode," have
complete visibility and control of runtime state to debug a problem, then take
the resulting patch file and apply it to the source tree. It would be a best
of both worlds scenario -- all the enhanced debugging of an interpreted
runtime with the type safety and speed of compiled code.

~~~
taliesinb
Interactive coding is a very powerful way of working, it's one of the reasons
I'm so productive in Mathematica.

At a Go talk he did, I raised the idea with Russ Cox of having a "repl"
package that would allow one to instrument a running program with a live REPL
to do debugging and development on it.

The reflect package is powerful enough to make some of that relatively
straightforward, but one major problem is that Go can't construct new types at
runtime. Another challenge would be dynamic linking of new code -- because the
Go toolchain doesn't support dynamic linking there would seem to be no hope of
say entering anonymous functions on the REPL.

Unless one builds a full Go interpreter -- but who wants to be in the business
of maintaining a fully compliant Go interpreter that can interoperate with the
Go runtime?

Still, calling existing functions and banging on variables would be pretty
useful.

~~~
stcredzero
_> one major problem is that Go can't construct new types at runtime._

The current implementations can't. I don't see any reason why one couldn't. In
any case, I don't think that's such a big deal. One just goes from completely
seamless interactive coding to mostly seamless interactive coding.

 _> Unless one builds a full Go interpreter_

That is precisely what I was proposing. (Are you implying some sort of hard
VM/interpreter dichotomy? I've met some people who implement VMs who think
this is somewhat arbitrary.)

 _> but who wants to be in the business of maintaining a fully compliant Go
interpreter that can interoperate with the Go runtime?_

There would be no need to interoperate at all with the current Go runtime. One
would have to have their own Go runtime, however. As an alternative, one could
just target an emulator with no optimizations, then use debugging information
and dirty tricks to map the new code with the old state in an entirely new
process.

~~~
gruseom
Go's compiler is said to be fast. Could you fake interpretation by continually
recompiling everything?

~~~
stcredzero
_> Could you fake interpretation by continually recompiling everything?_

That's pretty much what the modern JIT VM Smalltalk environments do. On
recompiling a method, all the affected JIT compiled machine code is kicked out
of the code cache, and you start from interpretation again, which eventually
results in the "hot" code being JIT compiled again.

------
it
It would help a bit if the article included at least roughly equivalent Go
code next to the Python code. The Go code is wordier, but maybe it takes less
time to write because it doesn't require as many decisions (libraries etc.) as
with Python.

    
    
            package main;
    
            import (
                    "fmt"
                    "net"
            )
    
            func main() {
                    hosts := []string { "www.google.com", "www.example.com", "www.python.org" }
                    c := make(chan string)
                    for _, h := range(hosts) {
                            go get_ip(h, c)
                    }
                    for i := 0; i < 3; i++ {
                            fmt.Println(<-c)
                    }
            }
    
            func get_ip(host string, c chan string) {
                    addrs, err := net.LookupHost(host)
                    if err != nil {
                            fmt.Println("Host not found:", host)
                            c <- host + ": <error>"
                            return
                    }
                    c <- host + ": " + addrs[0]
            }

~~~
zemo
This is a very good example of the type of thing I'm talking about. Nobody
prompted you to do so, but you gracefully handled the case of a DNS failure in
your code, because the control path was obvious throughout. Go makes this type
of error handling a topic very early on in the literature. I find this type of
clarity when structuring concurrent code to be very helpful in minimizing
subtle concurrency bugs.

~~~
d0mine
On error handling in Go vs. Python:

Lack of exceptions means the deeper the call stack the higher the proportion
of error handling code relative to a normal (non-exceptional) code path.

For example, if you decide to refactor some code from a bigger function into
its own smaller function then all error handling code have to be repeated
twice (first in the child function then in the parent that calls it). It
introduces unnecessary clutter and boiler-plate.

Exceptions allows you to limit the error handling to two places: the place
where you detect an error and the place where you are ready to handle it and
_not_ throughout the whole call stack.

Language with a builtin garbage collection can (should) afford a builtin
exception support.

I like that Go excludes some language features on purpose but in the case of
exceptions Python has its merits.

~~~
goblin89
Coming from Python, I was of the same opinion at first. A significant amount
of error handling lines is what I noticed first when looking at Go code[0],
too.

However, I was interested to learn that Google style guide for C++ recommends
not using exceptions. I don't know C++ (shame), but at least some of their
reasoning is applicable to Python as well:

For example, when you start raising an exception in a Python function, you
have to check its callers, whether they (or their callers) handle it. And
vice-versa—when a Go function has “expected” error in its signature as return
value, it's very obvious what you need to handle when you're the caller.

“Expected” error as return value also encourages single responsibility
principle, I suppose. E.g., for a function that decodes JSON, bad syntax is
“expected” error, the rest is a reason to panic().

I'm not sure if I get your example with refactoring, but it may be a case when
you use panic() in inner function, recover() in outer, and return an error as
usual.

That said, I've never actually used Go yet, so it's just theorizing.

[0] But then my Python code that (to me) looks more or less “solid” appears to
contain a comparable amount of error handling lines, so not sure if it's a
good metric.

------
just2n
Another gonatic? I'm immediately reminded of the days when everyone who liked
D proclaimed it would overtake C++ and rule the world with terrible, contrived
examples: "let me show you why my language is better than yours by completely
misunderstanding how to solve a problem, then implementing that
broken/overengineered solution in your language, then compare it to something
my language's API can do for me, just so we can see how much simpler that bad
solution is in my language!"

The insight to async I/O is that this server, for this I/O bound task, will
perform as well as your GOMAXPROCS example:

    
    
        require('http').createServer(function(req, res) {
            res.writeHead(200);
            res.end("hello world\n");
        }).listen(8000);
    

But it's a lot simpler. You don't need to bolt on parallelism when you don't
actually need parallelism. There are valid reasons to use Go, and there are
valid complaints against Node. I don't see any of either here.

~~~
SeanDav
Big difference is that D did not have a Google backing it and D had a fairly
major falling out by different factions.

This was a great pity because I think it probably is one of the best languages
ever made and didn't get the take up it absolutely deserved.

~~~
enneff
The big difference between D and Go is that D is another kitchen sink
language. It has almost all of C++'s features, and more! Conversely, Go has
many fewer features than C++ or D, and many argue that this is Go's biggest
selling point.

------
bcoates
I'd like to see more detail about the real problem he was facing in python. It
sounds like he mostly wants a non-blocking background job "I don’t want to set
up another daemon, I just want to send some email in the background!" Why not
just use Queue (thread-safe, waitable, built-in) and a background
thread(pool)?

There's an awful global lock on the actual execution of python code, but
unless the problem is performance or contention worrying about it is
premature.

~~~
dignan
Not only that, but there's a multiprocess Queue class as well that is a drop
in replacement for the threaded one. So if you are having problems with GIL
contention (unlikely, but possible), you can still just as easily use multiple
processes.

~~~
cgh
Exactly what I thought - "what about multiprocessing?" Doesn't that count as
language-level concurrency support? You can fire off a background job to send
email or whatever just as easily as in the Go example.

~~~
milesvp
This confused me as well, it felt like the author was thinking about the
problem space all wrong. As soon as I read

"As a Django developer, there wasn’t a straightforward and obvious way to just
do things in the background on a page request"

I started thinking, "um, django produces http responses, you can only respond
once...".

Clearly, from his gevents example, he's looking to do things that take time,
and wants to do them as concurrently as possible, then send the whole response
at once. But if he really doesn't want the user to wait, then this is not
something you should be doing in a webserver anyways. You really should be
building that into the front end javascript, and let it handle all the async
data grabs from small, fast, cacheable web requests, then redraw the page as
the data comes in.

~~~
slurgfest
If for whatever reason you don't want to build everything into the front end
Javascript, it is very common to throw jobs onto a task queue to be done
outside of the HTTP flow, so they do not block the response.

This could be a lot more accessible to beginners, however, because there are
moving pieces like a message queue that have to be set up and blah blah.

------
ricardobeat
Ah, code comparisons. I don't see much difference in the Go code vs
Javascript, except for the extra comments and logging in the js. How about
this?

    
    
        var cluster = require('cluster')
          , http    = require('http')
          , os      = require('os')
    
        if (cluster.isMaster) {
            os.cpus().forEach(cluster.fork)
        } else {
            http.createServer(function(req, res){
                res.writeHead(200)
                res.end('Hello world')
            }).listen(8000)
        }

~~~
enneff
You should update the node.js docs if you consider the original JS snippet
ugly, because that's where I pulled the original code sample from verbatim.

In any case, it's still not an apples to apples comparison. The node.js
example forks separate processes that share nothing, while in the Go example
it all runs in one process so the HTTP handlers can communicate with each
other via channels or other shared data structures.

~~~
ilaksh
The idea with node is that you dont normally need multiple threads or
processes because you have nonblocking io.

    
    
        http = require 'http'
        server = http.createServer 'localhost', (req, res) ->
          res.writeHead 200
          res.end 'ok'
        app = server.listen 3000

~~~
ilaksh
I made a mistake, did not mean to include 'localhost' in there.

------
mietek
Dimissing Erlang and Haskell with a wave of the hand, while seriously
considering node.js? Carry on, nothing to see here.

~~~
zemo
ah, so, I don't think I wrote that section particularly well. I hold Erlang
and Haskell in very high regard; I was really trying to mock my own
superiority complex, which I think is fairly common in the Python community. I
guess what I was really trying to get at is that Go is verymuch an industry
language. Haskell I would argue against being an industry language not because
it can't be used in industry; that's not at all what I mean. I don't mean to
compare them on their technical merits; what I mean to say is that Go has a
broad appeal, in that it is welcoming to beginners, it has large corporate
support, and that it is also technically capable. Of the programmers that I
know, the Haskell programmers are typically capable of solving the hardest
problems, but they also tend to be the most academic. The Erlang programmers
typically build the most stable software, but I think Erlang is intimidating
to less-experienced programmers (the same is true of Haskell, actually).

That could have been written better. Thanks for the feedback.

~~~
dons
You're digging in.

> Haskell I would argue against being an industry language

FYI, the problems the Haskell community has been working on are things like
scalability, performance and safety _because they're critical to industrial
problems_. Toy approaches don't work at the scale we operate at -- you need
real computer science.

You want 1,000,000 Haskell threads in your app? You've got it. Want to write
numerical models that compete with C++ code, in a fraction of the development
time? Done. Want to guarantee the app won't crash? Solved. Run models over
10,000 cores? It happens.

Because we put the work in.

\---

/me wanders back to a multi-million line Haskell codebase running systems in
25 countries, processing billions a year in financial transactions.

~~~
scrumper
> /me wanders back to a multi-million line Haskell codebase running systems in
> 25 countries, processing billions a year in financial transactions.

Curious... Can't be a bank, too conservative. Hedge fund? I know Jane Street
love their OCaml so functional does have a place in that world. But 25
countries? You'd have to be huge.

~~~
dagw
_Can't be a bank, too conservative_

I know two large international banks that have significant Haskell codebases.
I don't know where you get the idea that banks are too conservative.

~~~
scrumper
Very interesting! Thanks.

The idea comes from 10 years of working with them as an external vendor. I see
all sorts (but especially Python and C++) on prop desks, but mostly C# in
other areas (integration, data management etc.) That being said, nearly all of
my experience is in front office trading and asset management, primarily in
listed instruments, with little on OTCs, and nothing on payment processing,
'core banking' or the kind of stuff that spans the entire organisation.

It sounds like Haskell has found a niche at Standard Chartered doing perhaps
just that. What are those two banks you mentioned doing with their Haskell
code?

------
zzzeek
For small tasks in the background of a web request, you _can_ just, you know,
use a worker thread. This author seemed like he didn't even try regular
threads, and went directly from one hyped meme to another. It's often the case
that the GIL isn't much of an issue.

------
antihero
I'd like to start porting a few of my little scripts to Go (that do pretty
poor messy parallelism in Python), and I was wondering what a good
resource/book type thing would be for people learning Go. Like, the equivalent
of learn you some haskell or whatnot. Also some advice on "wtf library do I
use for this".

Is there some sort of Go package manager? How does all this shit work?

~~~
zemo
I recommend starting with <http://tour.golang.org/#1>.

Yes, the Go tool comes with package-management capabilities. "go get
labix.org/v2/mgo" will download the very excellent MongoDB driver mgo, for
example.

~~~
swasheck
But then actually implementing something useful is cryptic and obscure. I
tried figuring out how to connect to a postgresql server following the
spaghetti documentation of <https://github.com/bmizerany/pq> and
<http://golang.org/pkg/database/sql/> and have yet to find anything useful.
Hacking around only leaves me with frustration. Searching around only leads me
to unhelpful descriptions of what the GO command does in MSSQL Server.

~~~
kkowalczyk
Seriously? What is "cryptic" about db = sql.Open(...); db.Exec(); db.Query();
db.Close() etc.?

From <https://github.com/bmizerany/pq/blob/master/conn_test.go>:

    
    
      func TestExec(t *testing.T) {
    	db := openTestConn(t)
    	defer db.Close()
    
    	_, err := db.Exec("CREATE TEMP TABLE temp (a int)")
    	if err != nil {
    		t.Fatal(err)
    	}
    
    	r, err := db.Exec("INSERT INTO temp VALUES (1)")
    	if err != nil {
    		t.Fatal(err)
    	}
    

What is it exactly that you tried and failed? Because looking at conn_test.go
the API is dead simple and pretty much like any other db API of this kind.

------
srj55
"As a Django developer, there wasn’t a straightforward and obvious way to just
do things in the background on a page request. People suggested I try Celery,
but I didn’t like that option at all. A distributed task queue? What? I just
want to do something in the background without making the user wait; I don’t
need some super comprehensive ultimate computing machine. The whole notion
that I would need to set up and configure one of these supported brokers made
my spidey sense tingle"

It's not really that hard. I just latch on to a broker that I'm already using
elsewhere in my stack (Redis). Celery makes it super simple to run a command
in the background.

~~~
zemo
well, the complaint isn't entirely that it's hard, per se, but that there are
many different ways to do things concurrently in Python, and that it presents
too many choices to be made for the novice programmer. In Go, you just say `go
myfunction()` and you're done. There's a lot of value in that.

~~~
erichocean
Until, that is, you tackle a problem for which one machine isn't big enough,
at which time you need to do all of the "real" solutions anyway, and `go
myfunction()` buys you...nothing.

There's way too much focus today on new languages that are designed to work on
just one machine, and scale there – as if _vertical_ scaling was the true
problem we all face, when in fact, it's not. /sigh

~~~
jeremyjh
He's talking about a web application doing a task asynchronously. There is no
reason why it would be hard to scale Go web servers across multiple machines.
Yes you could use a distributed broker system to do asynchronous tasks, and
some languages platforms leave you no other choice, but there is no reason to
think his use case actually requires anything more than running an
asynchronous task.

------
niels_olson
I keep hearing about go. I am new-ish to programming. Only really getting
started on my first project, which depends on pyparsing, which depends on
other things. Is go something a novice should be attacking real-world problems
with?

~~~
zemo
it depends on what your goal is.

A language is just one tool in your toolset. I love using Go very much, but I
would recommend learning on Python. There's much more literature out there,
more people you know will know it, and if you are looking for work, there are
effectively zero entry-level programming jobs in Go.

The reason you keep hearing about Go is that it just very recently hit its 1.0
release, so it it a comparatively new language, and it's just a topic of
conversation. Talking about Python isn't really newsworthy in the same way,
because for most people, it's just a fact of everyday life. Go, however, is
this new thing that's a little mysterious, that most people haven't tried yet.

Have you ever heard the phrase "you can never really know yourself until you
know others"? Well, that's true of programming languages, too; learning new
languages can help you to write better code in a language you were already
familiar with. Learning new languages is great practice for any programmer.

But to start, I would just stick with Python and write some things that make
you happy. That's the most important part; to figure out how to use code to
make yourself happy. Which language you use is really just an implementation
detail.

~~~
niels_olson
> People you know will know it

Actually, not without going out and meeting new people. I'm a physician, so
meeting anyone who knows anything about IT is quite challenging. And the
helpdesk folks at the hospital usually aren't in the mood to troubleshoot
those kinds of errors!

~~~
zemo
ah, I initially met most of the programmers I know though hackathons and
meetups. Startup Weekend was one of the first things I went to where I met a
lot of people, and that happens basically everywhere.

------
zallarak
Very cool post. The code samples really make me want to try out Go when I get
some time to do so. Thanks.

~~~
zemo
thanks for reading! I recommend starting with <http://tour.golang.org/>. It's
a very useful learning tool.

------
mathattack
I think we can cut the author some slack. He admits in the header to being a
relative newbie. (Learned python less than a year ago, recently took Hacker
School)

------
knodi
I'm in love with Go. I'm very close to deploying it in production.

------
realrocker
In Go, the coroutines are in the same thread. There is a single thread here
too(just like node.js). Coroutines are just multiplexed to the one main
thread. Multi-Core Processing is handled by coroutine internals too i.e. there
may or may not be more than one threads and even if there are more than one
threads, they too will be multiplexed with the one main thread.

~~~
4ad
Goroutines running Go code are multiplexed onto a variable number of system
threads (GOMAXPROCS, in the gc implementation), Goroutines running C code, for
example via cgo, or when they call a blocking system call, have their own
thread.

~~~
realrocker
Yes I get that. I just wanted to point out that a single threaded model is not
necessarily a bad thing. It happens in GO too by default.

~~~
strmpnk
I think that's more of a matter of scheduler still being immature. Erlang only
added an SMP scheduler in R11 due to the complexities of managing internal
state without sacrificing it's soft-realtime abilities. It was also only
really reliable after R12.

I'm sure Go will mature here and the defaults will evolve along with that.
Whether that will take years or not is up for debate but at least it's a
possibility and doesn't cost the programmer anything other than a recompile if
they start with careful use of goroutines today.

------
electic
I am writing an article right now about how I went from Go to C++. Hope I can
have something up here soon.

------
tocomment
It it true there's no way to spawn a background task in Django without making
the user wait?

~~~
zemo
I haven't been using Django for a while, but I know there was no way built
into the framework to do it. The complaint isn't really that it's too hard,
it's that there's too many decisions to make, because it's not supported at
the language level.

------
ishbits
What's wrong with good old threads. It's not that hard. And threading in Java
will blow away any pseudo concurrency setup in python. Been there done that.
Love python but just couldn't get the performance we needed.

------
dgregd
According to Google Dart is better for web apps than Go.

Is it too early to switch from Python/Ruby to Go? Maybe it would be better to
wait for Dart.

I known that Mozilla and MS won't support Dart however they also don't support
Go.

------
Kiro
Why do you need concurrency to send an e-mail? Why do you need to do it in the
background? Just trying to understand this concurrency thing...

~~~
zemo
it's a slow, i/o operation. Perhaps it takes a second or two; maybe you're
generating a PDF and the email is of non-negligible size, or your email
provider is slow that day, or something of that nature. When a user clicks a
button, and the response is just "ok, we sent you an email", you can just
issue that response immediately, and then send the email. Otherwise, the
user's browser just sits there and hangs until the entire process is done.

------
richcollins
You should look at LuaJIT's coroutines as an option.

------
rjurney
I'm always confused by these kinds of posts. You really only code in one
language most of the time? I code in half a dozen every day.

------
rWolfcastle
Based solely on this article, and this article alone, and knowing nothing more
about Jordan Orelli, the conclusion I drew about the author is that he thinks
"Java Web Programming" strictly refers to applets and nothing more.

 _narrows eyes_...

/nerdhate

~~~
zemo
ah, I was working on a game. It was a space shooter. I wanted it to be
viewable in the browser so that I could just send a link to my friends and
they wouldn't have to download it. I wound up writing it in AS3.

------
se85
I prefer the node.js example given over the Go example.

Sure, the go example is shorter, but the JavaScript version reads much nicer
(at least to me).

------
dude8
I would have to say the author of this article probably isn't that good.

------
markmm
Wait a few weeks, for his followup article entitled "Why I came back to
Python....two words...mature libraries"

~~~
luriel
I have found at least the Go stdlib much more uniform and reliable than the
Python stdlib, perhaps not as complete, but it also has things that are
missing from the Python stdlib, and unlike with the Python stdlib I don't find
myself reaching from alternatives, the Go stdlib has great template system,
image manipulation, etc.

Third party libs still are more uneven, but that is not much different from
Python.

------
sproketboy
Why would anyone go to Node.js? Serious question.

~~~
zemo
nonblocking i/o is an important feature if you want to make something
responsive that will handle a lot of connections. node.js brings that to the
foreground, and makes it a topic that is digestible for a lot of programmers
that have never seen it before. The end result is that by using node.js, a
developer is able to experience one element of concurrency that they may not
have had exposure to using Ruby/Python/PHP. Yes, it is possible to do
nonblocking i/o in Ruby/Python/PHP, but it isn't as natural of an experience.

It's a usability thing. If you make something easier to use, more people use
it; as a result, node.js has introduced the topic of nonblocking i/o in a way
that other technologies have been unable to do. It also allows you to share
code between the client and the server, which may or may not matter, depending
on your project. And for a lot of developers, node.js means using a language
you already know.

The guys at Kitchen Table Coders do a workshop where they make a physical game
paddle with an arduino, and then hook it up to a node.js server, so that two
people can play pong with physical controllers in their browser. They're able
to teach that workshop in a day. I think that speaks volumes for types of
things that you can do with node.js, and its mass appeal.

But, like I said in the article, I find that node.js becomes disorganized
quickly, and I just plain don't enjoy debugging JavaScript. On top of that, if
you need to do CPU-bound work, node.js basically forces you to create an
isolated process and perform i/o with it, but now you have an OS process for
each of these instances, whereas in Go, creating a goroutine and communicating
with it over channels is much more lightweight. Node.js has its merits, and I
don't mean to say "nobody use node.js ever!", I just don't like using it.

