blog: we already have go 2 #5
|
@ -8,12 +8,11 @@ tags:
|
|||
- modules
|
||||
---
|
||||
|
||||
I've been using Go since Go 1.4. Since I started using Go so long ago, I’ve
|
||||
seen the language evolve significantly. The Go I write today is roughly the same
|
||||
Go as the Go I wrote back when I was still learning the language, but overall
|
||||
it’s evolved and changed into something similar yet different feeling in
|
||||
practice. Thinking back over the years, here are some of the biggest ticket
|
||||
items that really changed how I use Go on a daily basis:
|
||||
I've been using Go since Go 1.4. Since I started using Go then (2014-2015 ish),
|
||||
cadey marked this conversation as resolved
Outdated
|
||||
I’ve seen the language evolve significantly. The Go I write today is roughly the
|
||||
same Go as the Go I wrote back when I was still learning the language, but the
|
||||
toolchain has changed in ways that make it so much nicer in practice. Here are
|
||||
the biggest things that changed how I use Go on a regular basis:
|
||||
openskies
commented
This doesn't make sense. Saying that it's rougly the same but has overall changed into something that feels different in practice doesn't mean much to me. This sentence could be removed completely. Alternatively, it could be replaced with something like "syntactically/stylistically Go today is roughly the same, but the tooling and semantic additions make it feel much nicer to use." This doesn't make sense. Saying that it's rougly the same but has overall changed into something that feels different in practice doesn't mean much to me. This sentence could be removed completely.
Alternatively, it could be replaced with something like "syntactically/stylistically Go today is roughly the same, but the tooling and semantic additions make it feel much nicer to use."
|
||||
|
||||
* The compiler rewrite in Go
|
||||
* Go modules
|
||||
|
@ -27,11 +26,11 @@ today. Without having met the people I did in the Go slack, I would probably not
|
|||
have gotten as lucky as I have as consistently as I have.
|
||||
|
||||
Releasing a "Go 2" has become a philosophical and political challenge due to the
|
||||
forces that be. "Go 2" has kind of gotten the feeling of “this is never going to
|
||||
happen, is it?” with how the political forces within and without the Go team are
|
||||
forces that be. "Go 2" has kind of gotten the feeling of "this is never going to
|
||||
happen, is it?" with how the political forces within and without the Go team are
|
||||
openskies
commented
I dare you to make a "Go 2 Considered Harmful" pun. I dare you to make a "Go 2 Considered Harmful" pun.
|
||||
functioning. They seem to have been incrementally releasing new features and
|
||||
using version gating in `go.mod` to make it easier on people instead of a big
|
||||
semver-breaking release.
|
||||
release with breaking changes all over the standard library.
|
||||
|
||||
cadey marked this conversation as resolved
openskies
commented
define "semver-breaking" According to semver, the only thing you need to increment a major version for is for the removal of public API features. For example, in Go making something that was previously valid code invalid code. Until that happens, semver doesn't actually require naming it Go 2. In fact, naming it Go 2 would be a misstep in semver unless it has such a breaking change. define "semver-breaking"
According to semver, the only thing you need to increment a major version for is for the removal of public API features. For example, in Go making something that was previously valid code invalid code.
Until that happens, semver doesn't actually require naming it Go 2. In fact, naming it Go 2 would be a misstep in semver unless it has such a breaking change.
|
||||
This is pretty great and I am well in favour of this approach, but with all of
|
||||
the changes that have built up there really should be a Go 2 by this point. If
|
||||
|
@ -41,15 +40,16 @@ only to make no significant changes and tag what we have today as Go 2.
|
|||
of salt the size of east Texas. I am not an expert in programming language
|
||||
design and I do not pretend to be one on TV. I am also not a member of the Go
|
||||
team nor do I pretend to be one or see myself becoming one in the
|
||||
future. <br /><br />If you are on the Go team and think that something I said
|
||||
here was observably wrong, please [contact me](/contact) so I can correct it. I
|
||||
future.<br /><br />If you are on the Go team and think that something I said
|
||||
here is demonstrably wrong, please [contact me](/contact) so I can correct it. I
|
||||
have tried to contain my personal feelings or observations about things to these
|
||||
cadey marked this conversation as resolved
openskies
commented
observably, objectively, demonstrably. This is probably not quite the right word for the connotation you wanted here. observably, objectively, demonstrably.
This is probably not quite the right word for the connotation you wanted here.
|
||||
conversation snippets.</xeblog-conv>
|
||||
|
||||
This is a look back at the huge progress that has been made since Go 1 released
|
||||
and what I'd consider to be the headline features of Go 2. Most of this is a
|
||||
whirlwind tour of over a half-decade of improvments to the Go compiler, toolchain
|
||||
and standard library. I highly encourage you read this fairly large post in chunks
|
||||
and what I'd consider to be the headline features of Go 2.
|
||||
This is a whirlwind tour of the huge progress in improvement to the Go compiler,
|
||||
toolchain, and standard library, including what I'd consider to be the headline
|
||||
openskies
commented
Combine these two sentences. Example This is a whirlwind tour of the huge progress in improvement to the Go compiler, toolchain, and standard library, including what I'd consider to be the headline features of Go 2 Combine these two sentences. Example
This is a whirlwind tour of the huge progress in improvement to the Go compiler, toolchain, and standard library, including what I'd consider to be the headline features of Go 2
|
||||
features of Go 2. I highly encourage you read this fairly large post in chunks
|
||||
because it will feel like _a lot_ if you read it all at once.
|
||||
|
||||
## The Compiler Rewrite in Go
|
||||
|
@ -59,9 +59,9 @@ team has a background in Plan 9 and C was its lingua franca. However as a result
|
|||
of either it being written in C or the design around all the tools it was
|
||||
shelling out to, it wasn’t easy to cross compile Go programs. If you were
|
||||
building windows programs on a Mac you needed to do a separate install of Go
|
||||
from source with other targets enabled. This worked, it wasn’t the default
|
||||
though and eventually the Go compiler rewrite in Go changed this so that Go
|
||||
could cross compile natively with no effort required.
|
||||
from source with other targets enabled. This worked, but it wasn’t the default
|
||||
openskies
commented
s/This worked, it wasn’t the default though/This worked, but it wasn't the default/ s/This worked, it wasn’t the default though/This worked, but it wasn't the default/
|
||||
and eventually the Go compiler rewrite in Go changed this so that Go could cross
|
||||
compile natively with no extra effort required.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">This has been such an amazingly productive
|
||||
part of the Go toolchain that I was shocked that Go didn’t have this out of the
|
||||
|
@ -70,6 +70,13 @@ point where Go didn’t have the easy to use cross-compiling superpower it
|
|||
currently has, and I think that is a more sure marker of success than anything
|
||||
else.</xeblog-conv>
|
||||
|
||||
<xeblog-conv name="Mara" mood="happy">The cross compliation powers are why
|
||||
Tailscale uses Go so extensively throughout its core product. Every Tailscale
|
||||
client is built on the same Go source tree and everything is in lockstep with
|
||||
eachother, provided people actually update their apps. This kind of thing would
|
||||
be at the least impossible or at the most very difficult in other languages like
|
||||
Rust or C++.</xeblog-conv>
|
||||
|
||||
This one feature is probably at the heart of more CI flows, debian package
|
||||
releases and other workflows than we can know. It's really hard to understate
|
||||
how simple this kind of thing makes distributing software for other
|
||||
|
@ -105,19 +112,19 @@ time.</xeblog-conv>
|
|||
## Go Modules
|
||||
|
||||
In Go's dependency model, you have a folder that contains all your Go code
|
||||
called the GOPATH. The GOPATH has a few top level folders that have a well-known
|
||||
meaning in the Go ecosystem:
|
||||
called the `GOPATH`. The `GOPATH` has a few top level folders that have a
|
||||
well-known meaning in the Go ecosystem:
|
||||
|
||||
* bin: binary files made by `go install` or `go get` go here
|
||||
* pkg: intermediate compiler state goes here
|
||||
* src: Go packages go here
|
||||
|
||||
GOPATH has one major advantage: it is ruthlessly easy to understand the
|
||||
`GOPATH` has one major advantage: it is ruthlessly easy to understand the
|
||||
correlation between the packages you import in your code to their locations on
|
||||
disk.
|
||||
|
||||
If you need to see what `within.website/ln` is doing, you go to
|
||||
GOPATH/src/within.website/ln. The files you are looking for are somewhere in
|
||||
`GOPATH/src/within.website/ln`. The files you are looking for are somewhere in
|
||||
there. You don’t have to really understand how the package manager works (mostly
|
||||
because there isn’t one). If you want to hack something up you just go to the
|
||||
folder and add the changes you want to see.
|
||||
|
@ -169,7 +176,7 @@ choice that people really wanted solid guidance and defaults on. After a while
|
|||
they changed this to default to `~/go` (with an easy to use command to influence
|
||||
the defaults without having to set an environment variable). I don't personally
|
||||
understand the arguments people have for wanting to keep their home directory
|
||||
"clean", but the arguments are valid regardless.</xeblog-conv>
|
||||
"clean", but their preferences are valid regardless.</xeblog-conv>
|
||||
|
||||
Overall I think GOPATH was a net good thing for Go. It had its downsides, but as
|
||||
far as these things go it was a very opinionated place to start from. This is
|
||||
|
@ -197,11 +204,11 @@ such repository hosting sites.
|
|||
The main disconnect between importing from a GOPATH monorepo and a Go library
|
||||
off of GitHub is that when you import from a monorepo with a GOPATH in it, you
|
||||
need to be sure to import the repository path and not the path used inside the
|
||||
repository. This sounds weird but this is the difference between importing
|
||||
`github.com/Xe/x/src/github.com/Xe/x/markov` and `github.com/Xe/x/markov`. This
|
||||
means that things need to be extracted _out of_ monorepos and reformatted into
|
||||
“flat” repos so that you can only grab the one package you need. This became
|
||||
tedious in practice.
|
||||
repository. This sounds weird but this means you'd import
|
||||
`github.com/Xe/x/src/github.com/Xe/x/markov` instead of
|
||||
`github.com/Xe/x/markov`. This means that things need to be extracted _out of_
|
||||
monorepos and reformatted into "flat" repos so that you can only grab the one
|
||||
package you need. This became tedious in practice.
|
||||
|
||||
In Go 1.5 (the one where they rewrote the compiler in Go) they added support for
|
||||
[vendoring code into your
|
||||
|
@ -317,10 +324,14 @@ dependencies in it. It allows you to have `within.website/ln@v0.7` and
|
|||
`within.website/ln@0.9` as dependencies for _two different projects_ without
|
||||
having to vendor source code or do advanced GOPATH manipulation between
|
||||
cadey marked this conversation as resolved
openskies
commented
You didn't set up/foreshadow this connection well enough. cryptographic checksumming alone doesn't mean phoning home, and you don't explain how that avoids shelling out to git, or what the go module proxy is. This shouldn't be a big explanation, just like one missing sentence or a couple transitional phrases. You didn't set up/foreshadow this connection well enough.
cryptographic checksumming alone doesn't mean phoning home, and you don't explain how that avoids shelling out to git, or what the go module proxy is. This shouldn't be a big explanation, just like one missing sentence or a couple transitional phrases.
|
||||
projects. It also adds cryptographic checksumming for each Go module that you
|
||||
download from the internet. This allows you to avoid having to shell out to
|
||||
`git` every time you fetch a module that someone else has fetched before.
|
||||
Companies could run their own Go module proxy and then use that to provide
|
||||
offline access to Go code fetched from the internet.
|
||||
download from the internet, so that you can be sure the code wasn't tampered
|
||||
with in-flight. They also created a cryptographic checksum comparison server so
|
||||
that you could ask a third party to validate what it thinks the checksum is so
|
||||
you can be sure that the code isn't tampered with on the maintainer's side. This
|
||||
also allows you to avoid having to shell out to `git` every time you fetch a
|
||||
module that someone else has fetched before. Companies could run their own Go
|
||||
module proxy and then use that to provide offline access to Go code fetched from
|
||||
the internet.
|
||||
|
||||
<xeblog-conv name="Mara" mood="hmm">Wait, couldn't this allow Google to see the
|
||||
source code of all of your Go dependencies? How would this intersect with
|
||||
|
@ -332,10 +343,9 @@ disadvantages out of the gate with Go modules. I think that in practice the
|
|||
disadvantages are limited, but still the fact that it defaults to phoning home
|
||||
to Google every time you run a Go build without all the dependencies present
|
||||
locally is kind of questionable. They did make up for this with the checksum
|
||||
verification database a little, but it's still kinda sus.
|
||||
|
||||
I'm not aware of any companies I've worked at running their own internal Go
|
||||
module caching servers, but I ran my own for a very long time.</xeblog-conv>
|
||||
verification database a little, but it's still kinda sus.<br /><br />I'm not
|
||||
aware of any companies I've worked at running their own internal Go module
|
||||
caching servers, but I ran my own for a very long time.</xeblog-conv>
|
||||
|
||||
The earliest version of Go modules basically was a glorified `vendor` folder
|
||||
manager named `vgo`. This worked out amazingly well and probably made
|
||||
|
@ -401,10 +411,10 @@ Semantic Import Versioning has always been a part of Go modules and the Go team
|
|||
is now refusing to budge on this.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="coffee">My suggestion to people is to never
|
||||
release a version `1.x.x` of a Go project to avoid the “v2 landmine”. The Go
|
||||
release a version `1.x.x` of a Go project to avoid the "v2 landmine". The Go
|
||||
team claims that the right bit of tooling can help ease the pain, but this
|
||||
tooling never really made it out into the public. I bet it works great inside
|
||||
google3 though!</xeblog-conv>
|
||||
Google's internal monorepo though!</xeblog-conv>
|
||||
|
||||
When you were upgrading a Go project that already hit major version 2 or
|
||||
higher to Go modules, adopting Go modules forced maintainers to make another
|
||||
|
@ -436,7 +446,7 @@ could have two versions of the same C functions try to be linked in and this
|
|||
really just does not work.</xeblog-conv>
|
||||
|
||||
Overall though, Go modules has been a net positive for the community and for
|
||||
people wanting to create reliable software in Go. It’s just such a big semantic
|
||||
people wanting to create reliable software in Go. It’s just such a big semantics
|
||||
break in how the toolchain works that I almost think it would have been easier
|
||||
for the to accept if _that_ was Go 2. Especially since the semantic of how the
|
||||
toolchain worked changed so much.
|
||||
|
@ -614,8 +624,7 @@ that would normally be compile time errors into runtime errors.
|
|||
<xeblog-conv name="Cadey" mood="coffee">I say this as someone who maintains a
|
||||
library that uses contexts to store [contextually relevant log
|
||||
fields](https://pkg.go.dev/within.website/ln) as a way to make logs easier to
|
||||
correlate between.
|
||||
Arguably you could make the case that people are misusing the
|
||||
correlate between.<br /><br />Arguably you could make the case that people are misusing the
|
||||
tool and of course this is what will happen when you do that but I don't know if
|
||||
this is really the right thing to tell people.</xeblog-conv>
|
||||
|
||||
|
@ -629,13 +638,11 @@ really neat if contexts could be goroutine-level globals so you didn’t have to
|
|||
one of the major arguments I remember hearing against them was that contexts
|
||||
"polluted" their function definitions and callsites. I can't disagree with this
|
||||
sentiment, at some level it really does look like contexts propagate "virally"
|
||||
throughout a codebase.
|
||||
|
||||
I think that the net improvements to reliability and understandability of how
|
||||
things get stopped do make up for this though. Instead of a bunch of separate
|
||||
ways to cancel work in each individual library you have the best practice in
|
||||
the standard library. Having contexts around makes it a lot harder to "leak"
|
||||
goroutines on accident.</xeblog-conv>
|
||||
throughout a codebase.<br /><br />I think that the net improvements to
|
||||
reliability and understandability of how things get stopped do make up for this
|
||||
though. Instead of a bunch of separate ways to cancel work in each individual
|
||||
library you have the best practice in the standard library. Having contexts
|
||||
around makes it a lot harder to "leak" goroutines on accident.</xeblog-conv>
|
||||
|
||||
## Generics
|
||||
|
||||
|
|
s/I started using Go so long ago/then/
s/I started using Go so long ago/then/