It's not complex enough yet! • The Applied Go Weekly Newsletter 2024-06-09
Your weekly source of Go news, tips, and projects
Complexity is everyone's favorite, right?
Of course not, but how come that systems, particularly software systems, always seem to tend towards increased complexity? Maybe it's a lack of planning or failure to manage organic growth. But maybe it's the innocent wish of adding new, shiny functionality to make this system the "Swiss army knife of <insert the system's category here>" that makes systems grow into complex, unmaintainable behemoths.
Complexity can be addressed. For example, by visualizing structures, like the tool GQuill
does (see the Projects section for the link). Or sometimes we should take a fresh start and intentionally strive for minimalism, as the web app generator Napp
does (also in the Projects section).
Another form of complexity can emerge from seemingly simple concepts, like goroutines and channels. As simple and straightforward the concept is, it can become a large mess of goroutines that send messages back and forth and around, and then somewhere deep inside a deadlock occurs, or worse, a more subtle flaw that does not even trigger an error but only breaks data. When concurrent programming feels like managing spaghetti code, it's time to consider more structured alternatives, like the one discussed in the first featured article below.
Complexity inevitably creeps in unless we constantly work on keeping our systems simple.
Always remember KISS—Keep It Simple, Stupid.
Structured concurrency in Go
Anton Okolelov considers the go
statement the goto
of today. In this article, he applies the principles of structured programming to concurrency.
Sentinel errors and errors.Is() slow your code down by 500%
Returning and handling errors can be slow—up to five times slower than returning and handling a boolean. Zach Musgrave presents detailed test results of various error handling methods.
Sentinel errors and errors.Is() slow your code down by 500%
GitHub - ryanolee/go-pot: A service for giving away secrets to bots ...Probably slightly too many!
Project of the week: Give hostile bots a warm welcome and feed them with fake secrets until they choke.
GitHub - ryanolee/go-pot: A service for giving away secrets to bots ...Probably slightly too many!
[security] Go 1.22.4 and Go 1.21.11 are released
New Go minor releases are available that fix security issues in archive/zip
and net/netip
.
[security] Go 1.22.4 and Go 1.21.11 are released
Erratum (*)
(*) Latin for "I messed something up last time, here's the correction."
In the last issue's Go Tip, the Caddyfile syntax contained an error (in two places). The reverse proxy directive, while spelled reverse-proxy
on the command line, must be spelled with an underscore in the Caddyfile: reverse_proxy
. Apologies if this created any confusion. (Fixed in the web version.)
Upcoming events
Europe (in a broader sense) can look forward to two Go conferences this summer: GopherCon EU and GopherCon UK.
GopherCon Europe 2024
From June 17th to 20th, the "Alte Münze" ("Old Coin") hosts the GopherCon Europe 2024 conference. Two workshops and two days of talks build a great frame for learning and connecting with others.
GopherCon UK 2024
GopherCon UK opens its doors in August, celebrating its 10-year anniversary. From August 14th to 16th, Gophers can meet in the Brewery, in the heart of London, to attend workshops and conferences. A great opportunity to engage with speakers, delegates, and fellow Gophers.
I am happy to provide you this special offer: With the coupon code appliedgo
, you can save 5% on the tickets for GopherCon UK.
Podcast corner
go podcast() 039: Go is now more fun to build web apps
Dominic St-Pierre is finally happy with building Web apps in Go, thanks to his template libary and sqlc
.
Cup o' Go | “I don't have money, but I do have a very particular set of skills connectors” — Ashley Jeffs
Benthos, the company behind the stream processing software of the same name, got acquired by Redpanda, a company offering a Kafka-compatible streaming data platform. Benthos is now called Redpanda Connect. Jonathan and Shay talks to Ashley Jeffs, author of Benthos, about the aquisition.
Go tip of the week: A demo-friendly Web server
Today, I installed a Web app from a repo, but when I started the app, I found that the demo code serves the web pages hard-coded on port 8080. This port was already occupied on my machine, so I had to grab into the code to set the port to 8081.
Then, the app ran fine and listened on port 8081, but the log output just said something like: "Listening on :8081".
I thought to myself, what if the app scans for a free port and then prints a clickable URL in the log output? I would then be able to run the demo without any obstacles.
If you write a web app and want to attract raving fans, you probably want your app to do these things, too.
And it's not that difficult. First, let a loop test if a port within a given port range is available. We can use a net.Listener
for this. The loop exits if a free port is found or if the search range is exhausted.
func findFreePort(start, end int) (net.Listener, int, error) {
for port := 8080; port <= 8180; port++ {
addr := fmt.Sprintf(":%d", port)
listener, err := net.Listen("tcp", addr)
if err == nil {
return listener, port, nil
}
log.Println(err)
}
return nil, 0, errors.New("No port available")
}
The HTTP server then can take the active listener to start serving pages on the port found.
func main() {
listener, port, err := findFreePort(8080, 8180)
if err != nil {
log.Fatalf("findFreePort: %v\n", err)
}
log.Printf("Starting server...")
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from port %d", port)
})
go func() {
err := http.Serve(listener, nil)
if err != nil {
log.Fatalf("Could not start server on port %d: %v", port, err)
}
}()
log.Printf("Server started. Open http://localhost:%d", port)
select {} // prevent that main() exits (quick and dirty solution)
}
(Full code here. Note that it does not run in the playground, due to deadlock issues in the sandbox. You can save the code to a local main.go
file and call go run main.go
to play with it.)
A sample output of this code could look like this:
> go run .
2024/06/07 14:41:13 listen tcp :8080: bind: address already in use
2024/06/07 14:41:13 listen tcp :8081: bind: address already in use
2024/06/07 14:41:13 Starting server...
2024/06/07 14:41:13 Server started. Open http://localhost:8082
Now the server runs on the first open port in the search range, and the log output contains a clickable link (if the terminal supports link detection). No more failing demo servers!
Quote of the week: To be run in production
Publicly available container images are very similar to USB drives you find in the parking lot. They are meant to be downloaded and run in production.
More articles, videos, talks
Golang. Memory limits for running in Kubernetes. | by Yuri Fenyuk | May, 2024 | Medium
Determining optimal memory limits for a Go app in a Kubernetes pod requires some experimentation. Yuri Fenyuk explains how to find a good balance between performance and memory usage.
Manage and Query SQL Views with GORM and Atlas | Atlas | Manage your database schema as code
SQL views are only partially supported by GORM. Until now.
Reading Google Sheets from a Go program
Google Sheets can be a great ad-hoc data source, or even a quick-and-dirty UI. Eli Bendersky shows how he gained access to a GSheet for pulling data.
Trying something new - feature designs
This somehow escaped my attention: Hasen Judi started a series of "design documents" to discuss the implementation of a hypothetical feature in Go. The latest post in this series is View Counters Design Document
Go: Don't name packages common nouns
An interesting take: Don't use common nouns for package names, says Brandur. Package names like "db", "config", "limit", "lock" easily get in conflict with variables of the same name. The solution: make the name a tad bit more uncommon. Add a prefix or postfix, or use a combined name in lowercase to get out of the way of camel-case variable names.
Announcing GoReleaser v2
Carlos Becker released v2 of the awesome Goreleaser tool. It's basically the same as v1.6.2, functionality-wise, but stripped of all legacy features, so v1 configuration may break.
A heads-up: "If you use our GitHub Action, the latest version (v6.0.0) should use ~> v2 by default if your version
option is either empty or latest
." So your GH action might inadvertently use v2 with an incompatible v1 config.
Error Flows in Go
Preslav Rachev gets sick of repeating prefixes in wrapped error messages. And rightly so.
Projects
Libraries
GitHub - destel/rill: Go concurrency with channel transformations, type safety, batching and error handling. No boilerplate
rill
is a high-level concurrency library that takes care of streaming, error handling, batching, and ordered processing.
GitHub - dstpierre/tpl: Library that helps make Go html/template more tolerable.
If you prefer pure HTML and html/template
over a-h/templ
, this library that helps with structuring, parsing, and rendering of html/template.
GitHub - AccentDesign/gcss: CSS written in Pure Go
Write CSS without writing CSS. This library is sort of an ORM for CSS, providing type safety and the familiar Go syntax for styling your web UI.
GitHub - instructor-ai/instructor-go
Validate structured LLM output, manage retries and streaming responses from OpenAI, Anthropic, Cohere, and local models.
GitHub - Phillip-England/go-quickstart: A thin layer over the standard http library to help improve routing, context, and middleware chaining
If you find a repeating pattern in your code across projects, write a library for it. go-quickstart
is a wrapper for net/http
that simplifies building common http server components.
GitHub - jazoom/simplereload: Small browser reload middleware for Go webservers. No dependencies.
wgo
makes your dev server restart on build changes, and simplereload
makes your dev server trigger a reload in the browser. No need to hit the reload button.
GitHub - ccbhj/gendsl: Highly customizable expression evaluation in Lisp like syntax for building DSL in a minute
Want to take a detour from Go into the Lisp world? With this library, you can build a Lisp-like domain-specific (expression) language.
GitHub - tego101/templ_components: A collection of reusable UI components built with Golang's templ, TailwindCSS, Daisy UI, and Alpine.js.
UI Lego bricks without the studs.
Tools and applications
GitHub - chenjiandongx/dnstrack: 🔎 A dns-query tracking tool written in go.
dig
? dog
? No, dnstrack
! Inspect DNS queries and their responses.
SwiftWave
SwiftWave is a self-hosted, lightweight alternative to Heroku, Netlify, or Render. It has minimal hardware requirements. For deploying software, it requires Docker but it can dockerize projects that have no Dockerfile.
GitHub - jack-rabe/impl.nvim
Do you belong to the intersection of the two groups "I am a NeoVim user" and "I want to generate interface implementations automatically"? Here is the NeoVim plugin for you.
GitHub - unklnik/mr_snuggles_dungeon_adventure: Roguelite game made with Go and Raylib - Demo & Game is available on Steam https://store.steampowered.com/app/2968730/Mr_Snuggles_Dungeon_Adventure/
A 2D, top-down dungeon shooter. Compile it from the sources (raylib needed) or get it on Steam.
GitHub - mlange-42/tom: Tom -- Terminal for Open-Meteo
htop
for your local weather.
GitHub - benweint/gquil: A CLI for inspecting and visualizing GraphQL schemas
When data structures become too complicated, it's tools time. gquil
lists GraphQL fields, types, and directives, and produces a visual representation of a query schema (with a little bit of help from GraphViz).
GitHub - horiondreher/go-web-api-boilerplate: Some Web API boilerplate using Go and SQLC
Why write boilerplate code if someone else did it for you? web-api-boilerplate
is a (biased) template for writing, you guessed it, web APIs.
GitHub - damiensedgwick/napp: Napp: A command line tool that bootstraps Go, HTMX and SQLite web applications and Dockerises them for ease of deployment.
Build tiny apps! Napp generates a minimalistic Go, HTMX & SQLite application skeleton, including a Makefile and a Dockerfile, to start building right away.
GitHub - ryanolee/go-pot: A service for giving away secrets to bots ...Probably slightly too many!
Project of the week: Give hostile bots a warm welcome and feed them with fake secrets until they choke.
GitHub - EwenQuim/entropy: Entropy is a CLI tool that will scan your codebase for high entropy lines, which are often secrets.
Are you sure you did not forget to remove any hard-coded secrets from the code before checking it in? Let entropy
find them.
Completely unrelated to Go
Skip SDKs in Simple Integrations
Should you use an SDK, or rather directly interact with an API? Kent C. Dodds argues that for simple APIs, using an SDK is not worth the trouble, as SDKs often come with unnecessary complications and bugs.
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