New case studies about Google’s use of Go
opensource.googleblog.com
opensource.googleblog.com
Compare this with Typescript (or Swift, or Rust), which have type systems capable of modeling nearly any problem domain. Go doesn't have algebraic data types (sum types) which are incredibly useful in my experience (Swift/Rust enums, Typescript discriminated unions). I'm honestly not sure why I would use Go over TS, unless performance was my primary consideration. It feels like Go was designing to be as inoffensive as possible to a legion of new-grad Google programmers, and you sacrifice most modern language niceties for it. Please convince me I'm wrong, because I really wanted to like Go.
With respect to Python and JS, you can always drop down to `interface{}` for similar expressive power and type safety, but generally people don't do this for the sake of simple for-loop boilerplate.
Here are some serious pitfalls with Python (it's the language I know best) that dwarf concerns about language features. JS, Kotlin, and C# share some of these problems. Go doesn't really share any of these problems; it competes well with JVM and .Net with respect to performance, and its tooling story is simply top-notch on the whole (of course, there are individual tool categories where other languages have better offerings).
* Python is a super slow language and the proverbial advice "just rewrite the hotpath [with multiprocessing / with C / with Pandas / etc]" falls over for any bottleneck that involves processing a large object graph. In these cases, you can't use multiprocessing because the de/serialization and IPC costs will typically exceed any parallelism gains. You can't use Pandas because the data set isn't matrix-shaped, and even if you can shoehorn it into a dataframe, you'll end up calling back and forth between Python and Pandas/C so much that you'll lose anything you gain from Pandas (and have much harder to maintain code). Similarly with "rewrite it in C/Rust/etc", you'll have to basically rewrite the whole object graph (including all of the inherent classes and methods) into C/Rust/etc and you probably don't want to keep those in sync with the original Python classes, so congratulations, a huge amount of your code is now in C/Rust/etc and you're no longer enjoying any of the benefits you would enjoy with Python (probably iteration velocity). Sadly, performance isn't likely to get better in Python because the community is so heavily invested in C-extensions (because Python is so slow) and the C-extension interface is basically the whole CPython interpreter, such that anything that wants to play in the ecosystem has to be very CPython shaped including many mechanisms that are prohibitively difficult to optimize around. Pypy is making a lot of interesting progress, but compatibility is still a blocker for lots of applications (e.g., anything that wants to talk to a Postgres database--unsupported packages notwithstanding). Python is fine if all you're doing is shelling out to a database or a C library, but anything more becomes expensive quickly ("well how come $BIGCOMPANY is so successful despite using Python?!": probably deep pockets).
* When you want to distribute a Python program (e.g,. an internal tool), your options are pretty limited--the executable zip file formats (e.g., PEX files) are pretty nice, but inevitably something depends on an .so file (because Python utterly depends on C for just about everything) that doesn't get included in the zip file. Even in the happy path, you have to have the right version of a Python interpreter installed on the target system.
* Correctness is the least of problems with untyped Python or JS, rather the biggest problem is the lack of quality documentation (critical information is typically either missing or outdated). The second biggest problem is that there aren't rails to guide mediocre developers toward sane code--developers tend to not know how to "think in types" and the code is typically far more complex than equivalent typed languages as a consequence.
* Python nominally has a static type checker, but it's still very immature (still can't model JSON or even callbacks with keyword arguments). Further, getting it to find the type stubs for a given package is an exercise in frustration and terrible error messages. The only hope is that the Python community seems to be leaning into type annotations, so that should drive improvements in tooling in time (how long? is a different question)
* Tests are super slow, largely because Python is super slow. CI bills can get to be really expensive. Not a big deal for well-endowed companies, but this is really hard for companies with meager budgets (this is ultimately true for Python generally IMO, not just WRT CI bills).
* Documentation generation is brutal. Developers have to document types and keep them up to date. Consequently documented types are never up to date and many libraries--even the most popular--just punt on documenting types altogether. Then you have to write and maintain your own CI jobs for building and publishing documentation packages. And the documentation is still really reader-hostile on account of the everything-on-one-page, nested-with-no-context structure (e.g., SQLAlchemy has lots of methods and even classes with the same names but minor variances in module path and the only way to tell what you're looking at is to gradually scroll up to the previous `class Foo:` block and then back down to the thing you're looking at. Good luck ctrl+f-ing around). The latter problem would be easily remedied within Sphinx. The typing problem will get better as the typing story improves, but it's improving at only a snail's pace (mypy is still prohibitively difficult and restrictive for many projects). Further, if someone wanted to build a godoc.org clone for Python that automatically discovered, built, and published Python packages, I don't know if it would be possible because Python doesn't have a standard repository structure.
* Then there's a long tail of paper cuts. Black (Python formatter) is a welcome relief but it's also really slow. No decent editor plugins (dynamic typing) and PyCharm is relatively expensive and there's still constant friction between it and your preferred editor even after you've learned it. Python has no dead-code elimination so artifacts are frequently enormous--like "too big to fit into a lambda, better use an ECS task and good luck with those startup times" big. Etc etc.
Personally feel like rust is better overall, but I don't know if you've tried it
It's okay not to use Go for your projects. But there's no need to drop your personal opinion of a language into a post about specific case studies of how that language is used inside a company.
> I absolutely love using Go. The logical flows for my programs...
> Go is super productive. My day-to-day responsibilities include...
> Nothing gets out of the way better than Go.
> Go as a new language is a mega success.
I'm guessing you're OK with these, and maybe it's just negative opinions that are irrelevant?
Negativity is inherently bad. There is a place for it, of course, but when it's off-topic it's especially unwelcome in my opinion. And programming language discussion already has far too much negativity.
Joke aside, how about we all complain about your favourite language in every post? It over time becomes irrelevant to those who grok the language.
The most common case I happen to have run across is the result of parsing data or configuration files; situations where there might be structure, but all of it is optional.
PS: Your "algebraic data types / sum types" sounds very much like interface composition, a ReaderWriter ( E.G. https://golang.org/pkg/io/#ReadWriter ) for example composes interface types.
C-like languages traditionally give only the 'product' half of types (C also gives union but they're super low level, and Go just eschewed them). A _modern_ language would give both products and sums.
For a project with 20-30 files and around 8 dependencies, it took 10-20 seconds to compile and 4Gb of RAM (yes I checked with tsc --listFiles that no other files were parsed).
The same in Go to compile to native would probably take <5s in my experience!
Something is very wrong here. If you use `tsc -w`, you should get incremental compilation. Small changes should compile almost instantly.
For me, even without using `-w` on pretty large projects, my compile time is never more than 5s.
I have to wonder if you have bottlenecks elsewhere.
Regardless, TypeScript's type system is much, much more expressive than Go's, so compile time will theoretically be slower. For me, it's worth it because compile time is an inexpensive way to save lots of maintenance time in the future.
(Note that I would never use TypeScript and Go for the same type of project, but that's my mindset in theory.)
Of course, that doesn't affect the slow production build time, but I care a lot less about that (since it usually happens off in CI land somewhere and I'm not sitting waiting for it to happen.
So ultimately, this is a non-issue for me.
map/filter and their equivalent loops are both perfectly readable, but the latter involves more boilerplate.
Simplicity (in language features) can lead to complexity (in code) that is hard to maintain.
Golang was designed for getting shit done. If you are a big believer in OOP, then Golang feels underfeatured. But if you don't really care about OOP and you just want some of the advantages like basic inheritance, type safety, etc, Golang has everything you need to write performant, effective code quickly (there are use cases where that isn't true I'm sure, but, for me, Go's type system has been helpful and not a hinderance). There's nothing wrong with using the empty interface when you need to (any more than using any in TS, which you have to do in many applications).
I've found that Golang codebases are easy to pick up. I think everyone has some part of the Go style that they think is ugly (I 100% find append ugly), but for me this has mostly been inconsequential stuff - it has never gotten in the way of me solving business problems with high performance code. The tooling is the same (at least if you are using modules). It does its job well enough and then gets out of the way while you create business value.
I don't know your use case so this might not be relevant, but sometimes people will overuse for loops and slices when they might find it easier in Golang to pass around channels and use the pipeline pattern[1].
For me, Golang is like Python but with static typing and high performance. Fast to implement, easy to read, and focused on getting code out the door.
I dont particularly want Haskell with semi colons and braces, but a functional style definitely has its place.
Just like Go has a subset of the traditional object oriented style, i think there is a place for a subset of functional.
The problem is language-independent, but is more pronounced among adepts of "practical" languages and tools.
col.filter(_.isReady).map(convertToX).any(_.color == BLUE)
and generate whatever fused loops make that work. I don’t want to write and review loop boilerplate by hand for the same reason that I don’t want to customize the stack frame layout when I call a function.A bigger concern when I started out with Go was the imports/lack of versioning, and at the time the lack of official package manager.
for i, c in range col {
if c.isReady && convertToX(c).color == "BLUE":
return True
}
(which is not to say I don't miss the map/filter syntax - although I don't miss the bugs related to lazy execution in stuff like LINQ or Spark) anyBlue := false
for _, c in range col {
ready, err := c.IsReady()
if err != nil {
return nil, fmt.Errorf("isReady failed: %v", err)
}
if !ready {
continue
}
x, err := ConvertToX(c)
if err != nil {
return nil, fmt.Errorf("convertToX failed: %v", err)
}
color, err := x.GetColor()
if err != nil {
return nil, fmt.Errorf("getColor failed: %v", err)
}
if color == BLUE {
anyBlue = true
break
}
}
which badly obscures what’s going on but demands no cleverness at all (except that some might forget the “break” and still get the right answer). col.filter(c => Try(c.isReady).getOrElse(false))
.map(convertToX).any(_.color == BLUE)Rust is a good example of functional lang without exceptions (panics aside).
In Rust there are many cases where I could use FP but opt not to because it can make error handling more awkward. For example to collect the result of a map operation to a vector, and if there is an error along the way you want to abort the entire operation. In functional this means collecting to a Result<Vec<T>>. Not sure if I'm just tired today but I can think of how to do it in 5 seconds with a loop. I suspect functional solution would be uglier.
https://doc.rust-lang.org/stable/rust-by-example/error/iter_...
This is easy to miss if you are mainly reading reference docs. I probably read the getting started guide at a time before there was a section on it.
My other comment in this thread comes to mind https://news.ycombinator.com/item?id=24300057
I don’t personally really agree with what you’ve said, but that’s fine. Different people perceive things differently.
Robustness. Speed. Simplicity. Easiness. Conciseness. Writability. Readability.
Hard to tell which are independent vs correlated, let alone how they factor into productivity. And productivity is also a function of the kind of problem you work on.
I disagree. Python is often described as "executable pseudocode" - for example, to delete the `i`th element from a list `a` you use `del a[i]`.
In Go, it's much more convoluted: `a = append(a[:i], a[i+1:]...)`. Plus, without generics, you can't even easily hide that inside a function! There's a whole page of these "tricks" that are necessary to perform basic operations on slices: https://github.com/golang/go/wiki/SliceTricks
It would be trivial for Go to support the delete keyword on slices (mapping to the statement you noted), but I think it would be a bad idea. Sometimes you want an operation to be awkward intentionally because it’s fundamentally costly. Hiding that cost by making everything look the same doesn’t always help the programmer. Languages should be powerful, but there should be an intuitive relationship between the code the computational complexity (not exact, but intuitive).
I’m sure there are counter examples, but I think Go generally does a good job at this. Plain loops are standard, make, append, new, delete, etc. have obvious costs. Error handling is explicit.
Not only is this ugly and unintuitive (“what function do I call to delete an element?”; “append”), according to the linked page it can also cause a memory leak?!
I'm not a C guy, but I figure doing this in C would involve several lines of mmemove, with loads of error checking[1]. So the Go version is about as ergonomic as you can get without obscuring what's going on.
[1] - I guess you'd do something like: memmove(a+i+1, a+i, sizeof(element) * (a->len - i)) with a whole load of checks to make sure everything's in order. I think C has the advantage of being utterly explicit about what is actually happening, but I think a higher level thing like append() is kind of nice when you don't want to think hard about, say, inserting an element in the middle of an array.
That's indeed a good way to explain the utility driven nature of Go. I've been predominantly using OOP languages before and Go's deliberate lack of OOP features was although uncomfortable at first, the advantages of getting things done fast far outweighed it later when I released production applications with it.
>For me, Golang is like Python but with static typing and high performance. Fast to implement, easy to read, and focused on getting code out the door.
I was tired of adding disclaimer when teaching Python, that when you want to extract performance out of it you should also learn 'C/C++'. Go serves as a perfect replacement to Python where performance is a necessity, I don't see where that would be false in a production environment where 'code performance == capital efficiency'.
for foo in ...
if i in foo:
creating something of quadratic complexity!Yes, I would rather take the explicitly verbose Go code
To be clear: If foo is a dict, we have one loop. If foo is a list, we have two loops. If accidentally happens to be a string, even then it is nested loops
Although I do remember trying racket, where they solved the same problem by naming functions dict-remove set-remove hash-remove vector-drop etc, which does the job but never have I been more offended thinking I was going in for its abstraction capabilities
For me, when the task is right, “limiting” becomes “straightforward and uncomplicated” and the things it does well really shine. The language and its type system encourage a simplicity of thought that I find refreshing when compared to the power and complexity of modern languages. I also can’t say enough for the joy of deploying Go binaries over TypeScript projects.
Even so, I’m waiting for generics before I use it for anything really significant. As is right now, I could see myself becoming frustrated with the Zen of Go if I had to use it every day. Just give me map, damn it!
Rust is great but I waste a lot of cycles thinking about how to structure the code instead of the actual problem. What is cleaner here using a loop or a higher order function? Should I use if let to make the code a little shorter? Should I use that question mark trick to propagate the error? Do I use the expression or statement form of ifs?
Do all of the features in your language really make you more productive, or are the gains offset by the cognitive burden of dealing with them? And what is the cost of having many ways to do things in the context of a code review? What about when reading other people's code? What about when writing automatic tooling?
Golang is popular for a reason. It is popular even among programmers that enjoy using other languages. No need to feel bad for programmers who are happily building things.
Go provides less is more as a feature, but would be invisible unless the dev cared about seeking simplicity and performance.
Whenever I work in Go, I have a lot more confidence in the efficiency of resource usage, and sense of stability that I just don't get from something like Node.js, where I'm constantly wondering... are any of these 1000s of dependencies going to suddenly do something weird like hijack my .env file? How is my program managing memory and overhead when it needs to interface with the kernel via a C++ wrapper? Are these machine resources even being capitalized on by Node.js properly? etc.
I've heard a lot of great things about Rust, and I've touched on it a bit, but Go is just awesome for its abstractions, ease-of-use, and of course insanely fast compile times.
Right now you need enthusiasts and a project that can either accept or handle the risks brought on by the immature ecosystem.
Later on, Rust will most definitely be a huge thing. It's just not the right choice for everything - even if the community has a habit of pumping out "X - but with Rust" projects.
After a while, I kinda started to dig having to do it. You end up having a more personal connection with the dependencies you pick which makes it easier to contribute back upstream.
The one downside of being around in this stage of a language's ecosystem development is you can potentially get some pretty undesirable fragmentation.
A good example that comes to mind is one of the original Go library to interact with Zookeeper. There's like 6 maintained forks of that library due to the original author bowing out of maintaining it.
"Magic" refers to the implementation of certain language or library features directly in the compiler without using the language features. C++ is on the least magical side, since the entire standard library and major libraries are implemented exclusively using language features. Everything is specified and C++ is one of the very few languages which has an international standard. It's especially odd to call other languages out for this when Go for example has magical generic data structures when this feature isn't supported by the language.
Next time consider limiting your comment to praising Go and don't pretend that you know enough about other languages to draw a meaningful comparison.
Every language has things it's good at, and things it's bad at. Where does Go not do well?
I'd rather not mention the company, even though I did not work there.
And we're talking about migrating from Java..which is extremely well supported and probably the easiest language to hire for..
Described publicly like Dropbox's backend migration to Go: https://twitter.com/jamwt/status/629727590782099456
I could give you tens examples of that, many have been posted on HN.
I was just providing the example the parent post was asking about. And note it's "hearsay" to you only because I didn't name the company and people involved -- because I was told this in confidence -- but this is a major company where I'm from, and their attempt at adopting Go ended up in disaster. Just a data point, that's all.
https://blog.discord.com/why-discord-is-switching-from-go-to...
Discord: haha, no, that's silly! let's spend 100,000x more effort and rewrite it all in another language!
Now, before those of you who learned to argue on the internet extrapolate what I wrote and imagine that I wrote words I didn't write: I'm not saying that Go should never be abandoned for another language. I'm saying that this particular example of this particular choice puzzles me, because of the reasons stated, and ONLY the reasons stated.
Not entirely sure that I have the Go versions right, but that's what I remembered off the top of my head.
> Another Discord engineer chiming in here. I worked on trying to fix these spikes on the Go service for a couple weeks. We did indeed try moving up the latest Go at the time (1.10) but this had no effect.
[0]: https://old.reddit.com/r/programming/comments/eyuebc/why_dis...
It describes a rewrite of a single service from Go to Rust.
Reading between the lines, a rather simple piece of code.
At no point it implies that Discord rewrote all their Go code in Rust and completely abandoned Go.
> Any reason you’re using 3-year-old Go 1.9.2 but you’re okay using Rust nightly?
> Another Discord engineer chiming in here. I worked on trying to fix these spikes on the Go service for a couple weeks. We did indeed try moving up the latest Go at the time (1.10) but this had no effect.
[0]: https://old.reddit.com/r/programming/comments/eyuebc/why_dis...
Also, after publishing that blog, they also said they had wanted to try Rust for other reasons:
wanted to try out rust as well for services like this, due to adoption elsewhere in the company. Also, after upgrading between 4 golang versions on this service and noticing it didn't materially change performance, we decided to just spend our time on the rewrite (for fun, and latency) and to get a head start into the asynchronous rust ecosystem. [2]
And nothing wrong with that decision from my point of view (Rust is great!), but I believe they could have solved it without dropping Go for that particular service that they blogged about, at least as far as I was able to understand.
[1] https://blog.discord.com/why-discord-is-switching-from-go-to...
Do you know if that was the case when the decision to switch was made? They said elsewhere they tried Go 1.7-1.10 and none of those solved their issue, and at least back when the blog post was released I couldn't figure out whether the fix for the corresponding issue was known to have been slated for release in the next Go release.
It’s a good question.
The timing is a bit confusing because the blog was apparently published a bit after the fact, but I think I saw that they said they made the decision mid 2019.
Go 1.12 seemed to address their latency issue, which was available as GA in Feb 2019.
That’s based on some retroactive benchmarks on a set of old Go versions starting with 1.9 and targeting what they described as the problem and symptoms.
Things seemed to line up, but I can’t be sure.
I don’t know if Go 1.11 would have addressed their issue.
(In general, Go GC tail latencies including for large heaps have improved a bunch since the last version they said they tried, which I think was Go 1.10).
In any event, they saw a problem, and made a rationale decision for multiple rationale reasons.
> Another Discord engineer chiming in here. I worked on trying to fix these spikes on the Go service for a couple weeks. We did indeed try moving up the latest Go at the time (1.10) but this had no effect.
So I guess that means that there's a reasonable chance that they didn't see a fix on the horizon.
That being said, I have no idea if work to fix this issue was visible on Go's Github, so maybe the Discord engineers were unaware of said work or were unhappy with the pace of progress.
Kind of miffed at myself for missing that comment, since it directly addresses my question, but at least it's answered now.
[0]: https://old.reddit.com/r/programming/comments/eyuebc/why_dis...
It seems during that gap in time, the Go runtime team happened to solve their problem, which was GA in Go 1.12 in Feb 2019, which was prior to them doing the re-write in Rust, at least as far as I was able to follow.
One imprecise quote on timing of the re-write: [1]
This blog post perhaps is a bit "after the fact" we had made the switch over mid 2019
It's not crazy for someone to put aside a problem for a while, and then upon returning to the problem some time later decide to go a different route without re-exploring prior solutions, if that is what happened.
All that said, I might have misunderstood the timing, and I'm trying to avoid going back over all the various forums they commented in to find a better quote on timing ;-)
The situation you describe is certainly plausible, though. Shame that the chances of finding out what actually happened are quite low at this point.
I would be interested to hear rebuttals or other thoughts.
I've said this before, but I think it's a bit dishonest to sell this as a "Google language." It is an accepted language here, along with Python, Java, JS/TS, Dart, and C++. But it is by no means dominant.
To put it another way, it seems if the goal is to avoid working in Go I am better off staying @ Google than leaving. And that's weird, and maybe revealing.
I don't really care that you find that un-constructive, as you can go elsewhere to get people's critiques of the language, there are plenty of them and they come up every time someone posts about Go here. My opinion is certainly not unique on this subject.
If you're going to trash something at least put in enough effort to explain yourself. Otherwise I think this thread was better off without your comment.
I think you might be a little too emotionally attached to Go? I am allowed to have a subjective opinion on Go and voice it in public discussion forum. This is not a scientific paper or journal article.
I would genuinely like to know what your criticism of the language is, but you haven't offered any. The comment you wrote does not add any clarity to the discussion of Go, in fact I think it takes away clarity by relying on suggestion and avoiding grappling with any details. I think it was not a useful contribution to this thread. I'll leave it at that.
If you have to have an answer, he said he's opined on it in the past. Go trawl through his past comments. (Google search might help.)
Blame the cargo cult and hype driven development for that one.
Edit:
Just to add to that statement: the work stealing goroutine runtime is particularly problematic, certain things are even impossible in go due to it. If you look at runc, large parts of it are written in C and called during init before the runtime is started.
You can create an exported version of the function (calling into the unexported one), no diff except the new function.
But also just updating all the callsights is usually not a huge issue, especially if you are using an IDE such as GoLand.
These are the kinds of hacks that show that golang wasn't really designed for "programming in the large", despite their claims.
I've used goland, and the actual renaming is generally fine (it means it works correctly when needed). However, that doesn't mean that there isn't a lot of friction
I maintain some very large codebases. This has never been an issue.
If one decides to export a function, the only callers of that function will be from within the package it was defined in already. Even within a package, how many call sites will there actually be and do they need to use the exported version of the function?
I'm not saying it's good, or bad, just that in my (fairly extensive) experience it has not been a problem. I do recognize that some people may have problems with it, though.
- Go was too slow and GC too much overhead (real time analytics)
- Error handling and propagation is insanely verbose in Go, the C++ actually was more concise
- lack of generics made it impossible to reuse complex high-performance data structures and algorithms even within the project
Haven't looked back and between C++, Rust, Swift and Python, I'd never choose to use Go again.
At a far smaller scale, the SaaS product my company built, Domestica (https://about.domestica.app), is a Go monolith. It has an integrated job/cron queue using PostgreSQL included as well, all within the same binary. This makes it easy for us to distribute it as a Docker image to our users who want a private instance (https://hub.docker.com/r/candiddev/domestica).
Don’t know much about go myself, but I’m interested in examples of this.
In addition, a canonical format makes it slightly easier to do plaintext search indexing, so you can get some of the benefits of having the code parsed into a full AST without needing to do that parsing.
This is a friendlier world to work in than explicit green threads using keywords like async/await in other languages (Dart, Rust, JS)
I'm staying for the standard lib, tooling and stability.
Nothing gets out of the way better than Go.
Because of this, I'm mostly interested in only Go and Java. Go obviously avoids the async/await trap with its core feature, goroutines. Java managed to resist this trap and has Project Loom coming which will give it the same feature as goroutines, but in a backwards compatible way.
Go is criticized for not having generics, but I appreciate the slower and more thoughtful way both languages add new features. Javascript, C#, etc. these languages seem to add whatever FOMO driven new hyped language feature is popular at the moment. Many complain about Go taking so long to add generics, just like many complained about lambdas in Java. But evolving a language should not be done quickly and recklessly.
My focus is still on Java, but I'm occasionally looking at Go to see what they're doing. It's interesting watching these two languages become more like each other (generics in Go and fibers in Java).
In C# async/await is essentially sugar around callbacks, which isn't really related to threads, per se. However, the language has the Task Parallel Library, and a Task promise type that has a lot of methods around scheduling and thread targeting. Essentially the TPL does dictate how many threads are used and is, as far as language design is concerned, inextricable from async/await.
I like Go's thoughtful adoption but personally I wonder they can do faster.
Wasn't k8s written originally in Java and only ported to Go later on?
> Kubernetes was built on ideas that had been proven out at Google over the previous ten years with Borg. And Borg, itself, owed its existence to even earlier efforts at Google and beyond.
> Concretely, Kubernetes started as some prototypes from Brendan Burns combined with ongoing work from me and Craig McLuckie to better align the internal Google experience with the Google Cloud experience. Brendan, Craig, and I really wanted people to use this, so we made the case to build out this prototype as an open source project that would bring the best ideas from Borg out into the open.
> After we got the nod, it was time to actually build the system. We took Brendan’s prototype (in Java), rewrote it in Go, and built just enough to get the core ideas across. By this time the team had grown to include Ville Aikas, Tim Hockin, Brian Grant, Dawn Chen and Daniel Smith. Once we had something working, someone had to sign up to clean things up to get it ready for public launch. That ended up being me. Not knowing the significance at the time, I created a new repo, moved things over, and checked it in. So while I have the first public commit to the repo, there was work underway well before that.
And then you've Java, which is now trying to be the "VM for every runtime" but is still best at Java itself, for now. I tried running JS-on-Java (graaljs) to improve the performance of JavaScript from "only twice as fast as Python" to "within the top 10 on TechEmpower" but found it had too many compromises to rely on it, it was just another runtime layer I would have to worry about.
I end up wondering if the solution really is to begin by prototyping efforts in slower-executing languages to start except where existing conditions and code ecosystems might allow for faster initial results in another language. (Kubernetes projects should likely use Go, etc.) Which is less about Go and more about the need to rewrite software later, I suppose.
Then again, these days the problems I end up spending (too much) time on are "which dependency should I use," or "should I rewrite the dependency," I rarely ask myself which language is "better" for a task because I end up having to use languages others are familiar with. Go is not yet universally one of those languages, but the more I see unfamiliar Go code in the wild, the more I feel it could be. One of its current strengths is that its simple syntax and maybe its repetitiveness also makes it quite easy to follow for newcomers.
Swift is definitely something I'd like to explore more, but like Rust, it has few production-ready dependencies available. Kotlin or other Java derivatives on the other hand probably have too many -- if your code is written in Java, I've no idea if it will work great in Kubernetes or if it will expect OSGi or if it's a giant monolith. Which is to say, modern practices can make the JVM a surprisingly practical choice, but most software isn't really all that optimized -- slow and bloated legacy dependencies are both a problem in Java as in Node.js...
C# meanwhile can be efficient, but rarely is. And it has toolchain issues due to VS not being open source, and a very small ecosystem of dependencies, plus a history full of corporate rewrites of core functionality. It has a bright future, but its reliance on msbuild and Visual Studio limit it compared to Java. I'd like to suggest C++ but I've spent years learning it and find the complexity overwhelming in side projects. In practice, I think C++ is only appropriate for full-time projects with lots of engineers to validate correctness, etc. The exception I'd make is tiny C++ modules as glue code between languages, or to other existing C code.
The ecosystem is definitely growing in the last 5 years too since open source has been embraced by MS and the community.
The major rewrite of .NET -> .NET Core and then now renaming it back to .NET again is good in that it's a much better framework now, bad in that it's turning out like Python 2 vs Python 3. Huge projects just can't upgrade, so old .NET Framework stuff is sticking around longer than it should.
They're undoing the split between Core and .NET Framework by suggesting that they'll ship both within .NET 5 using shims or implementations of drop-in replacements for .NET Framework code to use. Imagine if after dropping Python 2 support there was a mode that scanned for Python 2 code and enabled it again, on a file-by-file basis, to work with newer Unicode strings using some kind of translation layer in the runtime. That's kind of what's happening here, I think, but maybe more lightweight than suggested. Legacy .NET Framework code still deprecated, but interoperability libraries will ship as part of the runtime or SDK, will have some amount of shims available. I haven't followed the details closely enough to say more than this, though. I last looked into it a few months ago.
>net5.0
>net5.0-windows
>net5.0_something
So you can use "pure" "net5.0" on Linux and generally cross-platform software meanwhile still be able to use old .NET FrameworkX winforms/wpf on "net5.0-windows".
While Java is generally slow, that's more the fault of Java developers and their FooDangleProviderModuleBuilderBuilderFactories. Due to runtime optimization Java can be nearly as performant as non-GC languages. In principle there are even scenarios where it can exceed the performance of any ahead of time compiled language.
There are idiomatic ways to avoid the GC in Go, and people do that in tiny places, but few people build ground-up that way, because it’s not the kind of program Go asks you to write.
And I think this is all fine as long as people understand it is just opinion sometime of people who are more accomplished. Arguments occur when someone comes in and tell, how they language/Framework/technology is "objectively" superior other people's working solutions.
This exact same language fuels my API and my client. It means I can share packages everywhere, and a problem solved once & put in a library is solved for the team
So, that said - I would also push back against introducing a new language into a stack which everyone shares knowledge of. What benefits did you propose that override such a thing? Or, conversely, why do the benefits I described above not apply to that team?
No one knew typescript at our org, but that was a much easier sell despite slowing down the build and HMR significantly.
It was not for lack of knowledge of go either; there were several developers on the team with strong go backgrounds.
Management was unsure of it as "new" technology despite using next.js, typescript. Really, they just were afraid of switching.
To your point about a vertically integrated stack, this is great in an small to medium environment but on a large (and quickly growing team) where the CI looks like a christmas tree and testing is sparse, it was actually quite difficult to manage. Maybe i'll muster up the courage to write a medium post one of these days.
I don't think go is a silver bullet solution, but when I see something I know can be a lot better and simpler, I generally tend to gravitate towards that.
K8s, docker, native concurrency, robust std lib, list goes on.
Obviously, not the magical swiss army knife for all engineering use cases, but successful in a lot of domains and well-liked by developers. Winning.
And its only version 1.XX.
I've never even used go and I am impressed.
Well done, Google. Well done. (golf clap)
Are there plans for a new version that is radically different, or is it going to be like Java or macOS where updates continue to change what is usually considered the minor version?
Click on the link about the "sixteen case studies" and you'll see the rest.
Go is at my employer's (one of the top 3 car companies world wide) techradar the number one to adopt. New stuff of all kind is done in Go.
So, Go is a huge success outside of Google as well.
Not saying that I'm of any importance for Go, but I'm using Go for personal projects, at work for CLIs and standard backend stuff (APIs + DB, Redis, etc.) with great success.
But to be clear: I'm saying that reading about other people's experiences with a language (including yours here) is useful in making your own decisions, but you must also account for how you and your usecase are different than the one that was presented.
Link from the article
Honestly, it's not breaking news that Go is used heavily outside Google.
If Go is so great, why was Kotlin released four years later and made the standard on Android? It's annoying enough to have to use Swift and Kotlin for iOS/Mac vs. Android. Now Go? What happened to Dart?
Then there's Rust. What about next week?
Golang is made for simple deployments, mostly services that need to scale, stuff you'd previously had to use something like C++ or Java for.
Dart is mostly relevant if you're building apps with Flutter.
Kotlin isn't Google's creation, they just recommend it for developing native Android apps instead of Java.
Dart is one of the three officially supported and approved languages of Fuchsia.
https://fuchsia.dev/fuchsia-src/contribute/governance/policy...
The only language that came out of Google that people have a right to be upset about is PromQL. That's an abomination.
For any of the languages you mentioned, it's easy to find the motivation for their creation, either by Wikipedia or on official pages Why X?. Your uninformed rant sounded a bit lazy and naive (sorry, no offense intended).
From the top of my head... Go was meant as a higher-level language than C where Python could not apply (bad performance, weak typing, no compilation, complex syntax); its wide adoption proves that kind of language was missing at the time. Dart was initially meant as an alternative to JavaScript, like CoffeScript, at a time where JS was less standard. Kotlin was not created by Google, and was meant as a light alternative to Java/JVM, with full compatibility, hence the adoption for Android which is JVM based. As far as I know, Swift and Rust aren't specifically tied to Google.
Go seems clearly one of the if not the best systems language around.
But how is Go in the line of business web application space? The space that's historically been dominated by your Python, Ruby, Go , node.js, C#, Java applications?
I get it's probably more performant, but honestly in C# my primary language I spend almost all my time optimizing DB queries and almost none optimizing C# code. I get it's concurrency model is better, but with web apps that usually isn't much of a problem.
Is Go as better in this space as it clearly is in the systems programming space? I get it could be used for the LoB use case but is it better, and if so is it significantly or marginally better?
You shouldn't. If anything you should be looking into where C++ does better than Go and see if Go is improving there–and understanding that there will always be places where Go is not the best choice or even appropriate.
Where do you think C++ outshines Go?
Taking an example from the article, parts of Google's indexing pipeline are now in Go, but nobody is suggesting that the search engine would be.
These programs are are not even peak optimized but the C++ version still wins every case by between 10% and 1000%.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
For drivers and database implementations, there is more time to do stuff. For example, I wrote a keyboard controller with Tinygo, and it mostly sits around waiting for the USB host's C++ driver to ask it for data. Go isn't adding any latency (and it's not really C++'s fault either; the standard sets a time interval to poll at). And if you wonder what an OS written in Go would look like, look at gVisor. It's not technically an OS, but it does a large number of OS-like things.
Database engines that are focused on throughput rather than latency will also do fine with an occasional GC delay. CockroachDB and InfluxDB have plenty of users.
I like Go a lot, but if you needed the performance or manual control it is not the tool for the job. On the other hand most problems don't fit that description and Go is one of the best choices for them.