Yesterday I posted the following on Twitter:
Why is the #golang community so much more holier-than-thou than the #ruby community? Harumph to all sanctimonious hackers.
This got a concerned response from someone who works at Google as a “Go Gopher”, whatever that means. It also made me feel like a dirty troll, which wasn’t my intention at all: I was just venting after a frustrating day.
When Google’s Go Programming Language was announced late last year I was fascinated. I loved the decisions they’d made regarding code formatting (the language enforces a particular standard, making debates about the right way of formatting code a moot point), dependency management (it’s a compile-time error to include something that you don’t use; streamlining your dependencies to speed up builds in C++ is a nightmare by comparison), and language features (defer, iota, interfaces and goroutines are all very cool). I read through the documentation, watched the videos and toyed around with the language a bit, but I didn’t dive in and get my hands (really) dirty straight away.
Recently, I’ve started working in earnest on the back-end for MegaHAL.10, an online chatterbot that can learn to talk in any language by example. That project has a few requirements that make Go an ideal language for the server-side code, including:
- The need to be fast, and to manipulate a lot of data in memory. This makes C or C++ an obvious choice, and discounts languages such as Ruby or Python. Go is a lot closer to C++ in terms of efficiency, so it’s a candidate for the implementation language.
- The need to work with all human languages, meaning it’s important that the chatterbot engine supports UTF-8 end-to-end. All strings in Go are UTF-8 by design, whereas it’s fiddly to properly support UTF-8 in C++.
- The server will need to handle many simultaneous requests, and the concept of goroutines is ideally suited to satisfying this requirement.
So I started coding things up, and eventually ran into some problems that I couldn’t answer by reading through the provided documentation.
For example, consider the provided documentation for the sort package. The description is a brief “the sort package provides primitives for sorting arrays and user-defined collections”. Just what I need! Unfortunately, the documentation for the Sort method is no more than its specification, “func Sort(data Interface)“. That is all.
You can click through to see the implementation of Sort, revealing that it just calls through to quickSort. Great! I’ll look at the documentation for that. Unfortunately, there is none; quickSort is private (because it starts with a lowercase character), meaning that it doesn’t appear in the documentation at all, although its implementation is right there in the source.
So they’re hiding stuff from you in the docs, while at the same time recommending that you treat the source as documentation.
Now, this is a contrived example. I didn’t really need to look up documentation for Sort, but I did have several problems of this category with other packages and functions that I wanted to use. What I’m trying to illustrate here is how difficult they’ve made it for a newcomer to the language to get acquainted with things. Contrast this, for example, with the documentation for sort in Ruby:
Returns a new array created by sorting self. Comparisons for the sort will be done using the <=> operator or using an optional code block. The block implements a comparison between a and b, returning -1, 0, or +1. See also Enumerable#sort_by.
01234 a = [ "d", "a", "e", "c", "b" ]a.sort #=> ["a", "b", "c", "d", "e"]a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
It’s succinct and easy to understand, with clear examples and cross references to related functions. Exactly what you need to dive in and get started on something.
I’ve just finished working on FAQoverflow, a fun little project that was implemented in two weeks using Ruby, and I rarely needed to look outside of the provided documentation when writing a fairly complicated API spider. When I did, I found the community polite, welcoming and useful. Consider, for example, this question to ruby-talk, made soon after the first version of Ruby was released in the west:
Ok, I’m having trouble with an extremely simple class. Here’s my example:
0123456789 class ABCdef initialize( _v )@v = _vendenda = ABC ( 50 )print a.v # produced an ERROR<br>
This got an immediate reply from Matz, the creator of the language:
Example:
0123456789101112 class ABCdef initialize( _v )@v = _vendattr_accesser :venda = ABC ( 50 )print a.va.v = 25print a.v
Now, that’s really helpful! Here’ by contrast, is the first question I ever saw on golang-nuts (when searching to find out how the ternary operator worked):
How can you call your self a C-like language and NOT have the ternary operator? But seriously, why isn’t it in Go? This could be a deal-breaker for me, as it’s often more succinct and clear to use a ternary operator than an if/else, *especially* if you require curly braces even for single-line blocks.
And here’s the first answer:
Then “go” write your own language or use a language that makes use of your precious ternary operator.
Ouch! That answered my question, but it certainly rubbed me the wrong way.
When you’re deeply focused on writing code, and jump to a browser to do a quick search, and the first thing you hit is a mean-spirited reply to a reasonable question, then it breaks your stride and leaves you with a foul taste in your mouth.
Of course, if this just happened a few times it wouldn’t be a problem. What concerned me is that throughout the day, whenever I searched for an answer to a question I had about Go, I always got a mean-spirited answer to a fair question. Sure, I admit I might have had an unlucky streak, and I admit that I usually read the first reply to each question due to my familiarity with Stack Overflow, whereby the first reply tends to be the best. But I just don’t encounter that with the Ruby community. And it was enough to make me stop looking to the forums for answers, which is a shame.
Some more examples of less-than-useful answers (paraphrased) that I encountered on the day I was working with Go:
“Having optional arguments to functions would be useful.”
“In the rare instances you need them, make wrapper functions and give them unique names.”
Coming from Python and Ruby, I’d have to say that optional arguments, or arguments with sensible defaults, are far from a rarity, and are often extremely useful. And, no, I don’t believe that it’s good practice to create eight differently-named wrappers for a function that you’d like to have three optional arguments.
“Why does strconv have functions to parse int and int64 but not int32?”
“Because making a function for every possible integer type is tedious and clutters the interface.”
Clutters the interface? Really? Do you mean that the generated documentation gets a bit longer, meaning you have to scroll through it? Do you mean that you really shouldn’t need to specifically convert int8 and int32 from their string representation, ever? Or that if you do you should write that functionality yourself?
“I was following the tutorial on the website, and it said… (a simple misunderstanding)?”
” I don’t get the point.”
Thanks for sharing, but why not correct the obvious misunderstanding or be more specific about what it is that you don’t get?
“The library code is … hard to learn from. I’d rather see short example programs.”
“Rule one of problem solving: break it down into smaller problems, see rule zero.”
Right, so rather than provide short, concise usage examples in the documentation, you want me to dive into the source and spend time understanding the implementation of the functions I want to use?
“I’m sure this is totally obvious, but I can’t seem to find it anywhere in the docs…”
“One way to get answers to questions is to search the golang-nuts mailing list.”
Hmmm… dare I ask any questions at all?
Now, yes, perhaps I’m being harsh. But when you’re struggling with something unfamiliar and new, it’s a godsend to find a superb resources such as Programming Ruby or The Ruby User’s Guide or why’s (poignant) guide to Ruby or the Standard Library Documentation, and these resources exist because the community cared enough to want to help newbies to understand why they fell in love with the language. Guess what? It works.
I just don’t get that feeling with the Go community at all. At the moment, it feels defensive and argumentative. Now, it may well be that Go is suited to a different class of problems than Ruby, and that the language is therefore going to be niche, appealing to systems programmers only, and that it’s still immature and not really suited to production code. Fine. My problem is that it sure wasn’t marketed that way. The Go team claim that their language is an expressive, concise, clean, and efficient language designed to make programmers more productive. Sounds good to me! Now if only I could learn to use it as such without banging my head against defensive, unhelpful, critical answers on golang-nuts.
So, Go Community, where should I be looking?
Pingback: Tweets that mention The Magic Pantry › Go -- Topsy.com
Hi. I’m the “Go Gopher”.
I’m a Developer Advocate at Google who works on Go. Among other things, my job is to make sure that developers get the support they need to work effectively with Go. Your tweet, and now this post, concern me deeply. I thank you for sharing your thoughts so clearly. It is truly valuable.
First off (and I’m don’t mean to quibble, but) I think you have selected your examples unfairly. The question to ruby-talk regarding variable access is a simple request for information. The questioner was trying to write some Ruby code, and was having trouble grasping a basic concept. As you would expect, the polite questioner received a helpful answer.
By contrast, the first golang-nuts thread you cite – posted within a few days of the language’s unveiling – is not a simple request for clarification, but an impassioned plea akin to a tantrum (“this could be a dealbreaker for me”). Now, unfortunately, the first responder is just plain rude. But the second response is detailed, reasonable, and courteous, and the ensuing discussion civil. Here’s the thread, for the curious: http://groups.google.com/group/golang-nuts/msg/e4d7d3fcb8ee5df5
The second example you provide, pertaining to optional arguments, quotes the least helpful (and last) response in a thread containing a detailed discussion of the issue. And, again, the question is not so much a question about how the language works, but another example of “Why is Go not like X?” http://groups.google.com/group/golang-nuts/t/35631178bd47b9e4
However they’re quoted, I don’t disagree that these are examples of a negative and unhelpful sentiment. Unfortunately, these are symptomatic of an attitude that plagued the Go community early on. Because of Google’s high profile, there was no way we could announce a language project without garnering huge amounts of attention. For a nascent programming language, this is both a blessing and a curse. It was a blessing in that we instantly got the attention of many talented programmers keen to contribute to the project. That enabled us to gain momentum faster than we might have otherwise (we now have close to 150 non-Google contributors).
The curse, however, came in the form of opinion. Hundreds of people descended upon the Go mailing list to provide their suggestions as to how the language could be made better, how it could never succeed without essential feature x, and how we must be fools to not have considered y. All this vitriol from people who had barely even used the language! Perhaps we were naive, but the tone of these interactions blindsided us. As a result, a culture of defensiveness developed among those who believed that Go was actually pretty good.
And now we have a mailing list archive full of these interactions. Whoops.
The good news is: that was then, this is now. There are more tutorials, the package documentation is improving, and – most importantly – the tone of discussion in golang-nuts is now genial and helpful. Myself, other Go team members, and a group of enthusiastic Go programmers spend a lot of time helping people with problems on golang-nuts and IRC. From simple misunderstandings to complex issues, everyone gets a response. We also have an active issue tracker, and most user-reported issues are resolved within a few days.
I would love it if we had a range of mature literature on Go (like Ruby does now), but we’ve only been around less than a year, and there just aren’t that many Go programmers yet. We’re working on it.
As to your question to the Go community: “where should I be looking?” The answers are: golang.org (check the package docs, the spec, tutorials, Effective Go, the code walks and labs, and other documentation), search golang-nuts, search blog.golang.org, ask in #go-nuts on freenode (there’s almost always someone around to help), post to golang-nuts, tweet to @go_nuts or #golang on twitter, and, finally, read the source. You can also try Stackoverflow, where I occasionally answer questions (when I don’t get beaten to the punch), and also a selection of blogs (although there’s no definitive listing of them, yet).
As to your particular query regarding sort.Sort: it’s not immediately obvious, but you need to look more closely at the function signature. Its first argument, data, is of type Interface. That’s sort.Interface. Scroll down to the definition of that type, and you see the methods your type needs to implement to satisfy the interface: http://golang.org/pkg/sort/#Interface
In this case there’s no need (or real benefit) to delving into the source. Once you know what you’re looking for (in this case the type definition), all you need is right there in front of you. Granted, knowing what you’re looking for comes with practice, but fortunately Go is a small, simple language that can be understood in days, and mastered in weeks or months. (Also, I bet if you’d asked on irc you’d have gotten an answer in minutes. :-)
I hope you’re not too discouraged, and decide to give Go another chance. I think you’ll find it rewarding.
All the best,
Andrew / @enneff / @go_nuts
I appreciate the detailed reply Andrew.
Yes, I admit I selected my examples unfairly, but, believe it or not, those kinds of replies, while they may not be the exact ones I first saw, are of the same sentiment as those I first got when searching golang-nuts for answers to questions I had. Like I said, one or two would have gone unnoticed, but at the time every answer I read came across as combative, defensive, argumentative, dismissive and so on.
I don’t think it’s worth trying to continue to illustrate how I think the communities differ; it’s just a feeling I get when browsing posts. I don’t want to come off as a troll, or as a fanboy of one community over the other.
Regarding Sort, that was an example to illustrate how lightweight the documentation is. I understand the concept that the code should be its own documentation, and that delving into the source (and, even better, the unit tests) is instructive. But sometimes you just want a quick example of what works. The Ruby documentation does this well. The Go documentation assumes a level of familiarity on the behalf of the reader that makes it often inappropriate for newcomers.
Besides, one of the more recent posts to golang-nuts (yesterday) says to “Consider the Go package source code as part of the documentation.”
And yes, I’d read everything on golang.org, including the FAQ, tutorial, effective Go, language reference and so on. While these documents are nice to have, they’re not as comprehensive for the newcomer as something like Programming Ruby.
I’m not discouraged at all from using Go for my project, but I am discouraged from using golang-nuts as a resource for learning the language, and I do feel as though the documentation on golang.org isn’t as comprehensive as I need it to be. All this means that the learning curve is steeper than it need be, which is a shame. But it won’t stop me :)
Doing some more Go programming today. In the afternoon I started searching Google, because I was having trouble running the scanner on UTF-8 strings and printing individual “runes”. Here’s the first hit I got:
“Why all functions related to unicode use an ‘int’ to working with
unicode values (runes) instead of use an ‘uint’?”
And here’s the answer:
“This is another speculative question. First, do some research by
reading the documentation, second, frame the question in the form of
a testable hypothesis, and, third, test the hypothesis”
Grrrrr!
Lloyd,
I agree with pretty much everything you’ve expressed here. I’ve also been very excited about Go, but I’ve found that it just doesn’t have the warm welcoming community that Ruby has. Not by a long shot.
Speaking of Ruby and Go, how about this implementation of the n.times concept?
// You can edit this code!
// Click here and start typing.
package main
import “fmt”
type Enum int
func (enumerator Enum) Times(block func(int)){
for i := 0; i < int(enumerator); i++ {
block(i);
}
}
func main() {
Enum(5).Times(func(i int){
fmt.Println("Iteration ", i);
});
}