News for hackers. Stuff that matters.
Re:Go 1.17 Beta by jrockway on Thursday June 10, 2021 @04:06PM (#27465114)
I have a bunch of apps that depend on Kubernetes (consumers of client-go), and I haven't experienced long build times. I cleaned my cache ("go clean -cache") and tried building one:

  $ /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.

Re:Go 1.17 Beta by truffdog on Thursday June 10, 2021 @04:50PM (#27465646)
OP might want to check their security software- things that hook into every file access can really kill compilation performance.
Re:Go 1.17 Beta by Groxx on Thursday June 10, 2021 @04:33PM (#27465419)
>go mod list -m -u all

minor correction: just `go list` on these. the `-m` ensures it's in module-mode.

Re:Go 1.17 Beta by jrockway on Thursday June 10, 2021 @04:46PM (#27465601)
Thanks! I typo'd it both times! It's now corrected.
Re:Go 1.17 Beta by psanford on Thursday June 10, 2021 @09:23PM (#27468271)
You aren't really pinned to the version of Prometheus the library depends on. Minimal Version Selection[0] means if you specify a newer minimal required version of Prometheus in your go.mod that is the version that will be used.

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.

[0]: https://research.swtch.com/vgo-mvs

Re:Go 1.17 Beta by jrockway on Friday June 11, 2021 @12:32PM (#27475393)
The problem is that Kubernetes went backwards in version numbers. I want to depend on, say, v0.19.0, but through the dependency chain, we end up with a dependency on v12.0.0. (At some point, they decided to switch from "kubernetes x.y.z = [email protected]" to "kubernetes x.y.z = [email protected]".)

I made a test module that depends on loki and kubernetes, and updating kubernetes results in:

  $ go get k8s.io/[email protected]
  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.

Re:Go 1.17 Beta by psanford on Friday June 11, 2021 @03:26PM (#27477446)
Fair.