Hacker News new | ask | show | jobs
by treve 2745 days ago
One of the thing that's always been a bit off-putting about the Go community and leadership is that it seemed that when I came across things that I perceived as flaws in the tooling or language, I often felt told off and was made to feel that it's me who is wrong for a variety of reasons. Examples of this include GOPATH, the package infrastructure, error handling, lack of generics. Rob Pike disagrees so I must be wrong.

It's kind of satisfying to see that the "Go way" wasn't the best way after all and that some of these things are actively being addressed. I hope it makes the community a bit more welcoming as well.

10 comments

I think this is an example of rounding things off to one bit: either a feature is good or bad. Worse, people will round a language off to one bit: either it's great or terrible.

Sometimes this is just due to defensiveness: someone uses a flaw to say the whole language is terrible and that gets a response from people who have learned to live with the flaw.

Generally, if you back to the original statements you'll find something more nuanced: generic types have a lot of complicated effects on language design and they didn't like their own early proposals, so they started out without them. Yes, error checking can be repetitive, but many of the attempts to fix that in other languages were worse.

In the meantime, the "Go way" is about following common conventions for working within the language's limitations. This isn't a bad thing!

But it's tricky to be welcoming while getting across that the best way to deal with limitations is just to accept them, for now. On the Internet, everyone wants to be Steve Jobs and demand changes.

(Also: Rob Pike, not Erik.)

Lots of people have made the same complaint/observation, though, and I don’t think they’re all just “rounding it off to one bit” as you describe.

I think they’re onto something, though as the GP notes, hopefully the situation is improving.

I’d flip your response around and suggest that in several cases, the correct fix is obvious and the core Go team’s insistence on extreme caution and “nuance” is misguided. GOPATH is a great example -- it’s just so obviously wrongheaded that I really don’t understand why it stuck around so long.

Another one that comes to mind, although this is quite old now, is the way early versions of Go would insist that the very last statement of a function was a “return”; you couldn’t do an “if foo { return x } else { return y }”, for example. It took a lot of pushing to persuade the core team to add some basic escape analysis, against insistence that it was some kind of nuanced feature with unpredictable side-effects, rather than a trivial thing that every other real compiler has to do.

> In the meantime, the "Go way" is about following common conventions for working within the language's limitations.

Except the problem is that "the Go way" changes in a way that breaks your previously-"working within the language's limitations".

An example of this that comes to mind is how the Go 1.5 vendor/ change was done. The community had rallied around several tools that would do vendoring and then would modify GOPATH to include vendor/ and would then symlink the current project into vendor/. All this required was a vendor/src. The Go 1.5 vendor/ implementation was almost identical but they removed the src directory -- which meant that pre-1.5 vendoring was now broken by Go (you can't really have two copies of your vendor tree in a repo and symlinks wouldn't work either).

There are a few other examples of this, but this one sticks out as it was the first feeling I got that the Go development team doesn't really care how the community has decided to work around a language defect. It literally would have just taken them one additional directory to not break every vendor/ project.

(Also, there has been absolutely no discussion with distributions -- as far as I'm aware -- on how packaging Go binaries should be done so we're all forced to come up with our own ideas. The Go modules stuff has considerations -- like builds requiring an internet connection -- that distributions would've had input on, but we didn't get asked about it.)

Contemptuous scorn seems to be the officially-sanctioned strategy for responding to reasoned critique or even questions about "the go way" within the community.

My favorite example here is this arrogant dismissal of the idea that a one line expression, rather than a 5 line mutating statement, might be preferred for conditionally setting a value:

    if expr {
        n = trueVal
    } else {
        n = falseVal
    }
> The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct. [0]

...

   n = expr ? trueVal : falseVal
"Unquestionably"

[0] https://golang.org/doc/faq#Does_Go_have_a_ternary_form

What I find particularly off-putting is that this attitude of superiority is sometimes married with objective incorrectness. If you're going to claim something is black and white, it should actually be black and white.

