> Although it's far from certain, after over a decade of work it looks like a design for parametric polymorphism, what is colloquially but misleadingly called generics...
What exactly is misleading about generics?
The psychology of thought leaders is fascinating. The term generics is colloquially understood to mean parametric polymorphism and here's Pike redefining the term to draw some distinction that doesn't really exist just to remain self-consistent.
Come to think of it, this is a really common pattern. If you've made remarks that you must now backtrack then refine terms until your old writing doesn't seem to contradict your current stance because you can just say people were using the terms wrong and you were right.
This is probably just age. I had two CS professors, one in the late 90s and the other around 2004, draw a similar distinction.
"Parametric polymorphism" was the "whole" feature, while "generics" meant specifically generic containers, usually wholly agnostic about their type parameters, like std::map or std::list. Since the rise of Java Generics (which are really somewhere in between, more than containers but less than full parametric polymorphism) I don't hear this distinction anymore.
You know, Pike was at Bell Labs for a few decades when it was the premiere computer science research place on the planet. It's possible that he has a more technical definition of generics in mind here. (Or he could be being evasive. What's quite unlikely is that he doesn't know the real definition of generics.)
I don't think Go's proposed system is parametric either. It's not clear to me how their contracts actually map to generics so I have no idea if Pike is telling the truth or just "thought leading".
What a wild generalization. I skimmed the article, and I see his point in "Go was designed by people working at Google to make it easier to write Google-relevant software, in particular network-resident servers", but that doesn't mean Docker and Kubernetes (and other tools that enable communicating with/usage of cloud infrastructure) being written in Go made it become the de-facto standard, and especially not "the language of cloud infrastructure". What about ALL the other components NOT written in Go?
Go certainly has a lot of mindshare in this space, and that can't be ignored. Some components of my production infrastructure I've used over the last year: cert-manager, concourse-ci, docker-registry, cilium, coredns, loki, grafana, prometheus, jaeger, influxdb, kubernetes, open-policy-agent; all those are Go. It's at the point where if you're in the business of writing software to run software, you're kind of surprised if you show up at some Github repo and it's not written in Go.
But, the joy of 2020-era design is that nothing is forcing you to use Go. Everything is coupled with network APIs these days, so you can generate your protocol buffers for whatever language you want and write your chunk in that. You don't have to look at the success of Go in this space, think "but I don't like it", and leave the field. You can do whatever you want. But, I do think it's accurate to say that Go has a lot of mindshare in this sphere of the Universe. It is what it is.
That is my exact observation as well, whenever I go to use and examine a piece of narrow and self-contained piece of Open Source software I'm not surprised to find the good ones are often written in Go. Some things that come to mind are Hashicorp Nomad, nsqd, InfluxDB/Telegraf, restic, etc.
I think the common thread here, and what separates this from internal tools a la "Amazon is 90% Java" is that these tools are Open Source from the beginning and want to encourage community contribution as much as possible. I don't like using go myself, but even I can't deny that if you're running an Open Source project and would like to encourage contributions from people of different levels of involvement and general programming proficiency, go is one of your safest bets.
Huh? I am sure 80%+ of AWS is Java and probably 90%+ of Azure is C#. I doubt it is going to change any time soon. Kubernetes is but one successful cloud product out of Google, and it just happened to be written in Go. There are even rumors in that thread about it starting as Java.
80% of AWS existed before Go was invented. Why would they rewrite that stuff? They're already #1. They have nothing to gain and everything to lose.
I think to get an idea of what mindshare looks like, you have to look at people that started from nothing today. These are the people that are making architecture decisions with an eye to the future, growth, and immediate productivity. When you're inside a huge org, you have to think about what is easiest to integrate with, and what skills you can get from other teams. At a company that's 80% Java, that's Java. It would be insane to switch, and likely to fail.
Sure, but Go has enabled a lot of great software in a very short amount of time. If you are in the cloud business, you'd better take a serious look at Go if you don't want to be out competed. It hits a sweet spot between performance and ease of use - feels almost like Python, performs almost like C++.
I feel like "Go has become the language of cloud infrastructure" is a bit of an inflammatory headline for this forum--I'm sure there are many cloud infrastructure components which aren't written in Go. The ones I think of tend to be AWS services that are written in Java or a handful of odds-and-ends things in Rust like AWS's Firecracker or some of CloudFlare's high performance networking systems. But especially in the open source world, there seems to be a lot of cloud infrastructure written in Go, and it seems to be accelerating. So in a sense I can understand saying "Go is the language of cloud infrastructure", but that framing seems unlikely to yield any interesting conversation.
> What about ALL the other components NOT written in Go?
Out of curiosity, which components are you thinking about?
> Out of curiosity, which components are you thinking about?
I could start listing off OS kernels, and then I'll move on to device drivers and hypervisors.
"The Cloud" is enabled by the fact we can efficiently separate applications and users running on the same hardware. The software which ultimately enables this is not written in Go... or Rust... or C++... or any other "hyped" language, but it is still an essential part of any cloud service.
Go is the language that made me realize I’m not much of a production quality software engineer.
Normally I would be quite happy riffing with ideas in Ruby or Python, and just running my code and iterating trying to figure out what to do.
When I tried this in Go, every time I wanted to change the shape of my code to try doing things slightly differently I had to do a lot of work to get the code to compile again.
I feel like a professional coder wouldn’t hit that road block because they’d have a better idea what they were doing in the first place.
I have scurried back to Ruby with my amateur tail between my legs, but I hope to try Go again some day and find a style that’s a bit more forgiving of my not-Staff-SWE skills.
Go is not the tool of choice for experienced professional programmers for exactly this reason.
The ability to quickly refactor code is very important and Go fails at it horribly for a number of reasons.
1) sheer verbosity.
2) multiple return makes altering function signatures tedious.
3) no generics mean code is written in hard to refactor styles out of the box
4) poor reflection support
5) poor tooling compared to professional grade languages (Java/C#/etc)
I could go on but long story short it's not you, it's the tool.
These issues can be overcome by remaining vigilant but for the most part they are part of the accepted "cost" of Go.
Which is to mean you pay them in return for a language that is very easy to learn (albeit hard to master because of the above problems), has a great runtime and has reasonable out of the box performance and memory footprint and stellar compile times.
These tradeoffs can actually be right for some teams, i.e larger ones with less experienced engineers that can afford to spend more cycles doing busy work refactorings.
However it's often a poor fit for small teams trying to work on software that is evolving quickly and can benefit from features of more powerful languages.
3) Would be true when comparing with pre-C++98, back when C++ compilers shipped pre-processor based macros for writing generic code, and used something like TObject as interface{}.
I had always thought the same thing about high use by aging out coders. Don't know how representative it is but the just released Go annual survey results seem to show that isn't the case.
In general good "experienced professional programmers" don't have one "tool of choice" but their tool of choice varies by what they're doing. I would choose Go for a lot of things, but not for everything.
Whilst I generally agree with this it's definitely the case that experience leads you to prefer certain tools over others even when they may both be usable for a specific task.
i.e Go is relatively well suited for a simplistic web service. But even if I don't expect to need to extend it I would still prefer to write it in something that is more extension friendly than Go.
Therein lies the problem. Go actually isn't better than other tools at most things so if you don't actually have a tool of choice than Go is rarely the best choice assuming you are comfortable with a large range of tools.
Building a database? C++/Rust (arguably JVM) are better choices.
Building a correctness critical piece of software? Rust/Haskell are likely better choices if this is your main constraint.
Building a big data pipeline? JVM language of choice is probably the clear winner because of sheer ecosystem momentum.
Building a large web application? JVM/C# are miles ahead of the competition here.
Building a bunch of microservices? This is probably one case where Go actually does reasonably well, if you work hard architecturally to constraint to complexity of each service it can do OK here. Unfortunately, just OK. JVM/C# probably still beat it out here because of better tooling.
Building a kernel? C/C++/Rust/D/Zig. GC is a non-starter.
Building a browser? See above.
Once again, I could go on. Go can be used for lots of these but all of the tools above are better for each of these domains. So if you are an experienced professional with a wide array of languages at your disposal what are you going to pick Go for?
I like the lack of enterprise layers that Java espouses, the simply deploys of a single binary, built in support for JSON and a perform at HTTP server. A code base that is accessible from the high level all the day to the fundamentals of the standard library. If I can’t find documentation, I can read Go code and grok it instantly. There is one style - gofmt style. Honestly, I rarely need genetics and I prefer the simplicity over over-engineered templates classes in Java and C++. If I need to do concurrency, it’s super simple and easier to get performant than Java or C++. Working with junior developers? They can learn Go in a week. Good luck with C++ and to a degree Java with the norm of relying on layers of Beans and XML frameworks.
If you consider all the trade-offs (performance / simplicity / security / etc), and you need to create robust RPC services, whether microservices or outward facing API frontends - Go (to me at least) will be the best choice considering all aspects (C++ may be faster but harder to write/debug in, Java more widely adopted but a nightmare in every other aspect, Python easier but slower and less stable, etc etc).
Think about successful tools use Go - they would have been a nightmare in some aspect in most other languages. Can you imagine Kubernetes in Java? Docker in Python? It shines where it shines for a reason.
> The ability to quickly refactor code is very important and Go fails at it horribly for a number of reasons. 1) sheer verbosity. 2) multiple return makes altering function signatures tedious. 3) no generics mean code is written in hard to refactor styles out of the box 4) poor reflection support 5) poor tooling compared to professional grade languages (Java/C#/etc)
1) there are worse languages in that category. some are even more widely used.
2) that doesn't make sense. return arguments are part of the argument list signature. either changing any argument makes this tedious, or none does. you indicated that only return ones do for some reason.
3) can't argue there. in the rare occasion that type asserting interfaces is required because of lack of generics, things really do suck.
4) can you elaborate on that?
5) only thing i found lacking was absence of advanced refactoring tools. for everything else, the available tooling seems to be on part with what i've used with java (anecdotal)
This helps but doesn't solve the core issues. I generally use Goland whenever editing Go code (as I am currently doing sigh) but even with such a powerful IDE the language is the main limiting factor in carrying out refactorings (which again, I'm doing right now).
Generally speaking, Go is one of the easiest languages to write with a simple text editor. Rust is among the hardest due to its complexity and demanding static analysis. This isn't a bad thing, and tools like rust-analyzer make writing Rust a lot easier. But rust-analyzer is amazing technology from the future; hardly an ordinary text editor plugin.
> Generally speaking, Go is one of the easiest languages to write with a simple text editor.
And one of the absolute dog's-breakfast worst to refactor regardless of editing environment. No statically typed language should be this hard to do basic changes in, and yet it exists.
Being writable in a "simple text editor" isn't a plus when the "simple text editors" in 2020 are IDEs with the name filed off.
The demanding static analysis and clear compiler errors actually make it easier and more robust to write unaided for me. Especially when it comes to refactoring -- it's essentially a process of resolving the compiler errors and you can be pretty confident you've arrived at a correct result.
Source: I write Rust everyday in a plain text editor without syntax highlighting.
> Go is one of the easiest languages to write with a simple text editor.
As long as you never refactor anything.
> Rust is among the hardest due to its complexity and demanding static analysis
I have never wanted or needed to offload Rust's "demanding static analysis" to my text editor. Rust's linearity/lifetime type system is really quite simple - it's not like you have to keep track of long-distance lifetime relationships in your head.
Even a reasonably powerful type system with e.g. HKTs, arithmetic, etc. like Haskell's rarely benefits from external tooling, and any interactivity can often be just as easily done via a polling build tool like ghcid rather than integrating it into a text editor.
The one place where it strikes me as sane to have a "smart" text editor is if you're using a proof assistant-style language like Coq/Idris/Isabelle/Liquid Haskell/etc. where there's actually a non-trivial amount of interactivity required while writing the code.
I am going to disagree pretty heavily with this. You don't give any explanations, evidence, or mention your experience, so let me lead with mine before I explain where I think you are wrong.
I cut my teeth in the 90s with C, and have professionally used PHP, Python, Java, C#, Javascript (both server and client side), and have been using Go as my main choice for the past 4 years. I've worked on teams as small as 1 up to teams in the hundreds, both as an individual contributor and tech lead. I say all that because I would consider myself an "experienced programmer". I am mostly writing APIs for web and mobile apps to communicate with, although I have written code in a wide variety of contexts. I say all of that because I can't imagine going back to Java or Python. I even migrated a bunch of my services from Typescript to Go because I found Go to be far more productive and easier to work with. Refactoring as always been easy. At my current job as a Chief Software Architect, I have over 25,000 lines of code in production running Go. I say all of that to provide background and context on my humble opinions.
1) Verbosity is among the leanest I have seen for a type-safe language. Compared to Java or C#, it is much more like Python. Perhaps the most verbose sections are a repetition of "if err != nil" blocks, but those are there for a reason and I explicitly prefer that over long "try catch" blocks.
2) Not sure what you are arguing here. If you are talking about functions returning multiple values, many languages do that. If you really don't want to, return a struct or a map. Or choose to not return multiple values. That is a choice of the programmer, if I understand you correctly. You could also use any of the major editors (I prefer VS Code) to refactor; the tooling is awesome (see #5)
3) Maybe it is due to the nature of what I do, but I have never once thought "man, I wish I had generics for this." I am sure there are some who genuinely need it, but I haven't run across that in my own experiences. I find that structs and interfaces have been everything I needed there, but again, my use case is on the server.
4) I haven't needed to use reflection either, so I have no comment here.
5) Hard disagree. GoLand (by Jetbrains) and VSCode are INCREDIBLY powerful. I will never go back to Eclipse or Visual Studio if I can avoid it. Go ships with tons of tools (formatters, linters, vetters, etc) and integrate with a ton of others (delve, etc). So your statement simply isn't true.
Your last statement is probably what drove my response. I was able to spin up a full API server incredibly quickly alone, and then with one other person, in a fresh startup with minimal issues. Rules and requirements were changing daily, so the code and business logic had to change. I can't imagine having to do that kind of work in Java (don't get me started on the deployment story here...). I would argue Go is a great fit for small teams. It is a small language with opinions, so programmers can focus on their use case.
Go isn't perfect, but it's my tool of choice. That's my two cents though.
Great to see an answer that provides context and reason for a language preference. By way of reflection on your answers:
1) This is hit and miss for me. I have to read Go code frequently: not every day or even week, and sometimes under incident pressure. It's less verbose than Java/C#/JavaScript, more verbose than Python/Ruby/Scala. But it's sufficiently verbose to require, for me, cognitive discipline to not skim (ie, "I've been skimming, need to go back up" awareness). So when I'm reading go I put my Java/C#/JavaScript hat on not my Python/Ruby/Scala hat. Not a big problem, but it was so, so close to being in the latter camp. For me then, its regularity claims are something of a wash such that I'd like to see some supporting empirical data or summation of anecdote that it does in fact optimise well here and make good engineering tradeoffs.
2) The problem (I think) is being being to skip by the returned values. It's better than return codes in C, but you're not absolutely required to handle them. I suspect trying to patch structured returns onto an algol-like is a dead end, and if we want structured returns, we want to use a language that really induces us to 'process it forward' eg via map/flatmap/case handling, rather than adding ceremony around if. I think Go made sensible and realistic choices here.
3) Lack of generics are a pain, but a pain for writers. Go does not optimise for that concern, except afaict for its core language creators who have escape valves. The conspiracy theorist in me says Go was wait and see on generics (and exceptions, and objects) as a function of when it was incepted, and may now reasonably conclude that generics are here to stay so the language will need to solve for them, but objects and exceptions were good holds. ie, I don't completely buy it required a decade to figure it out, but could buy it took a decade to observe generics are not going away.
4) In Go, this seems to be satisfied by codegen and templated YAML. I wonder if this is generational, in that the need for reflection might be lessened because of how work on cloud/virtualised systems happens (networked services handling data in and out, with regular deployments).
5) Agree. GoLand I find a great tool for reading and delving into programs, and VSCode is a fantastic 'every day carry' for code.
Most people that think C# is verbose haven't used modern C#. It's an excellent language and if I had to go back to MS world I wouldn't bad sad at all.
That said right now I get little opportunity to use it because it doesn't fit into the current ecosystems I am working in.
Shame because it really is a joy to program in, tooling is excellent async programming in C# -just works- which isn't the case in Rust, Java (or Kotlin) or anything comparable.
So while I don't get to use it often I hold C# in high regard.
Hm, not sure I agree with some of those criticisms:
1) I don't think Go is in the Java (pre 8) realm of verbosity, but I concede it's not as compact as say Python.
2) Technically you can write single return Go but idiomatic Go leans towards immutability so it's not recommended.
3) I've run into the lack of generics a few times, but personally haven't been too hampered by it. This is an entirely valid complaint, hopefully support will be added soon!
4) Some would argue this is a feature. ;)
5) This was more true a few years ago. Now with Go Modules for package management and VSCode + Go extension with full debugger freely available, tooling is much improved.
Liking Go has nothing to do with being a quality software engineer. Go itself is probably the least software engineering friendly language out there. The goal of a computer language is to express your thoughts and instructions into something a machine can understand. Full stop. Go is absolutely terrible at letting you the human express what you want the machine to do. It has compile time type checks, but then fails to provide the hatches needed to work with types sanely. It has the ability to call out to large bodies of C code, but not without significant costs. It compiles fast, which is good, because your going to write a lot more code to do the same things you'd do in other languages, even other compiled languages.
Yeah the type system is absolutely horrid. Just try to use any other type size than int, int64, float64 then you will be in a lot of pain casting every time you use them.
It's so silly for example that math.Min/Max only works on float64, it won't work with float32 without casting, or integers (although for ints is highly discouraged, because casting to float could cause you to get a different number, it is encouraged to just do if statement yourself)
It is a horrible language, only popular because it came from Google. It's biggest benefit was that it supposed to be easy to pick up, but it also demonstrates that the simplicity doesn't help at all with a significant code base, you still have to spend the same amount of time to learn it as in any other language.
> Go itself is probably the least software engineering friendly language out there
My experience with software engineering went from "the language (type system, grammar, syntax, etc) is super important!" to "the language is one of the least important considerations in choosing a language". The more important features are tooling and ecosystem.
I don't want to have to learn a new configuration language or imperative DSL just to add project dependencies or setup tests. I don't want to have to learn yet another documentation framework for generating documentation from code comments. I don't want to have to spend lots of time setting up CI/CD pipelines to build my source code and documentation packages and publish them to their respective repositories. I don't want to have to worry about whether my users or fellow developers have the right versions of dependencies or the runtime installed on their system. I don't want to have to make unmaintainable Dockerfiles because it's the only way to have performant builds in the happy path. I want to minimize time wasted during code review on comments about style or programming paradigms. Similarly I don't want to waste time waiting for code to compile.
If the language is type safe in 95% of cases, that's good enough--people still make lots of money writing lots of 100% untyped JS and Python and Clojure and so on--the extra 5% would be nice to have but I'm not going to trade tooling, ecosystem, and developer velocity for it.
Basically, as I become more experienced, I begin to understand the difference between programming and software engineering (my heart is in programming, but software engineering pays the bills). Go is a great language for software engineering, but most of its criticism seems to be directed at programming concerns.
Is it though? While tests in go are not terrible, to be a truly effective software engineer (vs just a programmer or dev) you want a very good test and documentation story, and there are languages out there with far, far, better tests and documentation primitives than Go.
I think the point is that Go gets like a 90% score in most categories. You can get languages that score 100% in performance or testing or documentation, but they tend to trade off 60+% in several other important categories.
Further, I contend that Go has excellent documentation primitives, notably that it doesn't have any sort of markup or documentation package management. I've never seen a better language in this regard.
Can you name a few? Genuine question. I've only really written a lot of tests in Python and Go, and I really dislike the python tests I've had to write. I don't think it's so much the language itself, but that python is so flexible with the mocking you can do that it enables code that is really tedious to test. With Go you have much more limited ability to mock things, so there are added constraints for code to be testable.
Similarly, with documentation, I really like that the godoc toolchain has resisted all the markup and annotation syntaxes that you see in Java. And I like that Go's convention of using a public URL as the module import path helps enable sites like godoc.org.
I find the language itself slightly more than mediocre. But I really like the toolchain and the restraint of the maintainers.
Testing wise, elixir is fantastic. I have a relatively large codebase where I run what are effectively full on simulations of the system in sharded-by-test partitions of state to verify correctness and robustness of the code. There are about 60 of those that run concurrently with the unit tests and the whole thing closes in 10 seconds.
Docs for elixir are pretty, too: here's a library that I wrote. The doc system is extensible enough that I could patch in docstrings from another language and also hyperlink (the </> buttons link to github) the GitHub code across languages (the `zig structs` section in the sidebar is autogenerated by parsing zig code) https://hexdocs.pm/zigler/Zigler.html
My joke is that you want to write documentation that's pretty and html-responsive enough that you can read it on the can between coding sprints.
> With Go you have much more limited ability to mock things, so there are added constraints for code to be testable.
I agree Go makes things more difficult to mock, but it's also the language I've used where it's easiest to avoid mocks and test the real thing. We have tests for REST and RPC services that... just make a service. There's relatively little boilerplate to make a gRPC or HTTP service with some basic expectations/fake data attached and just run your real client against that real fake server. ("Relatively" meaning, less than the equivalent mocks in Java, for a substantially more realistic test outcome.) And once you have this fake server, it's probably useful in multiple projects, while mock setup tends to be suite- or even case-specific.
Must be a matter of preference but this is exactly what I hate about godoc. I'd love to use markdown or any other structure, really. Just a wall of plain text is sometimes good, but most of the time bad idea for readability. And the idea of starting each godoc comment with function/variable name is terrible. YMMV.
I would entreat you to not be afraid of Golang. To be frank its adoption speaks to a desire to make software that does not require (or, often, benefit from "staff SWE" skills). Treat it as what it is, a jumped-up, terser, and in some ways gutted Java, and give it another go. It is designed, to a fault--and this is a little pejorative, I absolutely do not enjoy writing Golang because of it--to be not that hard.
This is my impression too. I was at Google when Golang v1 was released, and my friends and I were hobbyist language geeks and decided to play around with it.
We were....not fans. We were already in the habit of writing extremely clean and healthy code[1], and having a language hand-holding and hectoring us into doing things in its narrow, specific way was just too much of a hit to productivity. Now that I work in a C++ codebase full of very smart domain experts but light on engineering expertise, I can appreciate Go's value in certain circumstances, but if you're lucky enough to work with a talented and experienced engineering team, Go is a pain in the ass for anything but beginners.
[1] A habit I'm paradoxically trying to unlearn a little at my newer company, due to being on a different point on the short-term velocity/long-term health spectrum
This is largely where I'm at. I've never gotten paid to write C++, though I've written my share, and I went through Scala, Ruby, Kotlin, a little Elixir and a little Rust, and now almost exclusively TypeScript--and I just don't need what Golang wants to make me do to do a good job and to output high-quality code.
There's a software lifecycle. At the beginning of a software project, nobody knows anything about what to do, because (if the market niche isn't already filled) nobody has done it before. Python and Ruby are great for that. Then as the software grows up, the requirements become more well-known, and more people start using it, you need to transition to more maintainable code that runs more quickly. Go is ideal for companies in that growth stage - it runs fast, it's easy to communicate what the code does, it doesn't allow a lot of tricks that can trip up other developers, and it encourages relatively robust code. Once you get to the massive scale stage like Google you probably need to be in C++ anyway, but by definition growth companies are where a lot of the action is.
Speaking as a professional with 15 years of career in software engineering under his belt: don't be so hard on yourself.
I mean, I don't typically prototype or iterate on ideas in Typescript, either; I do that in Javascript, and reserve strong typing for when I know what I need to build, and it's just a matter of doing so in a way that's reliable, maintainable, and secure.
The point is that flexibility and strictness both have value, and it's more worth knowing which is more useful at a given point in a project's lifespan than trying to be dogmatic about one or the other.
Sorry, but I have to be honest: in my opinion most of the replies you got to this comment are extremely misleading.
As a user of Go and Ruby I can tell you that: Ruby is an awesome language, and there's nothing else that beats it at getting things done quickly and painlessly (unless you have a mathematical mindset, in which case nothing gets shorter and more elegant (at least the day you write it) than functional programming). It has many other defects, like safety in larger codebases, speed, some weird quirks, etc., but it's an awesome language, don't expect many other languages to be less painful than Ruby (on small programs at least).
Don't listen to those that say professional programmers won't use Go. The only reason a professional programmer will say hard no to Go is for extremely optimized or mission critical code that can't tolerate garbage collection (even though the GC in Go is very low latency) or need a more sophisticated type system, or numerical applications for which Go isn't really well suited.
If you compare Ruby and Python to Go, the transition might be hard if you haven't studied computer science formally. That said, it's a matter of making the switch, understanding that all those objects (boxes to put data in) that you had in Ruby, now are statically typed; this means that a box is of exactly one type and can't change midway (and even subtle changes need explicit casting/conversion). You also need to learn the difference between composition and inheritance, which might be tricky depending on how you learned to program... but beyond that, Go is a very small and easy-to-write-code-in language. You might like the syntax more or less, but it's easy to write good code in Go. It has many other gotchas and hoops you will need to jump through (var initialization, error handling, new vs make, weird append/len, learn to printf, learn pointers, etc), but it's a good step after Ruby / Python, if you need things bigger than what Ruby / Python allow you to comfortably manage.
A hello world might require defining a package, importing another package, and a more verbose print statement than python / ruby, but those are all great (and minimal) appliances when developing at a larger scale.
I felt the same way the first time I used go, but I came to realize that languages like go really force developers to think about details that languages like ruby don’t care as much about, like handling nil.
Sure, you can’t move quite as fast in go as you can in ruby, but you also get the benefit of not having to deal with errors like “undefined method foo for nil:NilClass” in production, which is nice.
Don't beat yourself up for that. I tried Go sometime back (year or so may be) and found it an awkward language. It probably has its own design philisophy may be that I missed.
Things like lack of generics and type system makes you repeat things quite a lot (e. g. It was pretty impossible to write a true ORM or a DI system in go). I found the interface system quite awkward in that types implicitly implement an interface if they have the same method signature was weird to me. I think method overloading wasn't supported either, if I remember correctly.
I think people who loved Go initially probably came from C. It feels a lot like C with better standard library, memory safety and fast compile times. I like Go for the same reasons actually. But until there's at least some way to write generic code, it's an awkward language to anyone coming from more expressive languages. I program in C# mostly which is an extremely expressive language with classes, interfaces, generics, expression trees, linq, delegates (akin to function pointers). Go is far behind other languages for application development, my two cents. But for systems programmers used to C which is a very small language, Go must be like a transition to paradise :)
I came from C++, where accidentally changing the wrong header file resulted in a 2 hour long build cycle.
No thanks. Modern C++ has its good parts, but Go has made me enjoy the profession again.
Interesting you said that. Recently, I started doing some work in C++ again to stay up to date with what's going on in the C++ world. Do you really feel it's not worth it? I'm thinking about something new to do, and C++ is what I picked. I started implementing a TUI email client.
The build time of C++ can be really long. I noticed it too.
I don't know, I guess it depends, what kind of software you are planning to write. All I can say is that learning C++ properly is a huge effort with diminishing results.
I'd say, invest your time wisely. Things are changing rapidly and old languages are usually solving problems that are not quite as important anymore as they used to be.
Thanks for the advice and i actually wxperience that diminiahing return you mentioned. I initially learnt programming with c++, so mostly picked it up again purely for nostalgic reasons to see where the language is now. It's become unmanageably large now! Where i live there isnt much work in C++, so job prospects are low for C++.
Im thinking of may be Rust or Go right now for more pragmatic reasons. Thank you for sharing your opinion.
this is a toxic mindset. just because the tooling is poor doesn't make you an amateur. if you're getting paid, you're doing great. keep it up and use the tools that work to get the job done.
"Guess and check" is a technique that I have also used in Go code, and it is fine.
A lot of the compiler errors really could be errors in pre-commit hooks (like, the one about unused variables), but the language designers made a trade-off to be Even More Opinionated (than, say, Rails) because they thought it was best from a pedagogical perspective.
I had an initial period where Go felt really difficult, coming from Python. Now I've adapted and I actually feel like refactoring things is easier than it was before coming to Go. Just the fact that arguments and their return values are more strictly defined helps a lot.
This is not that obvious, since many people are resisting it, but if you ever tried to use type annotations in Python, it dramatically improves refactoring (from my experience PyCharm it actually is more reliable than GoLand), you get autocompletion and bug detection. Highly recommend this for large Python projects.
I didn't like type annotations in Python, but I didn't like Go's type system either when I started. I'd be willing to take a second look at types in Python now. But, my real reason for choosing Go was for performance, and it blows our previous solution out of the water. Go isn't perfect but I'm pretty happy with it for right now. I still use Python for a lot of other things though.
Well, if performance is the objective, then I can't suggest Python, because that isn't the goal. You can still have a performant application implemented in Python, I for example had it encode video stream on the fly, but this of course is done through extensibility via C extensions and the core work wasn't really done in Python itself.
Sometimes with the right approach (mapping PostgreSQL calls 1:1) and right tooling (uvloop, Cython) you can write code in Python and still squeeze better performance than in Go[1], but you need to know what you're doing.
If you want to explore types, these resources[2][3] were useful for me.
I realize that with a lot of effort, Python can be performant or can be scaled. It was a pretty low-effort move to rewrite my Python service (which was pretty small) in Go and go from really poor performance to acceptable performance right away, and it only took me a short time. Also, I'm pretty good at Python but I'm not very knowledgeable about optimizing it for performance. I'd like to learn those tricks though.
> I had to do a lot of work to get the code to compile again.
That's fine, in most cases, writing python code, you find out that you fucked up when you run the script. Compiler errors catch whole classes of errors that you ordinarily wouldn't find unless you ran the code.
My experience was that I would have an idea for a new model and change my code. Later on I would find that new model would be flawed, but only after fixing compiler type errors in many different places when all I really needed to find was that one error that showed my model was flawed.
I should add that it’s heartening Pike actually acknowledges this in the interview, regarding limited typing and how it helps playfulness in languages like Python and Ruby.
I'm Python you can also define types in the annotations, and with IDE that understands them it will catch errors, have working autocomplete and make it very easy to refactor.
One of Go's downsides (imho) - immature tooling (lagging ide support especially compared to other languages), definitely makes your job harder as a software engineer. That is not a reflection on you or your quality. If it feels like it is getting in the way - it is okay to prefer other languages or platforms to express and codify your ideas. The languages don't define you :)
> When I tried this in Go, every time I wanted to change the shape of my code to try doing things slightly differently I had to do a lot of work to get the code to compile again.
Ha. Try Rust if you like a challenge: at least you will get outstanding compiler diagnostics while refactoring, and far better performance as an end result.
Having done a fair bit of work in both languages I find Rust's type system here is much more of a help. I've got a clear sense of where things have gone sideways in Rust, even if that clear sense can sometimes feel like a long hike to get through. Go leaves me constantly wondering if I remembered to implement all the right functions for this or that interface, among concerns put elsewhere in this thread by others.
Don't confuse the shortcomings of the tools you use with your intellectual limits. This is a very insidious philosophy and there is no good reason to internalize it. Always remember that tools must be subservient to user needs because they're tools.
I consider myself able to write production quality code.
When I started with Go I thought it was awesome. As my projects grew I found them to become less maintainable than my previous Java projects, and still less maintainable than my newer Rust projects.
Agreed, for creative coding endeavours other languages are better suited, especially when doing rapid prototyping and refacturing. Sometimes even simple bash scripting allows for quicker results.
Cloudflare, Cloudstrike, Uber and Dropbox are 4 public companies that I know use Go pretty heavily. And there plenty more startups using Go. In VC-backed startup land, I'm pretty sure Go has higher penetration than C# or PHP.
Yes, we (Cloudflare) use much more Go than Rust. But we do use a lot of both. There are teams that work exclusively in either language, there are teams that do none, and there are teams that do both.
(My team actually uses Go, and almost ended up using some Rust, but decided in the end not to, for good reasons.)
Contrary to what you'll hear a lot of folks say on the internet, there are use cases where Go and Rust overlap. My team has a lot of experience in Go, but not much in Rust. It would be useful to gain some experience, as Rust is growing in the org, and we may need to contribute to some Rust codebases in the future.
We needed to start a new service, and there was an initial prototype of the beginning of that written in Rust. Then, the pandemic happened. This means priorities shift. It makes more sense to not try to learn new things while trying to ship new things when there's so many other things going on. Additionally, it was going to be a bit harder to do it in Rust because there were already some useful code lying around in Go for some things that we'd have to port.
I am a PM these days so I have no real bearing on these decisions, but I support my team in their choices, and told them that I would no matter what. I obviously love Rust, but it's not the end-all be-all of languages, and I think the right call was probably made.
What people want to know is the trajectory of current relationship that a company has with a technology, otherwise I'll tell you that Facebook is a Haskell company and Amazon is a TLA+ company.
I know people in at least one of the companies you mentioned, and things look very different on the inside. They succeeded despite of the language, not because of it.
Surely, "it is not because of", every language is ok. But experienced programmers will choose the most suitable (most efficient, either in runtime performance and development speed/quality) one they think.
Their switch from Python to Go was pretty well documented on their engineering blog, but I can't find it, other than comments on HN like the one above.
Sounds like they are driven by what's fashionable. They were very aggressive about node.js to the point that they refused anything that was't in node.js) before that.
This sounds like him trying to do PR to get everyone thinking everyone else is already doing it so they try to catch up. Act like something is true to make it true when everyone jumps on the bandwagon.
I disagree. I've noticed that a lot of infra tools that would have been written in Python 5 years ago are now in Go.
I know Docker is written in Go, and I believe the Kubernetes ecosystem uses it heavily, so those are compelling evidence for Pike's argument by themselves.
These tend to be applications with very high performance requirements, including Deno. It seems to me that the choice between Go and Rust is generally a matter of whether you value iteration velocity more than peak performance or correctness.
It is true that the k8s project uses many Java patterns, and this really hurts the readability, but there are also many leaf great packages in Go style in the code base.
At least, I think, k8s proves the ability of Go runtime.
A few fellow OpenStack developers and I half-jokingly suggested we rewrite some or all the services in Go. Python gets to be a bit hard to deal with at that scale.
I used to work at an Openstack shop (small public cloud)
We considered this several times, very much not-jokingly.
Ultimately the investments never came.
At least for Swift the object-server was re-written in go as an alternative implementation.
Heh ours started out as "We should rewrite Nova and Neutron and then Ironic..." That's awesome that Swift was. I always felt like Swift was one of the more solid services, but maybe that's because I rarely had to deal with it.
We actually did write and deploy a small Go rescue agent for bare metal machines in Ironic. I'm not sure if that every got upstreamed though.
Reasonably high. There is a good deal of frustration with Go from experienced programmers that worked with it for several years and grew tired of the tedium involved.
Rust has some obstacles to overcome to supplant Go on a wider scale though. Namely compile time and learning curve - especially in relation to concurrency and async which are key features to replacing Go as it's main draw is it's green runtime.
I'm not seeing that. It seems like there's lots of enthusiasm to use Rust, but that people can't justify choosing it over Go probably because Rust is quite a lot more tedious than Go and its strong performance and correctness guarantees aren't worth the tradeoff for very many applications. I'm hopeful that things like rust-analyzer will help close that gap, but I don't think it will ever completely close much less reverse.
This is true. It's worth remembering why Go got it's shot though which is at the time of Docker being written it was originally written in Python. A few members of the container/orchestration community pushed to try writing it in Golang as Golang was also new and combining the enthusiasm of 2 communities was likely to result in greater success (turned out to be correct).
On the other hand Rust hasn't had an oportunity for a killer app, in fact it's main sponsor project Servo/Firefox is pretty much the opposite. It's a browser, the definition of a complex and slow moving behemoth of a project.
I attribute Rust's slow takeoff compared to Go mostly to this phenomenon.
After Docker was written in Go and started popularising containers outside of the lxc/openvz/other hardcore guys doing their own stuff directly on top of the kernel APIs then it was only natural that stuff would want to integrate with Docker and using the same language was a way to capture some of that enthusiasm. This resulted in software like Flynn, Deis and Kubernetes all picking Golang. The resulting network effect is very strong.
To some degree this is also down to the strength of the Go standard library. It has an excellent HTTP and TLS stack, encoding/decoding etc. All of this made it a good fit to write software that is fundamentally fairly "dumb" quite quickly. i.e software the mostly shuffles bytes from one socket to another.
Rust will most likely not find such a killer app so I think people need to be realistic about how long it will take Rust to find a marketshare. The big difference though is one can actually make good arguments to use Rust over C/C++ where you can't in most cases for Go. C is the largest software ecosystem right now and Rust is best positioned to take some of this market share away.
Rust's killer app will come from OS vendors support, like Microsoft and ironically Google (Fuschia and Crostini).
However while I like Rust, it seems that it will become more of a C++ companion than a replacement, as it will take quite some time to get a foothold on systems where C++ is finally replacing C as of the last decade.
Go has no expressiveness to it. You end up either with a large pile of copy pasted code, code generators, or massively error prone runtime introspection. Go blows up the entire idea of Don't Repeat Yourself. The language actively encourages it.
> Go blows up the entire idea of Don't Repeat Yourself.
Yes, this is true. I programm in Go professionally, about 50% of my work time (other half is python). But in many cases, I have found that copying the same code to other places doesn't have that much negative consequences as one would believe.
Refactoring becomes intensely burdensome, often to the point that it is avoided at all costs. Not a great situation when you need to iterate on a design.
So I'm almost certainly in a different industry (embedded) where EEs tend to prolifically copy+paste code. In the end this always makes it so that a change that should take very little time consumes an entire workweek or more. So I have a seething hatred of this practice from past experiences.
I suppose I should say that there's a lot of different types of duplicate code, some of which really don't matter per se. Sometimes two bits of code are basically the same but are completely unrelated and as things change they will diverge, i.e. it was just incidental. Code that is duplicated with a strong functional relationship make changes a nightmare though.
Rust does not have a comprehensive story for CSP concurrency like Go has. It does have a fair share of libraries/ecosystems (like Tokio), but not having something built in means that you have to hunt for the right set of libraries to work together. Meanwhile, in Go, every single library will just work with its concurrency model out of the box.
I write in Go daily and I've been ramping up on Rust. While CSP isn't built into the language, Crossbeam, Flume, and others are more than enough to fill the gap.
If anything, I find Rust returns flexibility to me in programming choice that Go made me forget I had. There are places where library support in Go is still richer, but language support has been stellar across the board in Rust.
I write Go daily, and I don't think CSP really panned out. For most applications, I find it's much easier to use a mutex and standard threading tooling than channels/CSP. That might be an artifact of how channels are implemented and their many hidden error cases--perhaps a better channel implementation could change the calculus. There are lots of reasons to prefer Go to Rust IMO, but I don't think CSP is among them.
That has not been my experience with CSP via Go channels after 8 years of solid use (I still use channels here and there, but not in a CSP pattern). Different strokes, I suppose.
The fight is not technical but political / business-oriented.
Each language is a much more than its syntax. It is a complete ecosystem with network effects.
Rust can overcome go, if it would provide a lot of open source libraries, as well as growing number of programmers.
To do that, it would need the backing of big tech (e.g. MS), that have a big budget to evangelize it.
In any rate, the choice of language today is completely meaningless, since you can wrap anything in a container, and put a GRPC interface on top of it.
So the choice of lang should be based on the libraries for the task at hand and not on the lang itself.
For platform stuff that has speed and correctness as the highest priority? Absolutely. Things like http proxies, message queues, shared infrastructure makes sense to be done in Rust.
For writing a normal networked http/rpc/event stream service Go is probably more than good enough. It’s not a winner-take-all market.
A great example imo is Buoyant’s Linkerd. Rust dataplane proxy as well as a control plane written in Go. Two different requirements for each of those services drove the language requirements
Just take the time to learn it, it's really trivial once you take the time to learn the basic types. You have lists, dictionaries (maps), and primitives. It could not be easier.
I think the real problem is that yaml encourages you to make things declarative (which is 99% of the time a good thing) but sometimes hiding complexity is the wrong thing, and so when you have clashing declarations, the imperative resolution path is not necessarily explicit, and hidden behind an operations layer that you can't really see or reason about.
For some reason YAML seems to be an attractive option to try to implement things that really should be imperative in a declarative sense. Other configuration languages are either semi-imperative (like the hashicorp stuff) or don't do that (I haven't seen TOML configs that do some of the thing that YAML does). My best guess is it's purely cultural, because that trend started with ansible, which, not to denigrate - in many ways did very good things.
The trouble is that 1% of the time always hits at a very inopportune time.
Markup languages are by their nature declarative. Take HTML, for example. You're providing a set of instructions for some other, smarter program to create some output based on your declarative input.
YAML is no different. You encode some configuration, something else makes it so.
Ansible kind of muddied things up because it looks like you're doing imperative things in YAML, but actually, you're doing declarative things and Ansible is interpreting your YAML in some particular way.
It's funny how everything that bell labs alums have touched has influenced computing in a way that isn't publicly acked and how the network and namespace ideas in plan9 and inferno have become foundational to cloud native infra. Pikes assertions in a couple cases are just wrong or exemplify naivete however. He is surprised by how a language designed to be opaque to casual examination, statically compiled and used in a majority of high profile cloud native applications (where the install is often download and run a go binary as part of an un-examined curl | sh pipeline) is happily used for malware? Also interesting how designers of languages who are formerly avid critics of PL become reticent and opposed to negativity as authors. Finally he touts the 'hard' problem of concurrency that GO offers an unanticipated solution for as if OpenMP hasn't been around as a functional approach since 98 for concurrent programming in the HPC and scientific domains.
> a language designed to be opaque to casual examination
Is this really the case? I thought the prevailing wisdom is that Go was designed to be as simple as possible so newbs can pick it up faster. I find Go to be quite easy to read and follow along with even though I've never written a line of it. Rust on the other hand...
opaque to casual examination means that you simply cannot read the code. You would think that a statically compiled binary blob wouldn't be handled as if it was a perl script, but it is.
I have huge respect for Rob Pike but there's a bit of revisionist history going on here.
Go was originally envisioned as a systems programming language. It was often called "a better C". This exposed Rob Pike's lack of experience in the area (IMHO) because anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter.
Where Go succeeded was completely unintentional (as as often the case): it was (and is, IMHO) a better Python. Go hasn't attracted C, C++ or even Java programmers. It attracted Python refugees. So it's no accident the touted use cases ("cloud infrastructure") are orchestration problems.
But at the same time, "cloud infrastructure" here refers to what, exactly? Kubernetes? Etcd? I think those could've been written in anything. More to the point, users of those don't really use Go as a result, right?
I think even Google found that internally Go was cannibalizing Python usage and little else.
Lots of Go newbies bemoan the lack of generics. I was never one of them. It's not the problem people think it is (IMHO). I'll be interested to see what this solution is even if simply means we can stop having having this conversation about Go not having generics. That alone is a win.
So I think there's two areas where Go screwed up. two big and one small.
The small one is the lack of IDE support. You don't need to write an IDE. You just need to have sufficient integration into Jetbrains IDEs (at a minimum).
The first big problem--and it still is a problem--is the dependency management, in that there wasn't a solution to this out of the gate (unlike, say, Rust and Crate). Like I was shocked the first time I saw import 'github.com/some_random_user/...' I dare you to go look at any even moderately sized Go project and unravel the levels of dependencies (including repeated dependencies, which may or may not impact binary size, I'm not sure). It's kind of a mess.
The second is, oddly, on concurrency or rather multi-core and multi-CPU utilization. Aren't we still in the GOMAXPROCS environment variable era? Really?
EDIT: adding this quote from Rob Pike in 2012 [1] as it's a first-hand account of Go's original design goals:
> I was asked a few weeks ago, "What was the biggest surprise you encountered rolling out Go?" I knew the answer instantly: Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++.
> Go was originally envisioned as a systems programming language. It was often called "a better C". This exposed Rob Pike's lack of experience in the area (IMHO) because anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter.
Yeah, Rob Pike and Brian Kernighan definitely lacked experience in C and systems programming.
If you didn't know you should have clarified before making such sweeping statements. Who knew writing an OS would count as systems programming experience.
"writing an OS" is a sweeping, unsupported and inaccurate statement. You can be involved in Linux and, say, write the ext4 filesystem or Wifi drivers. Those are pretty low-level. You could also write shell utilities like ls in probably anything where you're just using OS APIs. Is that low-level? I would say not.
My friend, my comrade in arms, I have a link[1] for you. If you read only one of these papers, then please just read the first one, but please note the author credits on almost all of them.
Oh my god. Can you at least do your research now ? They wrote the core bits and not just userspace utils. Did you read what they wrote before blustering here ?
Mostly systems programming. In particular, he wrote its graphics system, then rewrote it, then rewrote it again. He led Plan 9 for many years. So, he has plenty of experience in systems programming.
What he seems to lack IMHO is sufficient curiosity about computing innovations not produced by him or the prestigious institutions he has worked for (Bell Labs, Google).
There's multiple levels of experience. Someone can get really good at the technical solutions without learning what the human problems are and how to solve them.
For example, someone might dismiss IDEs as being unnecessary because technically the same job can be done without them by a superior human being, so the solution is to just be a superior human being.
Or as another example, someone could completely dismiss syntax highlighting as being useless for the superior, implying that the solution to the problem syntax highlighting solves is to just also become a superior human being.
There are multiple layers to any solution, and if one of them is missing, the others are kind of shaken out of balance.
Apart from UTF-8, the piece of software he designed I used most was the sam text editor. An opinionated and rather quirky design, with some internals that made quite enthralling reading for me at the time: http://doc.cat-v.org/plan_9/4th_edition/papers/sam/
It's an interesting editor, especially the split between the editor itself and the graphical frontend. That split has helped me work on some very limited systems, thanks to `sam -r`.
Personally, I prefer acme; it's my daily driver editor.
If having worked in UNIX, Plan 9 and Inferno (and saying "having worked" is quite an understatement), having designed and implemented several programming languages (Alef, Squeak, Limbo, Sawzall, Go, ...), and having been an important part of Bell Labs and Google during their respective peaks is considered lack of experience in systems programming, what on earth would you consider as enough experience?
Go was always intended for writing the type of networked application servers that are common in Google's infrastructure. [I was at Google when it was released - I thought you were too?]
It's succeeded at basically the same niche that it was intended for. The difference, as another commenter points out, is Rob Pike's ignorance of how the world outside of Bell Labs & Google had changed. In the 80s you would've built networked microservices in C. In the 2010s you built them in Python or Node.JS. Hence if you have a new language that's a success in the microservice application-server market, it will end up cannibalizing Python and Node.JS, not C. Python cannibalized Java in the 2010s and late 00s, and Java cannibalized C in the 2000s and late 90s.
Go is still inferior to Python in prototyping, in web development, and in data-science. (I used it for the former 2 while still at Google, and decided it wasn't an upgrade.) But it's superior for production microservices, and that's an increasingly large market these days.
> Go was always intended for writing the type of networked application servers that are common in Google's infrastructure. [I was at Google when it was released - I thought you were too?]
I was (2010-2017 to be exact) so I remember how this was communicated but internally and externally. This HN submission [1] to HN from 2011 reflects my recollection of that messaging that Go was a better C.
Even better, Rob in his own words [2]:
> I was asked a few weeks ago, "What was the biggest surprise you encountered rolling out Go?" I knew the answer instantly: Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++.
> Go is still inferior to Python in prototyping, in web development, and in data-science
On the data science point, I certainly agree that nothing looks likely to displace numpy/scipy anytime soon. Python's much-maligned GIL does simplify C module extensions and, I believe, was a key contributor in Facebook choosing to move to Mercurial many years ago (long before my time).
I wrote a fairly significant internal app at Google in Python and essentially swore I'd never do it again. The way I like to put it is that I don't want to write unit tests for spelling mistakes. I haven't used Go for Web development but I'd already choose it over Python just for static typing.
As an aside, I found the protobuf integration in Python to be basically terrible. Perhaps it's improved in the last 7+ years though.
> garbage collection made any systems language a nonstarter.
Unless you want to bucket all systsme programming in to one bucket, I will say this
#1 If your goal is to make the most efficient and fast code (garbage collected or not), it is not clear gc-less languages are always better. Sometimes, not free-ing the memory at the first possible time will actually be good for you overall.
#2 If you are writing anything with serious mem usage in Go, you will optimize for allocations using sync.Pool or some other form of reuse. I am sure well written C++ code would have to do the same tricks. reduce >> reuse >> recycle. Both GC and free() are recyclers. Sure, one could argue GC could provide more control.
I 100% agree there are cases C/C++ or Rust would be better for 20% of the trickier situation, but let us not base it all on the presence of garbage collector.
Heck, some of my Java code works faster than even my Go code. I don't blame Java for having a garbage collector.
> #1 If your goal is to make the most efficient and fast code (garbage collected or not), it is not clear gc-less languages are always better. Sometimes, not free-ing the memory at the first possible time will actually be good for you overall.
Which is why languages like C++ let you write and use your own allocators. There are lots of reasons to do this (eg word alignment).
And while I agree that it's certainly possible that delayed freeing may be beneficial I'm not convinced it's a problem in practice, at least when you compare it to how often common GC problems are (eg memory leaking (admittedly also a problem with manual allocation), out-of-control process memory growth and STW pauses).
#2 If you are writing anything with serious mem usage in Go, you will optimize for allocations using sync.Pool or some other form of reuse.
True, and I mentioned this in another comment: the idea that you can get around many GC issues by using object and memory pools.
> Heck, some of my Java code works faster than even my Go code.
Why should that be surprising? The JVM at this point has >25 years of engineering effort into it and (IMHO) it doesn't get half the credit it deserves from the devotees of the latest flavour of the month.
> Go was originally envisioned as a systems programming language. It was often called "a better C". This exposed Rob Pike's lack of experience in the area (IMHO) because anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter.
You don't know what you are talking about. Someone who has written operating systems, windowing systems, editors, many many tools & library functions, and well regarded books on programming doesn't exactly lack systems programming experience.
"anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter."
This is quite funny.
I remember when Go was released its creators were all like "GC is good enough now" and then Rust came around the corner blowing that whole premise out of the window.
Rust used to be a GC-based language too - very similar to Go in fact. They didn't abandon GC until sometime prior to the 1.0 release, well after Go first came out.
Early on Rust had optional GC boxing before it morphed into Rc/Arc, it never required GC of heap allocated objects like Go/Java/C# et al. Deterministic resource management has always been the default with Rust.
I guess every language has its devotees. Go is no exception. My own personal experience with talking to more than a few of these people were that they tended to be a bit... naive and overly optimistic, which is fine, but often the lessons of history were ignored.
The way I like to put it is Go devotees operate under 2 rules:
1. Whatever your complaint about Go is, it's totally not a problem (eg stop-the-world GC pauses, a longstanding issue that any experienced Java engineer could commiserate at length about);
2. Even if it is a problem--which remember it is not--it's totally fixed in Go 1.(N+1) where 1.N is the current version.
This comment is transparently trying to incite a flame war, but I'll try to take it on a more productive tangent.
> eg stop-the-world GC pauses, a longstanding issue that any experienced Java engineer could commiserate at length about
This is a really interesting example, because it shows the lack of nuance in the anti-GC position. By your logic, because Java's 100ms GC pause times have been problematic (and yes, I'm aware that Java's upcoming GC will boast significantly improved pause times and that it's theoretically possible to tune a Java GC for low pause times even if no one has managed it in production) Go's 5us pause times will be equally problematic. Because a pause is a pause, right--why should we muddy the waters with considerations like "duration"?
Single- or double-digit microsecond pause times completely change the conventional wisdom about the kinds of applications GC is suitable for. There are still lots of hard real time applications that Go's GC won't be suited for, but there are many soft real time applications for which Go would be fine (or at least the issues will be libraries or support for target architecture/platform and not GC).
> This is a really interesting example, because it shows the lack of nuance in the anti-GC position.
I wouldn't call my position strictly anti-GC. I would simply say that GC isn't the panacea it's made out to be and it is at least in part a false economy for at least three reasons:
1. You may need to tune your VM/GC parameters (as you mention). There's a cost to this;
2. GC can make it harder to identify memory leaks (which are still a problem through, for example, dangling references). I've worked on C++ systems where we instrumented many things including process size, which was basically just a flat line. As soon as it wasn't, you knew there was a problem. And this was for a server that read about ~6GB/second off a NIC.
3. Crashing a program due to accessing unallocated memory tends to give a more immediate signal of a problem, which is more often than not better for development.
My experience at CERN ATLAS HLT means that those C++ processes would also have a highly tuned custom multithreaded memory allocator, malloc() and new aren't even in the game to start with, and most likely one is doing a custom protocol at IP level.
Well, my personal experience with C++ developers is, that they are a bit ...naive and overly optimistic, when it comes to taking a look at the real world, with real deadlines. "I just write my own half assed string class" comes to mind... As if they are developing in a vacuum, with no competition out there. This really pisses me off.
And in my opinion, it is a better Java. It succeeds in the niche where Java is used today: big softwares, shared by numbers of teams, working on different timezones and in different languages, and with varying degrees of skill.
Go is so stubborn it takes the fun out of programming and ironically that's a good thing: when code can't be tied to anything personal, it is much more easily shared with anyone who works on it. I have found that writing Go itself is definitely tedious, sometimes boring, and the fun is not there; _however_, fun is had when you have a working binary that is statically compiled, reasonably devoid of bugs and surprisingly performant. You take joy in actually using pieces of software, not in fine-tuning your formatting rules.
The language itself is boring, but it's the same boring for everyone and it happens to be working well so you tend to focus more on the solution than on the intricacies. This, IMO, is the success of Go
Better as a tool, not as a language. By being uninteresting it removes focus on itself so we can better focus on what also matters: designing, measuring, documenting, fixing what is not code nor software
> Go was originally envisioned as a systems programming language. It was often called "a better C". This exposed Rob Pike's lack of experience in the area (IMHO) because anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter.
I've said this before, but even back in early 2014 Rob Pike had said that he regretted the term "systems programming" because people misunderstood him to mean it as a language for writing operating systems, when what he meant was a language for writing servers, although that later evolved to cloud infrastructure.
> This exposed Rob Pike's lack of experience in the area (IMHO) because anyone who had done any systems programming at all knew that garbage collection made any systems language a nonstarter.
What exactly do you mean by systems programming? Many successful databases (Cassandra, Kafka, ElasticSearch) are built on the JVM.
Many people consider "systems programming" to be close to the hardware stuff that is not visible by users. Userland code would generally not fall into this category, with the weird proviso that some OSs put a lot of GUI code into the kernel (cough windows cough). In this traditional classification, a database is considered an "app". The "find" command is an app. People log in and use the DB and the find command. The Bash shell would be an app. If a user is using it, it's an app.
If it is not user visible but exists to manage app access to hardware resources, it's a system. So a memory management system would not be an app. Neither would power management or IO or a scheduler. But these systems might have administrative apps that admins login and use (like Microsoft's "Control Panel" app -- to control settings for the system code. Similarly some apps might have their own memory management system. But the principle still applies.
I understand there is definition creep as more and more layers sit between the user and the hardware, so todays application code might, in some cases, be viewed as tomorrow's system code, but this is the original meaning.
> I have huge respect for Rob Pike but there's a bit of revisionist history going on here.
> Go was originally envisioned as a systems programming language.
Already with the release of Go 1 it was quite clear that Go has its best fit as a Server language. I don't think the usage of a language can really be planned. But looking at the previous works of the language authors, it's clear that they worked on solutions for distributed systems.
Also I think like 10 years ago people would have written stuff in C++ that today nobody would even remotely consider writing in it.
"Systems programming" isn't limited to OS kernels. I'd call, say, the Coreutils programs "systems programming." But it'd make perfect sense to implement those (or things like them) in Go†. And that's the niche I see a lot of modern Go software addressing, too: simple new OS-packagable CLI utilities, able to be written with less gotchas than if they were written in C.
† I say this because we already have an alternative to GNU Coreutils for memory-constrained embedded systems, in the form of Busybox. If Coreutils had to "serve two masters"—be both powerful at scale on big multi-core systems, and functional on tiny embedded boxes—then Go would make less sense. (Rust would be pretty good for that, though. See e.g. ripgrep.)
There is 'kernel device driver' kind of systems, and there is 'kubernetes module' kind of systems. Most of the modern infrastructure work happens for the latter use-case. GC is a very reasonable choice, provided you know what you're doing.
I agree that the term "systems programming" is getting stretched a bit thin. Maybe we need a new term for the k8s variety - I propose "infrastructure programming".
> More to the point, users of [Kubernetes] don't really use Go as a result, right?
Yeah, they do actually. The vast majority of tooling in the Kubernetes space is also written in Go. I don't know about etcd.
> The small one is the lack of IDE support. You don't need to write an IDE. You just need to have sufficient integration into Jetbrains IDEs (at a minimum).
I might be missing what you're saying here, but Goland has been around for a decent while now, and the full IntelliJ plugin has as well. Before that, Atom or vi with some plugs I've since forgotten the name of worked well enough.
I agree with your overall points though, especially on dependency management.
> I might be missing what you're saying here, but Goland has been around for a decent while now, and the full IntelliJ plugin has as well.
Right. That's true now (and, like you say, has been for some times) but was not the case for years. I was responding to this point in the interview talking about initial development, not the current state of the world, just to clarify.
Yep, that makes more sense. I was a vimgo user before Goland was available, and I found it to be good enough, but it definitely wasn't something that would attract new users.
I’m not sure whether this is the same level of big problem but I wish that they’d taken C’s other major failure more seriously and required error handling. Every Go-based tool that I use has at some point failed because an error was ignored. That necessarily doesn’t mean exceptions — simply having the compiler fail like it does for an unused import for every case where an error is assigned but not subsequently accessed would be sufficient.
My take on the "systems programming" comment Rob made, it wasn't meant as "kernel" level systems programming, but more server-side systems. When he started working on Go, it was done out of his annoyance with C++ on the very large project he worked on at Google.
> The small one is the lack of IDE support. You don't need to write an IDE. You just need to have sufficient integration into Jetbrains IDEs (at a minimum).
Visual Studio Code with the Go extension is very good.
So I wanted to find a good source for this and interestingly came across this article from 2011, titled "Go to C: Could Go Replace C?" [1] (HN submission [2]) and this point came up even then [3].
I also found there are subsets of Go aimed at filling this use case because of the GC issue [4] (eg Emgo [5], TinyGo [6]).
The Fuchsia Language Policy [7] also points to this. Fun fact: the networking stack in Fuchsia was written in Go because of Dave Crawshaw, who was (and I assume still is) a big Go advocate. I got into an argument with him once about stop-the-world GC pauses in Go. Anyway, the Fuchsia project has largely been unhappy with this ever since because there is an overhead to using Go that essentially you can't get rid of. Using memory and object pools can solve many but not all problems. And at some point I suspect they'll replace the networking stack with something not written in Go.
So there's some conflict, but mainly the problem is that GC is a critical problem in real-time systems that cannot have performance interrupts. Languages for these applications need to be able to bypass GC.
Single deployment binary, static typing, gofmt, and takes "there should be one and only one obvious way to do it" even farther than Python. It's very easy for new team members to ramp up on a Go codebase - formatting is standardized, libraries are standardized, and the language encourages very simple readable constructs (at the expense of brevity and abstraction, sometimes). That makes it attractive for companies in their growth stage, where you're working in teams but still have constraints on fast execution (CPU) and fast execution (developer velocity).
IMHO Go is still inferior to Python for solo-developer projects.
My personal view is that dynamically typed languages are largely falling out of favour with Javascript being the one glaring exception (and even there if I were starting a project today I'd use Typescript).
On the single deployment binary issue, let me just underline that point with one word: virtualenv.
I'm a python user and parallelism and performance are not the reason I tried Golang because I had no poblem with these for my use cases. However, it solves the only problem I have with Python which is deployement/distribution: basically your server can be a single binary. Best of all, you can target whatever platform with ease. You don't have to worry about your client having the right python or the needed dependencies and this comes with no effort on your part.
Given that the language is relatively easy to grasp and that the standard library covers all the basic needs of a server application, that alone is a huge win.
Python still has more and better libraries for certain tasks though.
I haven't switched from Python to Go, but I program heavily in both languages and can offer an additional point here:
Go makes it easy to produce binaries for any target platform that execute without requiring a working Go installation.
This ease of packaging makes Go my default language when I'm writing developer tooling - for example, if I know that team-mates are going to have to run tools that I write but I don't want to make assumptions about their development environments.
There is one caveat: This only works well if you avoid platform-specific functionality (e.g. syscall package) and CGO.
> The small one is the lack of IDE support. You don't need to write an IDE. You just need to have sufficient integration into Jetbrains IDEs (at a minimum).
Jetbrains wrote their own Go IDE, goland. The rest of us use an LSP client that talks to gopls. I have used that for about a year and it does everything that I would want an IDE to do; accurate context-sensitive completion, an easy way to peek at signatures and documentation, jump to definition, accurate renames, import organization/cleaning, etc. I am continually surprised at how good a job it does when I'm 8 nested protos deep and it can still complete struct keys and values (i.e. you can type "&Foo{ B" and it will complete it to "&Foo{ Bar: &Bar{}").
> The first big problem--and it still is a problem--is the dependency management, in that there wasn't a solution to this out of the gate (unlike, say, Rust and Crate). Like I was shocked the first time I saw import 'github.com/some_random_user/...' I dare you to go look at any even moderately sized Go project and unravel the levels of dependencies (including repeated dependencies, which may or may not impact binary size, I'm not sure).
I am pretty happy with go's approach to dependency management in the Go module era. You can tell the Internet "a little duplication is better than a little dependency," which Go does, but they will do it anyway. I like that I have tools that can just vendor all my dependencies (mostly so that CI builds can be completely stateless and free from network communication), and that every module I use is declared in go.mod file that the toolchain itself keeps tidy and accurate. The mechanics of an upgrade are a breeze -- find the module and update the version number next to it. If I want to edit some module I depend on, I can just use gohack and it checks out the source code in a convenient location and edits go.mod to make go pick up that version of the code instead of the Internet's version. And, you can at least figure out why you have a certain dependency with "go mod why". Finally, I love that "go doc xxx.Foo" is aware of what modules my module uses, so that I always get the right symbol. I would kill for "typescript doc xxx" or "clang doc yyy". (Seems like other people prefer 80 browser tabs with random websites loaded to do the same thing. I like my command-line, or at least some IDE integration.)
I have used other approaches to dependency management and they haven't made me as happy as Go's. npm is slow and fills my entire screen with garbage, only to eventually inform me that "module A depends on module B which depends on module C which has a SEVERE SECURITY VULNERABILITY!!!!!!! and there's nothing you can do except whine on Github!" I like Bazel's WORKSPACE approach, allowing me to specify the exact sha256 of the compiler toolchain I want to use, and every version of every transitive dependency. Somehow I feel like nobody is that serious about dependency provenance, though, and they invent a lot of clever workarounds to avoid maintaining that file. But at least you can be correct and in control if you want to. (With go projects, the biggest problem I've had is keeping protoc, protoc-gen-go, and the Go proto library in sync. Go doesn't handle non-Go things, and that really sucks. You have manually manage that stuff, and people mess it up. Or use Bazel, which I've tried and came to the conclusion that nobody else has ever done.)
So all in all, I think Go's IDE support and dependency management meet my needs. I dare say I think they're great! All of this stuff is relatively recent, though, so there are probably a lot of people stuck with their code in ~/go/src/github.com/me/my-app that manually run "goimports" from time to time. That sucks. But there are better tools available!
Yeah, I should clarify: I was responding to Rob's point in the interview where he was talking about tooling and IDE integration from the outset rather than the current state of the world.
As for Jetbrains writing their own IDE... well, yes and no. Sure there's a separate product from a user perspective but IntelliJ has had a Go plugin for several years. You'll probably find Goland (just like all the other little-IntelliJs like AppCode, PyCharm and RubyMine) are little more than stripped down versions of IntelliJ's code base with a different default set of plugins. My point is that Goland wasn't a "new IDE from scratch" level of investment by Jetbrains and that a third-party plugin could've been largely equivalent.
You're right that go didn't have amazing tooling from day 1, but the tools it did have were enough for me to change my workflow. I never cared about autoformatting (too many knobs to turn) before gofmt, and now I can't live without autoformatters.
Coming from a dynamic language background, I also never really got tools that claimed to provide completion to work, so I ignored them for most of my career. I worked on a Java project at Google and Emacs worked fine. Now there is LSP, and I first tried it with gopls, and it worked perfectly. Now I can't live without it, and try to avoid having to work in languages that don't have a good LSP implementation. (I am also very annoyed by the multitude of C/C++ projects whose crazy bespoke build systems manage to make clangd not work. That's the reality of tools coming along late; sometimes it's too late to have an impact because people have gotten by without the tool and are happy to continue with that.)
I have also used a little Goland. At my last job, we replaced a lot of PHP and Expect scripts with Go programs, and it was quite the journey to keep people happy with their existing IDEs. (Everyone had the Jetbrains you-get-everything pack, so at least Goland was free.) Goland is really a from-scratch implementation of editor support for Go. They had no other choice... but it makes different decisions from the open source tools which is quite the pain point. (I remember it importing opentracing-go as a plain "github.com/whatever/opentracing-go" and let things in the file refer to that as opentracing.Whatever. goimports wrote it more explicitly as 'opentracing "github.com/whatever/opentracing-go"'. I still don't know how that works, but apparently it did, and so diffs would always oscillate between the two until we convinced Goland to just run goimports.
What I like about go's tool support is that it's done a good job of adding features for people that want them, and letting those people use the tools without upstream dependencies knowing about those tools. I started using go modules before it was particularly popular in the community, and it didn't cause much trouble. (People sure liked to force push to their version branches, though, causing go.sum checks to fail. And people would always blame the Go team for that, unfortunately.)
I have a hunch that not many people are using gopls, but it works perfectly on codebases where I know the authors never used it. That is a pretty big deal and is better than what a lot of other languages do. "We have this new thing... restructure your codebase to try it out." It's nice for new codebases, but even nicer when you don't have to do that.
So all in all, I am very satisfied with the tooling situation.
What exactly is misleading about generics?
The psychology of thought leaders is fascinating. The term generics is colloquially understood to mean parametric polymorphism and here's Pike redefining the term to draw some distinction that doesn't really exist just to remain self-consistent.
Come to think of it, this is a really common pattern. If you've made remarks that you must now backtrack then refine terms until your old writing doesn't seem to contradict your current stance because you can just say people were using the terms wrong and you were right.
Some results for searching "generics": https://docs.microsoft.com/en-us/dotnet/csharp/programming-g..., https://www.typescriptlang.org/docs/handbook/generics.html, https://docs.swift.org/swift-book/LanguageGuide/Generics.htm..., https://doc.rust-lang.org/rust-by-example/generics.html. If you search for "Wadler generics" then a book about generics in Java is the first result: https://www.amazon.com/Java-Generics-Collections-Development....