It's My Project And I Cry If I Want To • The Applied Go Weekly Newsletter 2024-09-08
Your weekly source of Go news, tips, and projects
Contrary to my usual habits, I decided to include two projects in the Featured section that are the results of great personal dedication and persistence. They caught my eye as they are perfect examples of successful, non-trivial projects a single person can pull off.
These two projects are only two exemplars from a sea of open-source projects started by a single person who invested a ton of blood, sweat and tears (hence the email subject (*)) to help make the (Go) world a bit better.
((*) The email subject alludes to the 1965 song "It's my Party" by Lesley Gore.)
Featured articles
Database Transactions in Go with Layered Architecture | Three Dots Labs blog
Transactions are the mutexes of the database world. While your app might write to a database in a strictly serialized way, remember that other processes can concurrently write to the same table.
Transactions lock records for updating. And like mutexes, transactions can do fine-grained or coarse-grained locking, so choose your transaction strategy carefully.
Join Miłosz Smółka on driving the Transaction Route 101.
Telemetry in Go 1.23 and beyond
Go toolchain telemetry FTW! It's transparent, privacy-first, unobtrusive, and... actually useful! According to Robert Findley, "The most surprising aspect of the bugs coming from telemetry was how many of them were real."
Testing in Golang - a crash article to get you going - TheDeveloperCafe
Better read a crash article than crash your app! All you need to know about testing to get your tests up and running.
[security] Go 1.23.1 and Go 1.22.7 are released
Security updates for go/parser
, encoding/gob
, and go/build/constraint
.
Projects of the Week
(The ones I wrote about in the intro!)
Tunalog
Proudly finished after two years of side-hustling on this project: A minimalist but all-in-one blogging station.
GitHub - ariasql/ariasql: The AriaSQL relational database management system.
A pure-Go SQL database, handmade with love.
Podcast corner
Do Androids Dream of Electric Gophers? New Go releases & interview with Elliott Minns
Jonathan and Shay are back from vacation and are joined by Elliott Minns from the Dreams of Code YT channel.
Spotlight: How to use errors with iterator functions
The new iterator function feature in Go 1.23 lets you easily write a type that a range
loop can iterate over.
However, what if the iteration may fail for some reason? Consider the following example. Assume you want to write an audio player library that lets clients provide a playlist and a list of indices to play from that playlist. Since you have no control over the contents of the list of indices, you need to check each index. If an index is outside the bounds of the playlist, the loop should stop with an error.
The iterator function that the range
operator accepts do not return errors. So how can the loop error out?
Below is a standard implementation of the scenario, with no error handling. Note that the iterator function All()
checks the index but cannot return an error.
type Song struct {
Title string
Artist string
}
type Playlist struct {
list []Song
indices []int
}
func (p *Playlist) All(yield func(int, Song) bool) {
for _, index := range p.indices {
if index < 0 || index >= len(p.list) {
break // we can only break the loop, but not return any error!
}
song := p.list[index]
if !yield(index, song) {
break
}
}
}
func (ps *Playlist) Err() error {
return ps.err
}
func main() {
playlist := []Song{
{"As It Was", "Harry Styles"},
{"Anti-Hero", "Taylor Swift"},
{"Shape of You", "Ed Sheeran"},
{"Blinding Lights", "The Weeknd"},
{"Bad Guy", "Billie Eilish"},
}
indices := []int{0, 2, 4, 6, 1}
play := &Playlist{list: playlist, indices: indices}
for index, song := range play.All {
fmt.Printf("Now playing: %d – %s by %s\n", index, song.Title, song.Artist)
}
}
If you run this code, the range
loop ends after Shape of You, because index 6 is outside the bounds of the playlist. Yet, you cannot tell from the result if the player finished the playlist or if an error occurred.
In a golang-nuts thread, someone suggested to implement error handling in the style of bufio.Scanner
, that uses a separate Err()
method to check for success or failure:
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
```
Can we add this to the playlist iterator? Nothing easier than that!
First, add an err field to the Playlist struct:
```go
type Playlist struct {
list []Song
indices []int
err error
}
Next, when checking the index, set the error before breaking the loop:
if index < 0 || index >= len(p.list) {
p.err = fmt.Errorf("invalid index: %d", index)
break
}
Finally, the loop user can check the error after the loop finishes:
for index, song := range play.All {
fmt.Printf("Now playing: %d – %s by %s\n", index, song.Title, song.Artist)
}
if err := play.Err(); err != nil {
fmt.Printf("Playlist error: %v\n", err)
}
Find the full code in the Go Playground.
Of course, this is not the only option.
For example, if you don't need the index, you can use one of the yield
function's parameters to hold an error.
In a nutshell:
Change All()
to yield the current song and an error:
func (p *Playlist) All(yield func(Song, error) bool) {
for _, index := range p.indices {
if index < 0 || index >= len(p.list) {
yield(Song{}, fmt.Errorf("Index out of range: %d", index))
break
}
song := p.list[index]
if !yield(song, nil) {
break
}
}
}
Then change the range
loop to this:
for song, err := range play.All {
if err != nil {
fmt.Printf("Cannot continue: %v\n", err)
break
}
fmt.Printf("Now playing: %s by %s\n", song.Title, song.Artist)
}
(Full code in the Playground.)
Of course, this only works if the iterator returns only one value.
If you want to yield two values but don't like the bufio.Scanner
-style solution, you can bake the error into the return value:
type Song struct {
Title string
Artist string
Err error
}
// ...
for index, song := range play.All {
if song.Err != nil { ... }
// ...
}
These are just three options of smuggling error handling into the range-over-func mechanism. You will certainly find more variants if you drop the requirement of being compatible with the range
operator.
Quote of the Week: Magnifier
AI isn't a thing; it's a magnifier of a thing. And that thing is human creativity.
More articles, videos, talks
Don’t Log, Return Errors. I recently worked with a Go package… | by Benjamin Cane | Aug, 2024 | ITNEXT
Don't log errors in library packages. Or rather, don't do it poorly.
Shallow vs Deep Copying in Go - YouTube
When you copy values, what comes with the copy and what is left behind? Adib Hanna takes you through the depths of copying.
Slices in Go: Grow Big or Go Home
So, has startup mentality finally arrived in Go? Fortunately not. It's just a deep dive on how slices grow (and why you should care). – By Phuong Le.
The differences between "Type Alias" and "New Types" in Go
Go newcomers might stumble over the subtle visual difference between type ID = string
and type ID string
. After reading this article, not anymore.
Exploring Goja: A Golang JavaScript Runtime
Do you think about embedding a scripting language into your app? JT Archie decided for Goja, a Javascript runtime, mostly because of its seamless integration with Go structs.
Projects
Libraries
GitHub - zolstein/type-walk: Fast reflection for mere mortals
Self-improvement strategies for the impatient? No, we're talking about runtime reflection mechanisms. Go's standard reflection tends to produce a lot of allocations, hence garabage to collect. This experimental package aims at reducing allcoations by memoizing (vulgo: caching) previous reflection results.
GitHub - wneessen/niljson: A simple Go package for (un-)marshalling null-able JSON types
Handle nullable JSON data without pointers.
Tools and applications
GitHub - DerTimonius/twkb: A kanban TUI for taskwarrior, written in Go
Taskwarrior is a CLI TODO manager, yet it lacks a Kanban view... not anymore! twkb
fills the gap, and also made another Gopher fall in love with Charm's CLI toolset (Bubbletea and friends).
GitHub - mainak55512/stto: Simple line of code counter written in Go
Counting lines of code is a terrible productivity metric, but great for getting an idea of the accumulated tech debt! This tool counts locs quite fast indeed.
GitHub - ShimmyTheDev/go-mongodb-docker-api-stack: A ready-to-go Go, Mongo, MinIO and grafana api/application stack
Want to escape the cloud? Run your own! This stack helps you escape from Heroku, Amazon S3, and MongoDB Atlas.
GitHub - LeperGnome/bt: Interactive tree-like terminal file manager
If you dislike column-based TUI file managers (like the author does), maybe this one is for you.
Completely unrelated to Go
An Ode to Logging
Logging, seen through the eyes of a poet.
Why don't log files read that way?
Reasons to write design docs
So you can't be bothered with writing design docs? Here are five reasons that will change your mind.
Why Not Just Use …?
Yeah, ok, I get it. But one question remains... Why not just use Go?
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