&&, ||, switch, select, for, and while all do conditional execution in Go.

So the rule is not "A language needs only one conditional control flow construct." The rule is really, "We didn't think a conditional operator was worth it." That's a fine rule, but it's better to be honest about it than to pretend the language was designed around some pure principle that doesn't actually exist.

Yeah, I agree about it being off-putting. There's very little science in programming language ergonomics, so it all comes down to taste, right?

However, I wonder how much of this is a difference in substance and how much is about writing style? There is an older, authoritive style that has an implicit "in our opinion, of course" and sounds pretty grating these days.

I remember being taught in school to remove "I think" and qualifiers expressing uncertainty, under the theory that in an opinion piece, that's understood.

Especially these days when hyperbole is common, I prefer writers that have a humble writing style, but also try not to get hung up on stylistic differences.

The authors of Go have stated they themselves sometimes miss the ternary form, but have seen it abused too much (deeply nested ternary).

This isn't an insult to programmers, it is an option that clarity of code is more important then continence. Thus all if and for statements also require {} brackets.

This would be a reasonable position:

"While the ternary is often clearer, we chose to sacrifice expressiveness and brevity for the sake of preventing abuses, which we found were all too common."

But that is not the claim being made in the FAQ.

> Thus all if and for statements also require {} brackets.

Indeed this rule seems to spring from the same philosophy. It is most certainly not a preference for clarity, though. It is a preference for consistency.

The philosophy is: "We're giving up expressiveness and brevity because in our experience most people can't be trusted to not shoot themselves in the foot."

This choice would be much more palatable if they were honest about it. But instead, they take the road of insisting that the verbose consistency is actually clearer, which it isn't, at least in many people's opinions.

> It is most certainly not a preference for clarity, though. It is a preference for consistency.

FTR, with "most certainly" you're committing the same fault your accusing the Go team here. You might not think it matters for clarity. I, at least, disagree.

> in our experience most people can't be trusted to not shoot themselves in the foot.

I don't understand the difference between this suggested phrasing and talking about clarity. I'd argue you tend to shoot yourself in the foot if and only if you aren't clear about what you're doing. Clarity and lack of footguns seem directly correlated.

> FTR, with "most certainly" you're committing the same fault your accusing the Go team here.

Fair enough. It's too late to edit.

> I don't understand the difference between this suggested phrasing and talking about clarity. I'd argue you tend to shoot yourself in the foot if and only if you aren't clear about what you're doing.

This is partially true but it's not that simple imo.

In my OP, the ternary version is clearer. But if you allow it, then you also open the door to nested ternaries, and foot shooting.

Allowing single line if statements (as, eg, ruby does) also allows for clearer code, at the expense of consistency.

> Allowing single line if statements (as, eg, ruby does) also allows for clearer code, at the expense of consistency.

This (or rather allowing conditionals without braces) was what I was referring to. They are a foot-gun, because of the lack of clarity. It's a common source of bugs in C/C++ code that a developer thought they'd add a line of code to a conditional block or loop but didn't, because of a lack of braces. Requiring braces unconditionally make it always unambiguous and obvious what block a given statement belongs to.

Obviously YMMV - this is, as most discussions in programming, a matter of opinion. Which was my point :)

In 10 years the expression form will be added to Go. It will be hailed as great progress, as adding clarity, and as unquestionably the Go way.
Oh man don't tell me these things. I haven't used Go yet in production, but the more I learn about the ways it diverges from functional programming, the more I doubt I'll ever use it.

