A Picture Is Worth More Than 20 Lines Of Code • The Applied Go Weekly Newsletter 2025-05-18
Your weekly source of Go news, tips, and projects
A Picture Is Worth More Than 20 Lines Of Code
Hi ,
I'm sure you've been through this one or more times: You try to explain something. You have a clear picture in your mind but words fail to describe it accurately. There is no other way than getting that picture from your head onto a sheet of paper. Or into the Go playground.
Yes, the Go playground can output images, not just text. There is a little-known trick to accomplish this, which I reveal in this issue's Spotlight.
Happy pixelizing!
–Christoph
Featured articles
Centralize HTTP Error Handling in Go | Alexis Bouchez's personal website
When you realize you're writing HTTP error handling boilerplate all over your handlers, it's time to try another approach—like the one Alexis Bouchez describes.
Map with Expiration in Go
So you need an in-memory cache? No problem, set up Redis, add it to an (already large) k8s config YAML, write code to send and receive data, set up monitoring to take action if the Redis instance gets down, etc etc etc...
Or, simply write a "forgetful" map in a few dozen lines of code and forget about all the infrastructure stuff.
Go Scheduler
A deep exploration of the Go scheduler, probably deeper than you ever wanted to dig into that topic.
Podcast corner
No Silver Bullet: Watermill: from a hobby project to 8k stars on GitHub
Miłosz and Robert share the story of their event-driven library Watermill.
Cup o' Go: Thanks, Ian. 🙏 Plus Kevin Hoffman talks about empathy and the joy of logging ⚡
Ooo—my Spotlight Security Habits That Matter Most is discussed on Cup o' Go! ❤️ (I love Shay's mental image of angry customers coming with pitchforks after the poor dev who neglected security...)
Jonathan and Shay also wave goodbye to Ian Lance Taylor and interview Kevin Hoffman, founder and CEO of IT Lightning, the company behind SparkLogs.com.
Fallthrough: A Phoenix's Path to Principal
Not the phoenix you might think of (you know, this mystic bird that can burn itself and get reborn from its ashes). Rather, Evan Phoenix is the guest of this episode,talking about his journey from coding on a TI calculator to becoming a prominent open-source developer and entrepreneur.
Spotlight: Pixel perfect: How to display images in the Go Playground
In the previous issue, I shared demo code for Tupper's Formula, a formula that can generate an image of itself (and virtually anything that can be shown as a 17x106 black-and-white image). The code prints the image as Unicode blocks to stdout, because every code running in the Go Playground prints results as strings to stdout, right?
Well, not quite. The Go Playground can render images, albeit with a trick. I'll explain this with the Tupper code from the previous issue. After calculating the 17x106 bitmap matrix, the code printed the matrix like so:
bmap := tupperMatrix(k)
for _, line := range bmap {
for _, c := range line {
if c {
fmt.Print("█") // Unicode block character
} else {
fmt.Print(" ")
}
}
fmt.Println()
}
The output doesn't look very nice, though. The "image" is distorted because the block character is much taller than it is wide, and furthermore, there is space between adjacent characters and lines.
Time to fix this! A little-known fact is that the playground can render images of type image.Image
. Since the only available output is text output via fmt.Print/ln/f
, the playground implements a trick: Output that begins with the string IMAGE:
is interpreted as a base64-encoded .png
image. So for printing out an image.Image
, all we need to do is to:
- Encode the
image.Image
as a PNG using `image/png.Encode()`` - Printing a string that starts with "IMAGE:" and continues with a base64 encoding of the PNG image.
Here is a straightforward implementation:
func displayImage(m image.Image) {
var buf bytes.Buffer
if err := png.Encode(&buf, m); err != nil {
panic(err)
}
fmt.Println("IMAGE:" + base64.StdEncoding.EncodeToString(buf.Bytes()))
}
This is a "more-high-level" version of ShowImage in package golang.org/x/tour/pic
.
The next step is to turn our Tupper matrix into an image.Image
. As an extra feature, let's add a scaling factor to enlarge the image because if printed 1:1, the image is really tiny!
We need to change func main()
after calling tupperMatrix()
. Function tupperMatrix()
can remain completely unchanged, by the way.
First, create an RGBA image of the matrix' dimensions, each dimension multiplied by the scale factor.
Then, replace the nested print loop with a nested loop that fills each pixel with the color black or white, depending on the Tupper matrix' boolean value.
Finally, call displayImage()
with the resulting image.
bmap := tupperMatrix(k)
img := image.NewRGBA(image.Rect(0, 0, 106, 17))
for y := 0; y < 17; y++ {
for x := 0; x < 106; x++ {
if bmap[y][x] {
img.Set(x, y, color.Black)
} else {
img.Set(x, y, color.White)
}
}
}
}
}
displayImage(img)
There is just one slight drawback: The resulting image is tiny. But no worries, a few more lines help inflate it to any size you like.
bmap := tupperMatrix(k)
scale := 3 // Adjust for larger/smaller output (e.g., 2 = 2x2 pixels per original pixel)
width := 106 * scale
height := 17 * scale
img := image.NewRGBA(image.Rect(0, 0, width, height))
for yOrig := 0; yOrig < 17; yOrig++ {
for xOrig := 0; xOrig < 106; xOrig++ {
for yScaled := 0; yScaled < scale; yScaled++ {
for xScaled := 0; xScaled < scale; xScaled++ {
x := xOrig*scale + xScaled
y := yOrig*scale + yScaled
if bmap[yOrig][xOrig] {
img.Set(x, y, color.Black)
} else {
img.Set(x, y, color.White)
}
}
}
}
}
displayImage(img)
Run this code in the playground and get Tupper's rendered as a nice image:
Much better than the ASCII art graphic, isn't it?
Quote of the Week: Two Things
Life comes down to two things:
Knowing how to get what you want
Knowing what’s worth wanting
More articles, videos, talks
Leaving Google – Airs – Ian Lance Taylor
Ian Lance Taylor, a long-term member of the Go core team, has left Google and is taking a break from contributing to Go. I remember him as a very active and helpful contributor to the golang-nuts
email list, Go issues on GitHub, and other places on the web.
All the best, Ian. Hoping to see you back on the Go project at some point in the future!
Using the OpenAI Responses API in Go (Golang) – Intro Guide
Frankly, I wouldn't bind my Go code to a particular LLM vendor's API; I'd rather use a generic package like LangChainGo and connect to the providers of my choice, but if you need specific features of the OpenAI Responses API in your Go app, here is the post to get your code up and running.
Looking back at oapi-codegen
's last year · Jamie Tanna | Software Engineer
oapi-codegen
, a popular OpenAPI package, made some decent progress during the last year. Jamie Tanna takes a recap and is looking for sponsorship.
How I Work With PostgreSQL in Go | Alexis Bouchez's personal website
Adding a PostgreSQL DB to a Go project is more than just "use database/sql
with the postgres driver" and call it a day. Alexis Bouchez lists all the things to take care of: Connection pooling, migration management, creating a consistent development environment, organizing DB access, writing queries, and seeding the DB.
Dot file hiding file server
Novus and his mentor, Vetus, explore how to write a file server that hides dot files from site visitors. On the way, Novus learns how interface embedding works.
Projects
Libraries
GitHub - MonsieurTib/keyed-semaphore: A Go library providing context-aware semaphores where concurrency limits are applied per unique arbitrary key, enabling fine-grained resource locking.
Unlike standard semaphores, keyed_semaphore
semaphores limit access to resources by keys, such as user ID or resource ID, rather than just globally.
GitHub - stanNthe5/stringbuf: A Go string concatenation library that is more efficient than strings.Builder.
stringbuf
is faster than string.Builder
because it defers the actual string concatenation (which involves copying data) until calling String()
or Bytes()
.
Tools and applications
GitHub - webriots/rate: A high-performance rate limiting library for Go applications
While golang.org/x/time/rate
is a single-instance rate limiter, webriots/rate
aims to be a simpler rate limiter but suitable to run millions of instances of it.
GitHub - lzap/gobump: Pins Go version when bumping dependencies
Some software vendors, especially in an enterprise context, don't want to automatically upgrade their project to the latest Go version; they'd rather stick with an older version and install processes to apply (security) fixes on top of the pinned version. This tool helps such vendors updating dependencies without bumping the Go version in go.mod
.
GitHub - isaacphi/mcp-language-server: mcp-language-server gives MCP enabled clients access semantic tools like get definition, references, rename, and diagnostics.
I can't summarize it better than the author: "mcp-language-server helps MCP enabled clients navigate codebases more easily by giving them access semantic tools like get definition, references, rename, and diagnostics."
So, for example, your MCP agent could connect an LLM with gopls
to give it tools like "Go to definition" etc.
Completely unrelated to Go
5 Tips to Productionize Your Prototype
If you have an egg, you have a meal.
If you have a prototype, you have a product ... NOT!

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