The Applied Go Weekly Newsletter logo

The Applied Go Weekly Newsletter

Subscribe
Archives
August 18, 2024

One, two, three • The Applied Go Weekly Newsletter 2024-08-18

AppliedGoNewsletterHeader640.png

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.

–Christoffer Stjernlöf

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.

Check it out.


Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany

Don't miss what's next. Subscribe to The Applied Go Weekly Newsletter:
LinkedIn
Powered by Buttondown, the easiest way to start and grow your newsletter.