I was thinking I could write my own if(condition, true_case, false_case) method similar to the way it's done in spreadsheets, but Go also doesn't have macros or inline if/else expressions, so there is simply no way to emulate ternary logic in a performant manner :-(

Oh let's be very clear: Go is actively, explicitly anti-FP, anti-expressiveness, anti-brevity. Those are simply not its values. And any attempts to write Go in FP style will be considered unidiomatic Go.

And the missing ternary will be the least of your problems. Do you enjoy `map` and `filter`? Sorry, the "go way" is to use a for loop every time. Reimplementing map on every type where you need it is considered best practice in Go. Have a problem with that? Expect a snarky comment about your priorities.

This can all be pretty frustrating when you've experienced the joys of more expressive languages.

Go has good concurrency primitives and is fast. That's what it's good at. Those are the reasons to use it. Temper your expectations accordingly.

> Have a problem with that? Expect a snarky comment about your priorities.

Whereas your comment is completely devoid of snark.

That comment, however, is a comment on hacker news.

Not the official docs of a programming language. In one of those, a bit of snark is really quite normal and of no real impact.

Why not have if/else be an expression in the first place, like Kotlin?

  n = if(expr) trueVal else falseVal
No need to learn a separate ternary operator.
Quite a few languages do if expressions, and IMO they’re great. Simple syntax, readable and powerful. It’s crazy to me that any new language wouldn’t have them.
The argument specified in the docs is "a language needs only one conditional flow construct" (in a language, of course, that has half a dozen conditional flow constructs ...)

The more palatable argument that people who try to cover for ... seems to be that when people nest if expressions, it becomes a mess. I'm glad these people exist.

The real reason is found here: http://dtrace.org/blogs/wesolows/2014/12/29/golang-is-trash/

(or if you prefer, in the compiler's source itself. It doesn't take a compiler expert to realize it's not very clean code. Even violates the go style, and the C one before that was just horrendous)

The TLDR is that Go's compiler is a "fisher-price my first compiler" and really shows that the authors simply barely knew how to get a compiler working in the first place. That they were not ready to go into a rational discussion on programming language and type theory ... is not something anyone should be surprised about.

That they avoid the arguments by dismissing the people making them in such a condescending way is ... well, there's not really anything good to say about that.

Ken Thompson has been writing compilers for over 50 years now. If you believe that Ken "barely knew how to get a compiler working in the first place", we have nothing to talk about, as you obviously made up your mind already.
Then read the source for the compiler yourself. Tell me I'm wrong.
Because the designers of Kotlin are more open to experimentation and new ideas.

  (setq n (cond
    (expr trueVal)
    (t falseVal)))
This particular idea dates back to at least 1965.
Er, yes, I should say “new ideas about which features are worth stealing from Lisp” :)
> A language needs only one conditional control flow construct.

If by "one" you mean `if` _and_ `switch` then yes!

and `select`
I don't know. While no doubt some individual conversations have played out this way (law of averages and all that), I think this is a bad way to characterize the overall conversation. From my viewpoint, the conversation is largely people coming from other languages telling the Go community its way is wrong while the people on the Go team argue that there are tradeoffs that they'd like to explore. For example, pretty much every Go-related conversation over at /r/programming seems to have someone arguing that it's literally impossible to build software in a language that lacks generics (or exceptions) while people from the Go community argue that generics are probably worth the tradeoff, and then only if the maintainers can figure out a way to implement generics _well_ (i.e., not like C++ or Java).
>I don't know. While no doubt some individual conversations have played out this way (law of averages and all that), I think this is a bad way to characterize the overall conversation.

Most everything I've seen from the Go camp, including the new re-discovery of various wheels with the Go 2.0 proposals, felt like the parent describes to me.

Never got the same from Rust, otoh.

I don't really want this thread to further devolve into a tit-for-tat. I'll just say that Rust's community has its bad eggs like any other, but that it does do exceptionally well at sympathizing with criticism. I'm mostly in "the Go camp", but Go's community can learn from Rust's here. On the other hand, for whatever reason, Rust is rarely approached with the same hostility that Go's community is--at least I don't see nearly the same percent of threads in /r/rust in the form, "I've been using Rust for 2 hours now and I haven't been able to figure out lifetimes and lifetimes are different than my language so lifetimes are stupid and no one can ship code with Rust!"
See comments for Rust new website thread on reddit and elsewhere. Most Rust community seems mightily pissed off for all negative comments about their newly designed website. Besides Rust enthusiasts have reputation of trolling random people on internet who have unflattering things to say about Rust.

Or try opening new thread on Swift forum on issues where decisions have been take. They will quickly put you in place and close the thread.

I have yet to see a successful language where whiners are embraced with great enthusiasm.

>Besides Rust enthusiasts have reputation of trolling random people on internet who have unflattering things to say about Rust.

I don't speak about Rust enthusiasts or even the Rust community at large, there are people like that in all languages (though indeed some communities might be better than others, but with large enough numbers of users of a language you get all kinds of people in a similar enough distribution).

I speak of the core team. Go's one has a vibe I don't get from Rust's.

> I think this is a bad way to characterize the overall conversation.

> pretty much every Go-related conversation over at /r/programming seems to have someone arguing that it's literally impossible to build software in a language that lacks generics

Literally literally? Isn't your reply a "bad way to characterize the overall conversation" as well?

> Literally literally?

Yes; I've challenged this as hyperbole and people double down.

> Isn't your reply a "bad way to characterize the overall conversation" as well?

I don't think so. My reply characterizes the overall conversation as a difference of opinion about whether or not Go's design choices are matters of tradeoffs, and I believe this to be accurate. I chose my example because it was exceptionally stark, but the point is that if such stark comments are made so frequently, surely there is a long tail of less-stark comments. Anyway, I don't want to belabor the point because we have no data and all we can do is conjecture and stir up bad feelings and likely a flame war, so let's not do that.

the fact that you call Rob Pike "Erik Pike" really reads like the complaints of someone who doesn't do their homework and asks questions that have already been answered in many places.

Generics is a major tell, too, since the Go team's position on generics was always "generics are interesting but we don't know how to make them work well with Go's existing type system". See for example, this blog post from 2009: https://research.swtch.com/generic which references the FAQ answer to the generics problem here: https://golang.org/doc/faq#generics: "Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a design that gives value proportionate to the complexity, although we continue to think about it."

so I can see why people who have repeatedly answered the same question for years, only to have their answer misrepresented for years, to be annoyed when people who haven't read any prior discussion bring up a point that has been already talked about ad nauseam.

Sorry about mis-remembering his name, but my point was a bit more nuanced. The frustration I had was not that certain features were missing, but I was met with a response that suggested that I was wrong for even wanting these features.

It was a comment on my personal experiences of interacting with the Go community, not the language and its limitations. My hope wasn't that Go implements my every pet peeve, my hope is that the community has gained some humility since I last dipped my toes in it.

Pike seems especially aggressive when interacting with people he disagrees with and this was for me indicative of the culture. It's been a few years though, so maybe by now I'm wrong!

Here's Pike on the topic of syntax highlighting:

https://groups.google.com/d/msg/golang-nuts/hJHCAaiL0so/E2mQ...

I think you mis-linked there. The email message with the denigrating comment about people who like syntax highlighting is here...

https://groups.google.com/forum/#!msg/golang-nuts/hJHCAaiL0s...

That was the day I dropped the mailing list.

I don't see anything denigrating there.

I disagree with Rob though, syntax highlighting is not juvenile, it's cargo cult programming.

"Syntax highlighting is juvenile."

That clearly implies anyone who uses syntax highlighting is juvenile. I'd say calling someone juvenile is meant to be denigrating.

> Pike seems especially aggressive when interacting with people he disagrees with and this was for me indicative of the culture. It's been a few years though, so maybe by now I'm wrong!

FWIW, as much as I agree with Rob Pike on most things, I totally agree that he's abrasive and his way of phrasing things is often unhelpful (even though I think people also tend to read contempt into his brevity that isn't there). If it helps, I think he has realized that in the meantime and is largely staying out of public discussions for that reason.

