This is something seldom attempted, but I congratulate you. Go is one of a few languages that really is batteries-included. Just about anything you could need is included in the stdlib.
https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-...
Not to mention nothing prevents anyone from using or writing their own library only for the parts that need specialization. You're free to do that and many have.
And standard libraries can be versioned and deprecated too.
The time API, on the other hand, is that bad, and worse. Besides the bizarre monotonic time implementation, there's also the bloated size of the time.Time struct, and the lack of actual "dates" (YYYY-MM-DD) and "times" (HH:MM:SS) that you can do arithmetic on. You can't really roll your own robustly either because time.Time isn't a great foundation to build on and //go:linkname is getting locked down.
Thankfully, build constraints are much better now, since they just use regular boolean operators, e.g.:
//go:build windows && (i386 || amd64)
I agree that there shouldn't be any _buildtag.go magic, and I think they ought to remove that "feature" entirely in a future version of Go (which can be done so that it doesn't affect older or unversioned code). It seems they added a "unix" build tag too.Also, one of my personal gripes is that the standard library exposes no guaranteed way to access the system CSPRNG. Any code can replace (crypto/rand).Reader with another implementation and compromise cryptographic operations. It's a trivial supply-chain attack vector, and even in non-malicious scenarios, it can be done mistakenly and break things all over the place in a subtle but dangerous way. The language developers have so far refused to fix it too.
Then there's log/slog with no TRACE or FATAL levels built-in; yeah, you can roll your own levels, but why should you have to?
Some of the above will never be in Go due to how the community and language designers are philosophically against them.
It would have been interesting if the author had a suggestion on what the Golang team should've / could've done instead, beyond correctly communicating the nature of the breaking change in the Go 1.9 release notes.
It's been a while since I played with the furry thing but is that even possible in Golang?
Eg I don’t find the stdlib logging library particularly great; not bad, but not impressive. Ditto for the stdlib errors package before they added error wrapping
In Go you can naturally do it, by using the manual constructor approach, however there is no magic auto wiring like you can do with attributes and compiler plugins, plus standard libraries infrastructure for locating services, from those three ecosystems above.
If your Go version doesn't know of such a build tag as "bar", then foo_bar.go is unconditionally compiled. If Go in a later version adds "bar" as a known build tag, then foo_bar.go becomes conditionally compiled. Better hope you know this is how things work (reality: lots of Go devs don't).
Build tag lines don't have this problem. They always specify compilation conditions, even if the build tag is not already known to the compiler. They also apply to the whole file, the same as _tag in the name; there's no preprocessor spaghetti possible.
However Go doesn't like magic, thus that isn't something that will ever happen on the standard library, like on Python, Java, .NET.
Build constraints with "//go:build" already exist, I'm not making them up or proposing something new: https://pkg.go.dev/go/build#hdr-Build_Constraints
This has nothing to do with preprocessor spaghetti, which is impossible in Go. Either a file is included or it is excluded. Neither with file naming nor "//go:build" can you cause only portions of a file to be compiled.
Really, the _tag.go mechanism is just a very simple kind of build constraint, equivalent to "//go:build tag". The problem is that it relies on a magic list of known build tags, and the contents of that list change over time. Apart from _test.go, which is a little too convenient to give up in my opinion, the rest of the tags could be pushed into build constraints, or at the very least, the list of known build tags could be frozen in its current state.
And if one goes back 20 years, constructor based injection was the norm, the magic only came later thanks to Aspect Oriented Programming, yet another tool that Go will never adopt.