Go 1.17 Beta
tip.golang.org
tip.golang.org
On the world of DLLs and COM, those compile times are relatively ok.
k8s has so far decided not to use module versions, which makes using k8s with Go hard.
Unless by then cargo has already learned how to deal with binary crates.
I agree that Cargo is much better than the Go build system, though.
Binary caching á la Nix can work, but I can't really see that working out without Nix's commitment to environment purity.
Sounds like something is pretty screwed up if you're running cargo clean as part of your regular workflow.
> works in domains that don't depend on selling binary libraries for their business
Play stupid games, win stupid prizes? Meh.
Rust Cargo does about as well, probably the best for a compiled language. NPM could be about as good too - it almost feels like they deserve a point off for the ridiculously huge number of tiny packages required to do anything, though that isn't really the dependency manager's fault.
If you want to be sure of what version you get, use it.
Yes, you can ask the tool to print them. This is way worse than any of the other systems being discussed, where you can read a file in the repo.
So other than having a lockfile and having a flexible version specification (and a sensible way to resolve multiple version requests), Maven did "it" first!
... what was "it" again?
$ /usr/bin/time go build ./cmd/ekglue
70.33user 32.72system 0:07.92elapsed 1300%CPU (0avgtext+0avgdata
583644maxresident)k
333392inputs+1232496outputs (14768major+1135114minor)pagefaults 0swaps
$ /usr/bin/time go build ./cmd/ekglue
1.54user 0.90system 0:00.33elapsed 741%CPU (0avgtext+0avgdata
71952maxresident)k
16inputs+0outputs (3major+11111minor)pagefaults 0swaps
It was 8 seconds for a clean build, and 330ms for an incremental build. I agree that building on a 1 core machine with no build cache and module cache is slow. I also realize it's a big pain to preserve the cache between docker builds, so you probably hit this with every commit in CI. The problem is really CI, not Go, but I agree that it sucks. I use Cloud Build / Kaniko which has decent caching, but I do have to wait 1 minute on every build for GCP to provision a new machine (since I'm using a larger-than-default machine; the time spent sleeping while a machine is provisioned is saved by parallelism in the Go compiler). Meanwhile, I run tests on CircleCI, and that is mostly bogged down by very high network contention; pulling caches is slower than rebuilding from scratch.As for modules, I like them. My biggest blocker in using other programming languages is that their package system sucks compared to Go. I do run into problems -- upstream authors don't really know how to use Go modules, and upstream applications are very quick to take on unnecessary dependencies. For example, I depend on the Loki client. The Loki client and server are the same Go module, so they pin me to a particular version of the Prometheus library (that the Loki server depends on), which then pins me to a particular version of the Kubernetes library (that Prometheus depends on). Basically, the dependency graph is hundreds of times larger than it needs to be, because it's not a problem for the upstream authors and they've never thought about it. Splitting the client and server into two modules would make life much easier for consumers, but slightly harder for the producer, so it's rare that you see it one. (My team also makes an app that makes this same mistake -- forcing users of the client to depend on things like Kubernetes. It's hard to fix, because the server uses the client internally, but I may do it in the future. Or just auto-copy the client code into a separate repo + go.mod file for consumers!)
Upstream authors are also very quick to make fixes for themselves, unaware that they don't propagate to consumers. Many libraries have "replace" directives in go.mod, but those don't propagate to consumers, causing solved problems to reoccur for each consumer. You have to manually propagate them yourself. The solution there is to be a good open-source citizen -- if you have to hack up some module, either properly fork it and depend on the fork (there should be a tool that handles this renaming for you automatically), or push your changes upstream and depend on the new release.
Basically, modules involve the transitive closure of all shortcuts a bunch of people you've never met have taken, and the results are not always good. That has been true in every language I've ever used; I have 83 irrelevant Depndabot alerts that can't be fixed in most of my Javascript projects, for example. I think it's the best module / packaging system I've ever used, and I like it very much. In fact, there is little I'd change.
> figure out what versions are actually being built into the final binary
go list -m all
Will print the versions. go list -m -u all
Will print what versions you could upgrade to.I personally include this in every binary I produce: https://github.com/povilasv/prommod
This lets me monitor module versions across the fleet. If there's a security problem in a module, I can instantly see which apps are affected, and update them.
minor correction: just `go list` on these. the `-m` ensures it's in module-mode.
Its slightly annoying that your dependencies' optional dependencies pollute your go.sum, but it really doesn't matter. If those don't show up in your package import graph they won't be included in your builds.
I made a test module that depends on loki and kubernetes, and updating kubernetes results in:
$ go get k8s.io/client-go@v0.19.0
go: downloading k8s.io/client-go v0.19.0
go get: downgraded github.com/grafana/loki v1.5.0 => v1.0.2
go get: downgraded github.com/thanos-io/thanos v0.12.1-0.20200416112106-b391ca115ed8 => v0.11.0
go get: downgraded k8s.io/client-go v12.0.0+incompatible => v0.19.0
This causes loki to downgrade to a version that doesn't work.I don't blame the module system for this, I think it's doing a great job. But when you use other people's code, you're responsible for the transitive closure of all their minor tiny mistakes, and when you depend on big codebases, the mistakes really add up. That's where the hate comes from; a lot of code was written before modules existed, and modules changed the semantics of that code.
Your Go project must be on an epic scale to break even 10 minutes of compile time.
Obligatory XKCD: https://xkcd.com/303/
The anchor tags for the listings go to top instead of being self-referencing. Is that a bug?
Like
format = `<h3 id="%d"><a href="#0">%s</a></h3>` +
Should be format = `<h3 id="%d"><a href="#%d">%s</a></h3>` +
And Fprintf should duplicate a parameter?Hm. I guess the web has programmed me differently. Say I'm CTRL-F searching through the page and I notice an interesting bit of code and say "Hey I have a question about this". Then I start looking for a shortcut to that one file and assume that shortcut is the nearby <h3> header. I expect this because I've seen this pattern implemented a lot. You could have the <h3> be that local anchor and a short [top] link next to it.
- Goland from Jetbrains; awesome but costly
- Vscode with golang plugin; slow, brittle, little functionality
-vim; yuck
It'd help adoption greatly if there was a decent free option here.
[1]: https://en.wikipedia.org/wiki/Rio_(windowing_system)
[2]: https://9fans.github.io/plan9port/man/man4/plumber.html
The only thing it has going for it is being based on Oberon's UI workflows.
The only GoLand feature I've seen that I'm envious of is the mode for editing template files - and even this breaks down quickly once you leave the HTML plane.
Its there everywhere you need it. If I have to use these other fancy pants editors I always enable vim emulation when possible but its never the same.
One amusing downside: the Golang hello world binary takes 2 MB; when compiled with gcc though (against libgo, therefore, dynamically linked), it takes an astonishing 60 KB - not even 64 KB!
Unless you’re in the lucrative hello world industry. Or at least I assume it’s lucrative since so many people come here posting about hello world binary sizes—it certainly seems to employ a lot of people.
And even then it's not a sure win, because LTO can remove a lot of useless code from dependencies, so if you only use a small part of a dependency you might still be better off with static linking regardless of other factors.
It's pretty hard to justify the complexity and overhead of dynamic linking nowadays, IMO.
It's so crazy where we are.
It's like when people whinge about Electron. Electron gets you a runtime that's near identical across the major platforms, with a11y (something the Linux native toolkits still don't have their shit together on) essentially for free, plus you can use modern reactive component frameworks like React and Vue on the desktop. Yeah, I'll pay 300 MiB for that.
For example, that's all that the production image of NATS Streaming is - https://github.com/nats-io/nats-streaming-docker/blob/024b04...
Benefits: Improved performance and reduced hosting costs
Go is so nice for getting stuff done.
The problems arise when you try to do something it's not good at and you start wrangling with the language. If your coworkers have strong opinions on how Go is supposed to be used, it can make matters worse.
My biggest qualm by far is the limited type system, e.g. it has no concept of immutability or non-null pointers :( Also accomplishing simple things sometimes requires surprisingly weird techniques, e.g. cloning a slice.
The lucky people can evaluate a problem and choosing the right tool for it. The unlucky bastards like me get handed a language and are expected to build everything in it. It can be rough sometimes.
Because of that, the language is unlikely to fix the issues that are very real to me. The community claims they don't need them, the language designers, perhaps a bit more arrogantly, claim that I don't need them. Yet, I've used other languages where I've never had to consider this. I can clone whatever I want, whenever I want.
If I only ever cloned []bytes, I'd write a helper function, keep it in an utility package and go on with my life.
This ties back to the original theme of "it works well for certain things, but if you try to do something that the designers didn't predict, good luck to you".
Someone did a writeup on this which is a perfect illustration of a general theme with Go: on the surface it looks fine, but the closer you look, the stranger things get:
https://github.com/go101/go101/wiki/There-is-not-a-perfect-w...
IMO, copy() is well-designed and the semantics are sensible. I think the other examples in that article are not clear, and the semantics have me second guessing what they're doing.
> Drawback 1: if s is nil, the result sClone is not nil.
I can see how this particular semantic seems an issue, but I think its sensible. If your copy() returned nil and you wanted to use it, then you'd have to check if sClone is not nil first, so that if statement is unavoidable. Instead, it's often safer in practice to check ahead of time.
Sorry again for my tone, it's easy to appear rude on the internet on a late night.
That's a fun one
Go 1.17 implements a new way of passing function arguments and results using registers instead of the stack. This work is enabled for Linux, MacOS, and Windows on the 64-bit x86 architecture... For a representative set of Go packages and programs, benchmarking has shown performance improvements of about 5%, and a typical reduction in binary size of about 2%.
res, err := new(http.Transport).RoundTrip(req) client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
Then use the client as normal. You can also modify the function for very specific redirect behavior.Granted, part of it is that it's too complex to be captured by one timeout, but everyone wants one timeout. kinda like string-sub-slicing and UTF-8 multi-byte characters - it's a Bad Idea™ because the over-simplified stuff is fundamentally wrong and will often cause problems. E.g. I routinely encounter tools with short timeouts that don't work on slow network connections (e.g. Bazel), despite actively downloading - what you generally want for user-use is a timeout that ensures the download does not hang forever doing nothing, not the download completes within a specific amount of time.
... but also it's just abnormally bad.
I'd love to see this one addressed but it's not looking too hopeful at this stage.
Along with deprecating Intel support, it seems like Apple, their users and the ecosystem is totally fine not giving a shit about supporting aging software. It doesn't seem like anyone cares that much either.
Even more impressive that on average, Macbooks have a much longer lifespan than other laptops, while the software they run is intolerant of old versions.
https://github.com/jftuga?tab=repositories&q=&type=public&la...
Any feedback is most welcome!
> Note that the new conversion from slice to array pointer is the first case in which a type conversion can panic at run time. Analysis tools that assume type conversions can never panic should be updated to consider this possibility.
WHY! So now we can't trust that the type *[N]T won't panic at runtime when accessed by in-range index values. This should be identified as an unsafe conversion.
If the Go tooling insists on involving itself with versioning, dependencies, and source control, it should actually USE the source control tools to manage versioning and dependencies! It isn't rocket science to make a temp directory, clone from the local repo, check out a tag, and use that for building. Git even has facilities to check out the tree at a specific commit, no full clone required. (Granted, my view is Git-centric, but I believe that mercurial and svn also allow you to clone and check out labelled versions, especially considering those are _the basic requirements_ of an SCM.) And why do we need to verify cryptographic integrity of downloaded code bundles when the SCMs typically use cryptographic primitives to describe versions? Then to mandate a gatekeeping "sum database" on top of all that?
Finally, it is depressing to me how shut-in and closed-off the core team seems. The designs for big language changes are rarely ever proposed by the community, only by people already in the team. While (I hope) the community's input helps inform their decisions, the final module design was rsc's. Before he drafted the design document, dep versioning was a user-space/community problem, but after it came from him, then—and only then—was dependency version management truly considered for the toolchain. The generics design came from, and was accepted by the core team. Rob Pike's recent d̶e̶̶c̶̶i̶̶s̶̶i̶̶o̶̶n̶ proposal to support taking the addresses of simple types is—as one might expect—unquestionably going to be added.
The greatest thing that could happen to Go would be a community-organized and -centric fork, like Gitea was to Gogs. Even if they didn't maintain strict compatibility with each other, I know which one I'd use.