The community has gotten better. Early discussions were frequently marred hype, and it was often impossible to cut through the noise. However, talks given by the authors usually impressed me by being fairly even-handed, and open about the trade-offs that were taken.
He's literally just making a joke riffing on 1 Corinthians 13:11.
No, while he does reference that (just quoting it directly, not “riffing”), it's not just a joke, it's a reinforcement of his earlier dismissal, in the thread, of syntax highlighting as a “juvenile” practice parallel to colored rods used to teach arithmetic to young children, which grown ups should not need or use.
The kinds of parametric polymorphism implementations mentioned here do not represent the full set of options. Charitably this represents an ignorance on the part of the Go developers, but really it has felt like an apathy towards the field of programming language design and research. Intensional polymorphism (basically passing the type of a parametric argument as a parameter, and either using a specialized implementation of the function or one that operates over a boxed value) has been known about for years and is used in languages like Haskell: https://www.cs.cmu.edu/~rwh/papers/intensional/popl95.pdf
That paper is mentioned in the comments of my first link. I would be surprised if the Go team doesn't know about it. In that thread, as well as here, both you and the other poster haven't actually stated how the paper's strategy would work for Go, and haven't actually stated how the strategy affects compile times, binary sizes, and execution time.

edit: addendum: but also, in every thread about Go, there are some Haskell people showing up to talk about how the Go team is too stupid to understand the Haskell type system. This happens regardless of what the opening topic is, which in this case, is dependency management. No matter what the topic is, if it's a thread about Go, you will find Haskell programmers there, condescendingly talking about how Haskell's type system is so much better than Go's type system. It is very tiring.

