One, two, three • The Applied Go Weekly Newsletter 2024-08-18
Your weekly source of Go news, tips, and projects
This week, I struggled with a codebase that I hadn't touched for a while. What a mess! My brains worked hard to reconstruct how all the parts work together, and why I made this decision over another back when I wrote that code.
But all the time, I realized that Go's direct and non-magic nature is such an invaluable advantage when dealing with unknown code—including old code written by myself. In other languages, I would have suffered from additional mental overhead from convoluted language constructs, pointless abstractions, and there-must-be-more-than-one-way-to-do-it "philosophies".
Go is simpler than most languages, and that's a good thing.
Yet, Go can be quite complex under the hood, as the articles about the testing harness, the execution tracer, the mutex internals, and a runtime crash prove.
But first: three... two... one...
Go One-Two-Three: My Favorite Features of Go Release 1.23
Go 1.23 is out.
Since so many articles have been written about various new or improved features in Go 1.23, I decided to focus on my favorite changes and link out to relevant articles or documents.
So if you are looking for a particular blog or doc about a Go 1.23 feature, you can probably find it through my article :) (And if not: I am happy to add it.)
Go: How the Testing Harness Works
What happens when you run go test
? Sure, Go runs your tests. But under the hood, that's far from being easy and straightforward. Matt T. Proud loves to know how the tools work that he is working with, so he descended into the internals of go test
and discovered a mechanism that is "rather elegant".
GopherCon Europe 2024: Felix Geisendörfer - How to Win Frames and Influence Pointers @felixge - YouTube
In Go 1.21, the Go execution tracer went from 20% overhead down to a meager 1%. (Yay!) Felix Geisendörfer discusses how that immense speedup was achieved and what challenges the team faced.
Go structs are copied on assignment (and other things about Go I'd missed)
Julia Evans, of WizardZine fame, uses Go on an on/off basis. Now she collected a couple of peculiarities of Go that Go newcomers might stumble upon.
Podcast corner
Big shoes to fill
The previous week had two major news for the Go world and the developer world: (1) the changes at the top of the Go team, and (2) the StackOverflow Developer survey that revealed a significant decrease in contentment among devs. Kris, Angelica & Johnny discuss these news.
Cup O' Go
No new episode posted when this newsletter issue "went to press". I bet that at the time you read this, the new episode is on air.
Go tip of the week: It's time to switch!
Surely you know the "standard" way of branching into one of multiple code paths depending on a given value:
switch a {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
default:
fmt.Println("default")
}
That's how switch
works in Go and in many other languages (except that in Go, no fallthrough to subsequent cases happens).
But the switch
statement can do more. Here are a few variants.
1. Multiple values in a case
A case can list multiple values to match:
switch a {
case 1:
fmt.Println("1")
case 2, 3, 4:
fmt.Println("2, 3, or 4")
// case 1,2: // error: duplicate case 1, duplicate case 2
// fmt.Println("1 or 2")
}
A given value can only be used for one case block. Duplicate case values trigger an error.
2. An initializer like in a for loop
You may initialize a value before switching on it. The scope of a
is limited to the switch construct:
switch a := f(); a {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
}
3. No switch expression but case expressions
Cases are not restricted to static values. If you omit the switch
expression, you can use expressions for each case
:
switch {
case a == 1:
fmt.Println("1")
case a >=2 && a <= 4:
fmt.Println("2")
case a <= 5:
fmt.Println("3")
}
If the current value of a
matches more than one case, the first matching case is chosen.
4. Switching on a variable's type
If your code receives an interface value from somewhere, a type switch can check the actual type of this value:
switch v := a.(type) {
case int:
fmt.Println("a is an int:", v)
case string, []byte:
fmt.Println("a is a string:", v)
}
5. Switching on a type parameter
This one may seem a bit esoteric: You can define a generic function where the type parameter is not used for the parameter list. Instead, a switch statement can refer to this parameter to check a parameter's value:
func do[T comparable](a any) {
switch v := a.(type) {
case int:
fmt.Println("a is an int:", v)
case T:
fmt.Printf("a is a %T: %v", v, v)
case []T:
fmt.Println("a is a slice:", v)
case []byte:
fmt.Println("a is a byte slice:", v)
}
}
func main() {
do[bool](a)
do[bool](true)
do[int]([]int{1, 2, 3})
}
As with case expressions, if the actual type of a
matches multiple cases, the first matching case is chosen.
(Play with all these options in the Go Playground.)
Switch your way of switching
With that many options, the switch
statement leaves little to desire. For more details, check the Switch statements section of the Go language reference.
Quote of the Week: Reliability
It is much easier to add features to reliable software, than it is to add reliability to featureful software.
More articles, videos, talks
A New Home for nhooyr/websocket - Coder
A heads-up for users of nhooyr/websocket
: The library is now maintained by Coder.com.
Golang Sync Mutex: Normal and Starvation Mode
Phuong Le looks under the hood of mutexes and inspects their anatomy, the mutex flow, and a mechanism to prevent goroutine starvation. As a "normal mutex user", you probably don't need to know mutexes in this deep detail, but it's super interesting!
An HTTP Server in Go From scratch
Build your own HTTP server in Go! Small caveat: You must not use net/http
but rather build all network communication and HTTP functionality from scratch.
Go is my hammer, and everything is a nail
May I kindly disagree ;-) Go is a Swiss army knife! (With a carefully selected set of blades, of course. Not like this one!
Author: '"Go is my spork and everything is spaghetti" would have made a great headline as well.'
Lock striping – tpaschalis – software, systems
Paschalis looked for a way to take advantage of the constant lookup time of hash data structures (the Go map datatype is one, for example), and ended up with using lock striping to find a suitable middle ground between too coarse-grained synchronization (such as, one lock for the entire map) that serializes access too much, and too fine-grained synchronization (such as locking each entry separately) that has quite some overhead.
HTTP/1.0 From Scratch
Remember the HTTP/0.9 From Scratch article? The series continues. Here is HTTP/1.0.
Emulating real dependencies in Integration Tests using Testcontainers | by Alex Pliutau
Alex Pliutau compares various options for running integration tests, which typically depend on external resources like databases. Spolier alert: testcontainers
is the best option.
Debugging a Go runtime crash: the one-instruction window
A public post-mortem of a bug hunt in the Go runtime. Nick Ripley explains how he encircled a bug that occurred only on 64-bit ARM, and only under certain circumstances.
Go 1.23 Iterators Tutorial
Elliot Forbes iterates through iterators. Yes, this pun is lame. No, I don't apologize.
Your Go version CI matrix might be wrong
"Go’s incredibly trigger happy when it comes to changing a go.mod's go version, which it will happily and silently do at any opportunity."—Brandur Leach observed that Go may misguide CI flows into upgrading the Go toolchain. Luckily, the remedy is trivial: set GOTOOLCHAIN=local
.
Projects
Libraries
goship.it
THe GoTH stack on steroids. Goship.it is a UI component library for GoTH (Go+Templ+HTMX) applications. It "contains DaisyUI components translated into Templ components that can be easily customized using both TailwindCSS and DaisyUI." As of this writing, the repo is private, and so you have to copy the code snippets right from the website.
GitHub - ssoready/ssoready: Open-source dev tools for enterprise SSO. Ship SAML support this afternoon.
SSO for your enterprise. An open source alternative to products like Auth0 or WorkOS.
Looking for help to port LibreCUDA in native Go
Want to bring Go and Machine Learning closer together? The authors of go-tensors
are looking for contributors.
GitHub - chanyeinthaw/kuroshiro.go: Go port of kuroshiro, a Japanese language library for converting Japanese sentence to Hiragana, Katakana or Romaji with furigana and okurigana modes supported.
I cannot imagine how it is to use more than one writing system. The Japanese language does have three of them, but forturnately, kuroshiro.go
helps to move between them.
GitHub - gluek/go-gds: Library to parse GDSII binary files written in Go
GDSII is a binary database file format for data exchange of integrated circuit or IC layout artwork, as Wikipedia helpfully explains.
GitHub - GopherML/bag: Bag of words as code
Claude summarizes "BoW" as: "The Bag of Words model represents text as a vector of word frequencies, disregarding grammar and order, to enable mathematical analysis of language data."
Or take this Explain-Like-I'm-Five description from GPT-4o: "Imagine you have a big box of LEGO bricks of different colors, and each color represents a word; the Bag of Words model is like counting how many bricks of each color you have in the box without caring about how they were put together to build something."
But if this package is for you, then you probably don't need an ELI5 summary anyway.
GitHub - manterfield/go-mapreader: mapreader is a tiny Golang library for accessing arbitrary keys from maps - especially useful when dealing with semi-unknown JSON payloads
The author wrote this library to solve a particular need: To manipulate a small portion of some JSON data while preserving the rest of the payload. A library with a more general approach is go-ard, but the author concluded that it does not seem to optimally support his particular use case.
GitHub - zitadel/passwap: Package passwap provides a unified implementation between different password hashing algorithms. It allows for easy swapping between algorithms, using the same API for all of them.
Do you use multiple password hashing algorithms? Fight the complexity with the One API That Rules Them All.
Go4lage - Free and Open Source Web Framework in Go
A quickstart template for web applciations. (Go4lage is a pun on the German word for template—"Vorlage".) Features include user management, an admin dashboard, and a backup system. The docs are still a work in progress, but the author ensures the code is easy to understand. And the project comes with an example app, a CV generator based on Google's Gemini LLM.
Tools and applications
GitHub - yznts/dsh: A set of command line database tools
Tired of firing up bulky Database IDEs for just checking a table or runing a quick query? This set of CLI commands puts your database at your fingertips.
GitHub - akkik04/Trace: POC for a real-time log monitoring solution, orchestrated as a distributed system
Observability is crucial for apps, especially for large ones, and especially for large, distributed, microservice-y ones. This is a proof of concept of a distributed log monitor.
Completely unrelated to Go
The Perils of Future-Coding
Future-coding, aka over-engineering, is the urge to think too much about possible future use cases when implementing a new feature. Chances are these possible future use cases never happen, but you may end up with hard-to-understand, hard-to-maintain software.
Picking glibc versions at runtime
C usually links dynamically, which means that a C binary has to load one or more libraries at startup. But what if you want to test a C binary with a different version of a library that what's installed on the system?
It turns out that the C world has a clever way of selecting a particular library version. You thus don't need a Docker container or other sophisticated isolation mechanisms.
You should make a new programming language
Aren't there enough programming languages on the planet already? Well, this is not about making a new language for the world but rather for you. Just for the sake of learning.
Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany