> design patterns--and we should be reminded that design patterns exist to address defects in tooling
This is a really important point, and I think it's why a number of best-practices in Go are actually not best practices in other languages, and vice versa.
One of the explicit, top-level design goals of Go was to focus on creating top-notch tooling as part of the language. While it is not the only language that has tried to do this from the get-go, it's one of a very small number[0].
Because the tooling was a first-class design goal, a number of the problems that traditional design patterns were created to address are less problematic in Go code[1].
[0] Case-in-point: gofmt, which other languages are now adopting due to its success.
[1] Again, gofmt: there are a number of design patterns and style bikesheds around code format, but really, the most important thing is that there exist a uniform standard. gofmt provides that reliably and a way to enforce that as a pre-commit hook, which has done wonders for eliminating minor style variations that IMHO cause more problems than they solve.
Top notch tooling? The debugger is neigh unusable. `go get` is a community joke. The compiler is fast mostly because it doesn't check for things that better compilers do. Go race is a symptom that not all is well in the CSP house. Other static analysis tools are third party and limited if they exist at all. Go really does remind me of JDK 1.4.
I'm sad that your post is downvoted, because (while I might have been a little more pleasant about it) I think you're generally on-point. The debugger is pretty poor, the compiler is pretty poor, there isn't much static analysis (and while the language's youth is an excuse, the profusion of tools for more semantically rich languages like Scala make me skeptical of the excuse).
I didn't mention Java 1.4 just for a lark; it's been long enough since I used it that I don't remember the ecosystem well but I do remember the style of coding being so brutally centered around type assertions and blind casts that Go really does remind me a lot of it.
Perhaps his post was downvoted because he made a strong assertion - "the compiler is fast because it doesn't check for things that other compilers do" without elaborating or providing any evidence. This is the first time that I've seen someone complain about deficiencies in the compiler too, so that adds a little skepticism.
Could you elaborate on the static analysis that you find lacking?
Actually JDK 1.4 was much, much better than Go for tooling.
The debugger was usable. You had realtime memory/CPU profiling tools like JProfiler. There was a workaround to get JMX working (JMXRI) with is great for production monitoring. Code formatting tools were significantly better than gofmt. You had bug finding static analysis tools e.g. Findbugs which integrated well into build tools.
And of course you had great IDEs like Eclipse (which was actually great back then), NetBeans, JDeveloper which allowed for refactoring, autocompletion and code assistance.
You're right of course but what I meant was what it's like to actually type the code in and read other code more than the rest of the rant which is about tooling. In many ways saying "Go is like JDK 1.4" is a compliment as JDK 1.4 was older than Golang is now.
I'm working with Golang every day now and the ONLY reason I'm using it is its CSP concurrency model, which is still way behind what Clojure's core.async can do.
> Because the tooling was a first-class design goal, a number of the problems that traditional design patterns were created to address are less problematic in Go code[1].
> [1] Again: gofmt…
What does gofmt have to do with design patterns?
gofmt is about code formatting. Design patterns are about abstraction and expressiveness. A code formatting tool does nothing to address abstraction and expressiveness of the language.
> gofmt is about code formatting. Design patterns are about abstraction and expressiveness.
First, gofmt can do more than code formatting, such as applying simplifying code transformations that are semantically equivalent. Second, code formatting and design patterns are indeed related, because the way code is laid out in text is the way that design patterns are expressed. The layout of code affects how abstractions are presented, which affects which abstractions are easy to reason about and work with.
Finally, I picked gofmt because it's a pretty uncontroversial tool, and one that is so successful that even languages like Rust have adopted or are working something similar. I'm really not interested in starting another flamewar about why Go lacks $FEATURE and therefore $OTHER_LANG is better, because we have had enough of those on HN, don't you think?
> First, gofmt can do more than code formatting, such as applying simplifying code transformations that are semantically equivalent
Which also has nothing to do with design patterns. (At least not if you're limited to the extremely basic -r gofmt rewrite rules.)
> Second, code formatting and design patterns are indeed related, because the way code is laid out in text is the way that design patterns are expressed. The layout of code affects how abstractions are presented, which affects which abstractions are easy to reason about and work with.
No, I don't buy that a code formatting tool obviates the need for design patterns. How does gofmt replace the Visitor pattern (just to pick one at random from the GoF)?
> No, I don't buy that a code formatting tool obviates the need for design patterns. How does gofmt replace the Visitor pattern (just to pick one at random from the GoF)?
Asking if a code formatting tool "obviates the need for design patterns" is the wrong question, because it assumes that there is a need for design patterns in the first place.
I do agree with you that a code formatting tool is not capable of somehow fixing software design and architecture decisions. However, "design patterns" by their GoF meaning exist as to address shortcomings of the languages and tools used: most of their advice does not make sense as soon as you move away from Java into less object-oriented or less procedural languages. To talk about "the need for design patterns" as if they are some sort of mathematical truth is misleading and dangerous.
You do need design patterns in Go. A prime example: the interface that Sort() requires is basically the Strategy pattern. You need it in Go because the language is missing generics. There are many other examples.
In that message, Rob Pike misunderstands what the visitor pattern is for. Go's "type switch" is just chained Java instanceof. Java still benefits from the visitor pattern for (e.g.) compiler transformations, even though it has instanceof.
This is one of the more troubling aspects of the parts of the Go community that I am exposed to--aggressive insularity. It's perhaps cyclical--in the past I've made similar criticisms of Node, and did of Ruby before the hype died down and the more aggressively enthusiastic people calmed down or moved on--but it's kind of a pain in the rear at present. That said, Go's deification of a single individual is unique to me; of Matz, Guido, Bjarne, Gosling, or Rasmus, I don't know any who are quoted as if it's by itself persuasive. What Rob Pike says about things is not necessarily correct--and sometimes it's not even accurate--but seems strangely, to Go advocates (as separate from "Go users"), to immediately enter a sort of canon to be trotted out at every opportunity.
All languages need design patterns; they are about designing how to implement certain functionality.
Languages differ in which design patterns have a native expression in the language, which can be reduced to simple reusable library code, and which require type-it-in-each-time fill-in-the-blanks code recipes.
The fact that Design Patterns were popularized in software development by the GoF book which, among other things, included code recipes to illustrate its patterns, and that the patterns in it tended to be ones for which the popular languages of the day required code recipes (lacking native implementations or the ability to provide general implementations as library code), has unfortunately associated the term with the code recipes, which aren't really the central point of understanding and using patterns.
> How does gofmt replace the Visitor pattern (just to pick one at random from the GoF)?
This would not be the first time that we have had a discussion on HN about this exact design pattern in Go, so it's hardly a random choice. And given past precedent, I think it's best if I end my half of the conversation here and propose to agree to disagree. To quote my previous post,
> I'm really not interested in starting another flamewar about why Go lacks $X and therefore $Y is better, because we have had enough of those on HN, don't you think?
This is a really important point, and I think it's why a number of best-practices in Go are actually not best practices in other languages, and vice versa.
One of the explicit, top-level design goals of Go was to focus on creating top-notch tooling as part of the language. While it is not the only language that has tried to do this from the get-go, it's one of a very small number[0].
Because the tooling was a first-class design goal, a number of the problems that traditional design patterns were created to address are less problematic in Go code[1].
[0] Case-in-point: gofmt, which other languages are now adopting due to its success.
[1] Again, gofmt: there are a number of design patterns and style bikesheds around code format, but really, the most important thing is that there exist a uniform standard. gofmt provides that reliably and a way to enforce that as a pre-commit hook, which has done wonders for eliminating minor style variations that IMHO cause more problems than they solve.