I wrote a blog post about the error handling. Someone put it on /r/golang (note the subreddit name).

There were 22 comments, and the one from the Go developer was (and I quote):

"Tempted to stop reading after the first word in the article. (The language isn't called Golang)"

There are "I've used Go for a week and here are my strong opinions on it!" posted to reddit (and elsewhere) every week.

Frankly, it's just tiring; especially as a lot of the same points and misconceptions are repeated. Some points are valid, but it's repetitive at best. It would be like discussing Python's significant whitespace with inexperienced Python programmers every week. Sure, it's quirky and arguably not a good idea, but the discussion had been done a few times already.

Turns out that filtering stuff that uses "golang" instead of "Go" is actually a pretty good heuristic for determining if an article is worth reading. Is it perfect? Of course not; it's a heuristic.

Reading your article, this is exactly the sort of "been there, discussed that" kind of example. Your article isn't bad – I think it's mostly on-point – but it's also pretty much a repeat of what many others have said/discussed.

I started using Go in 2008, but I get your point.

Still, I think my and my parent's point is that: it would have been better if they'd just said nothing.

> I started using Go in 2008, but I get your point.

Yeah, it's an imperfect heuristic. I didn't intend it as a remark about you or your article in particular (I had added a sentence about that in my previous comment, but it must have gotten lost in the editing).

> it would have been better if they'd just said nothing.

Yes, I agree. "If you can't say it nice, then it's probably best to not say anything at all". I thought it would just be helpful to explain some of the frustrations that are (probably) behind the comment.

Do you happen to have a link to the reddit post or to your article?
That's a really disappointing story. Fortunately these sorts of attitudes aren't common in the Go community.
Such putdowns are a regular occurrence in Golang-nuts (ironically, the Go team has named their own/list forum "golang-nuts" despite that "not being the name of the language").
"golang" is the official disambiguation, so it's factually incorrect to call people out for using that term. I don't follow that mailing list particularly closely, but I've not seen anything like this in the threads I have perused. To the extent that these things happen, the community should address this behavior.
> "golang" is the official disambiguation, so it's factually incorrect to call people out for using that term.

I don't think "factually incorrect" is warranted. It's factually correct that the language is called Go. And while "golang" is a useful alternative for searchability and where "go" is taken, it is still a valid criticism to request using "Go" in natural language and prose. As for "official disambiguation", I'd say the most official thing said on the topic is this FAQ entry, which is quite clear on the matter: https://tip.golang.org/doc/faq#go_or_golang

(not saying Brad's comment isn't abrasive or rude. But it's not "factually incorrect")

Seems like you're splitting semantic hairs.

The language maintainers regularly and consistently use "golang" as a disambiguation:

* golang.org

* github.com/golang

* Twitter @golang and #golang

* golang-nuts

In this context, it seems pretty "official" and the rebuke "factually incorrect" or at least the rebuke applies equally to the maintainers.

That said, it was a single wayward comment and it is (in my experience) out of character. I want to acknowledge that it was rude and validate the person who was wrongly rebuked; I explicitly don't want to pick on anyone nor tempt the Internet to pile on.

> ironically, the Go team has named their own/list forum "golang-nuts" despite that "not being the name of the language"

FWIW, go-nuts was already taken.

What I've come to learn from using Go on a number of projects and reading the long mailing list threads on topics that lead to the decisions and development of language features is that Go is a language intended for many programmers (e.g. average) to be successful writing systems(-like) software. Officially, it was meant to be for systems software, but it's since expanded beyond that scope. Given that it's designed and developed by very bright authors for everyday programmers, it's actually surprising how much thought has gone into seemingly obvious language features. They want users of the language to be successful more than they want their users ego to be happy about language features.

Given that, they do also 'talk down' in their official documentation. I had to look back in time to understand the memory model for the sync.atomic operations which is documented:

"These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory."

The final word on what 'great care' means is that Go doesn't actually have a memory model for this part of the standard library. The discussion thread around it has a different tone than the official documentation. They agree on how they want implementations to operate, but don't feel that it needs to be officially defined or documented. I would have been happy if they at least referenced the discussion thread rather than merely label it 'great care' meaning 'not for you'. The other thing you find is that the performant parts of the standard library often does not follow "Share memory by communicating; don't communicate by sharing memory".

One of the betrayals when working with I/O was finding that standard library routines can return a value AND an error, and that sometimes a non-nil error is not an error (EOF is not the only one of these).

I agree completely, that’s precisely the same impression I got. Maybe it was mostly from discussions on HN and it doesn represent the community at large. Whatever the reason I’m glad to see focus on fixing the GOPATH abomination and the plan to finally add generics in Go 2.
Honestly I got the impression no one ever liked gopath.
I hated it at first but came around over time, to the point where I haven't switched to the modules workflow yet.
The modules workflow is a wreck currently. Defer a while if you can.
care to explain why? I've been using it across all my projects just fine.
My biggest complaints are when something goes wrong. It will frequently silently fail or act like it succeeded. Diagnosing these errors has been a major time sink since I started using it.

Next have been oddities with vendoring workflows. Given previous decisions it seemed like the golang team was driving towards vendored solutions but with go mod they seem to have backed off of that position. The workflows with go mod are clunkier & less well documented. Unfortunately I’m (and my teams) are highly invested in vendored libraries.

We’ve also had trouble with it not playing nice with dependencies that have not taken up modules (and some that are unlikely to).

That’s not even to mention my problem with their design or the hamfisted way they have gone about it, which is something I just have to get past.

I think a primary problem with the modules workflow is that you can't switch to it until all Go projects you work on switch to it. Plus, all of us have got our own GOPATH home-directory workarounds so there's no real point in switching anymore.
That's not true at all. A Go-modules-enabled project can import packages from a non-modules-enabled project that doesn't have Go.mod in it. This was always the case with Glide and Dep, too.
That's not what I'm talking about. I'm talking about being able to build outside of GOPATH. This requires the top-level project to use go.mod and many don't (like Docker for instance).
But that's not the same thing. You don't have to switch all the projects you work on over to Go modules at the same time, only the projects you want to upgrade. It's entirely possible to migrate incrementally.
> I think a primary problem with the modules workflow is that you can't switch to it until all Go projects you work on switch to it

It seems this gets fixed in Go 1.12 though. AIUI you'll be able to set GOMODULES=on, unset GOPATH and just continue working as before.

Same here. Will wait until Aug 2019 when I have to think about it.
Pretty much every language has a GOPATH thing.

CLASSPATH, PYTHON_PATH, PERL5LIB, ...

I never really understand the hate here. It seems more like they didn't hate GOPATH specifically and more that they didn't like not having a package manager.

GOPATH behaves very, very differently from PYTHON_PATH and CLASSPATH, it is not the same thing at all.

Basically before go 1.11, it was impossible to just do

    git clone ... somedir
    cd somedir
    # build code and run something
You had to instead make sure "somedir" ended up somewhere within a particular deep directory structure. That is what people mean when they say "GOPATH".
> Basically before go 1.11, it was impossible to just do

That's not true. It was always perfectly possible to do that, the code you build just couldn't import any libraries not installed in GOPATH. AIUI that is exactly the same as in other languages.

Our git repo for a backend service contains dozens of packages, and many small packages is recommended in go, and they do need to import one another...

I guess it is not all that different from Python, with Python you need to add the source path to PYTHONPATH / sys.path (and often do so at runtime in the entrypoint script). With go you need the "src/github.com/dagss" prefix to the path. Or at least, according to conventions. You are right that it is more similar on a technical level than what I thought.

The ones listed by you apply mostly as library search path, while go compilers required GOPATH to point to the project being compiled.
False.

You can put your code anywhere you want and `go build` and `go run` will work just fine.

It's only third party libraries that have to be in GOPATH, which is exactly a library (well, package) search path.

False only for very small values of code.

ie if your code itself is split into modules, they won't work (as they are imported by their full path, not relatively), and anything in your vendor dir is also ignored when used outside of a GOPATH entry.

Java, Perl, and Python all date back to the '90s. Yeah, that was a commmon pattern in the '90s.
Because setting environment variables is something most devs like to avoid.
No, because I have like 50 projects in ~/src and suddenly have to keep some of my code in ~/src/go/src/GitHub.com/cgag and that annoys me.
I have tried several times to fix this problem in the past 5 or 6 years, once with symlinks (which would break quite often -- it's unsurprising that Plan 9 developers wouldn't care too much for handling symlinks correctly :P).

The current way I handle it is that $HOME/.local is my GOPATH, and $HOME/src links to $HOME/.local/src. So you can just have $HOME/src/github.com/bar/foo -- which is less ideal than just $HOME/src/foo, but it's something at least.

I keep the source code for my projects in ~/src and I always set my GOPATH to my home dir. So the special 'go' in the path can be avoided. It will just be ~/src/github.com/...

But, yes, I rolled my eyes when learning about GOPATH for the first time.

it's not just that large numbers of projects are a hassle, they make it harder to develop projects in isolation
i think the "Go way" was more like: Google have a different in-house solution for this so let's just leave it out and for something to bubble up out of community.

Go solves Googles main problem -> something which new engineers can use to write practical solutions without having to think too much. It's not beautiful or expressive or technically interesting; most "craftsman" devs won't stick with it too long..But that's not the majority of devs google is hiring.

Sit down, bang out code and don't concern yourself too much with craftmanship - it will be re-written in a couple of years. Just worry about performance.

And then proceed to shit on whatever did bubble up from the community, at least as far as package management goes. I’m glad we’re finally getting the core team to focus on modules but as an outsider that whole situation was handled poorly and doesn’t give me a lot of faith in solutions bubbling up from the community.
I was very active in the community at around the 1.0 release time, and probably am guilty of this, so late apologies. The problem in my eyes was that this was a new language that really solved a lot of problems in its simplicity from experience. And we all know design by committee is a disaster. The list was under a -constant- barrage of 'you should do X like language Y.' The general response from the community was along the lines of 'if you like language Y, you should use that, stop polluting the mailing list.' Essentially, it quickly got old with the constant asking of things, many ridiculous, that I feel probably a few good suggestions got thrown out with the weekly trash so to speak.