KISS. Because YAGNI. • The Applied Go Weekly Newsletter 2024-09-01
Your weekly source of Go news, tips, and projects
Beware of over-engineering. Sometimes, a quick hack is sufficient. This week's spotlight describes an example: Instead of selecting a CLI command library and implementing commands and subcommands in Go, you can use a quick hack to unite independent CLI tools under a parent command. But there is a catch: Such "quick" hacks can turn out to be long-lived, postponing a proper solution by months or years.
For more about over-engineering, or the avoidance of the same, read the 4-chan article in the Featured section below. Or get some tips for building a TUI app that is powerful without drowning in complexity. Or learn an effortless way of deduplicating values for reducing memory footprint.
In any case, Keep It Simple, Stupid. Because (as you'll learn in the Unrelated To Go section) You Ain't Gonna Need It.
Featured Articles
New unique package - The Go Programming Language
Attention, pun ahead: This package is truly unique
. Added to Go 1.23, the unique
package helps to save memory by deduplicating (comparable) values.
Michael Knyszek explains how the unique
package works and presents a real-world example from the internals of the net/netip
package that saves memory by deduplicating zone attributes of IPv6 addresses.
The 4-chan Go programmer
No, this is not about the (in-)famous image bulletin board 4chan. Rather, Zach Musgrave once came across a channel of channels and wondered if this concept can be stretched to another level. And another.
Tips for building Bubble Tea programs
Terminal UIs are easy to design and implement, right? Well, despite their simple visual appearance (compared to desktop GUIs or web UIs), the mechanics behind TUIs are similar to those of graphical UIs.
Louis Garman bumped into some obstacles and compiled a list of tips for anybody who wants to start writing a moderately complex TUI app.
Podcast corner
✄ To bisect or not to bisect? I guess the answer's in the middle with Jamie Tanna's step counter!
Jamie Tanna steps in for Jonathan Hall who is on vacation. Jamie and Shay discuss the proposed bisect
tool, a new proposal that aims at bringing iterators to error handling (no, not the other way round), embed support in CUE, a praise of 0.x versions, and an open-source DB diagram editor.
The community of gophers
Gopher communities FTW! Host Angelica talks to gopher meetup organizers from around the world.
Spotlight: How to implement subcommands without using a CLI command package in 2 steps
CLI is king!
Your IT infrastructure wants to be managed, and while UIs are fancy and convenient, the CLI rules when quick action is required. For ultimate control over your infrastructure, you envision a tool named srv
that provides numerous subcommands, like srv status
, srv start
, srv stop
, and so forth. Just like Git does it!
Of course, you want to write all these subcommands in Go. You know that there are several CLI command packages available that support subcommands, like Cobra, urfave/cli
, Kong, and many more.
But which one to choose?
"None" is an option
If you need to decide quickly, opt for none of them. Postpone this decision until you find some time to evaluate available CLI packages. You can still bundle all your tools as subcommands under a main command.
The trick? A simple shell function.
A simple Bash/Zsh/Powershell function can deliver a simple command/subcommand hierarchy in 2 steps.
Step 1: Create stand-alone commands
Start by writing all your sub-commands as stand-alone binaries. If we stick with the above example, you would name these binaries srv-status
, srv-start
, srv-stop
, and so on.
Step 2: Add a function to your shell config file
Here is a rather simple function that can be called as srv
and invokes srv-command
. Sounds trivial? Maybe, but you get a few advantages from this approach:
- All commands have a common entrypoint. All users know that all server management commands are called as
srv
. No need to keep a list of commands in one's head or on stickies. - All available subcommands are discoverable. If called as
srv
or assrv help
, the script prints out all available commands. - Everyone can easily contribute new commands. Adding a new binary with a
srv-
prefix to a directory listed in $PATH is sufficient to extend the list of subcommands forsrv
. The script automatically picks up the new command, no manual changes required.
So here is the script for several shell flavors.
For Bash, add this script to .bashrc
and restart the shell or start a new one:
srv() {
print_usage() {
echo "Usage: srv "
echo "Available subcommands:"
printf ' %s\n' $(compgen -c srv- | sed 's/^srv-//' | sort | uniq)
echo " help"
}
if [ $# -eq 0 ] || [ "$1" = "help" ]; then
print_usage
return 0
fi
command srv-"$@"
}
Zsh users can re-use this script after swapping out the printf
line for:
printf ' %s\n' ${(f)"$(print -l ${(ok)commands[(I)srv-*]} | sed 's/^srv-//')"}
The reason for this change is that compgen
is a Bash-internal function. The Zsh script uses Zsh's associative commands
array instead for finding all srv
subcommands.
Fish syntax is different. Create ~/.config/fish/functions/srv.fish
and insert this script:
function srv
function print_usage
echo "Usage: srv "
echo "Available subcommands:"
for cmd in (string replace -r '^.*/srv-' '' (command -s srv-*))
echo " $cmd"
end
echo " help"
end
if test (count $argv) -eq 0; or test "$argv[1]" = "help"
print_usage
return 0
end
command srv-$argv[1] $argv[2..-1]
end
PowerShell users can put the following script into $PROFILE
:
function srv {
function Print-Usage {
Write-Host "Usage: srv "
Write-Host "Available subcommands:"
Get-Command srv-* | ForEach-Object { $_.Name -replace '^srv-' } | Sort-Object -Unique | ForEach-Object { Write-Host " $_" }
Write-Host " help"
}
if ($args.Count -eq 0 -or $args[0] -eq "help") {
Print-Usage
return
}
$command = "srv-$($args -join ' ')"
Invoke-Expression $command
}
Finito
With almost no effort, you now can create and use subcommands. Calling srv start --now server1 server2
translates directly to srv-start --now server1 server2
, while srv
and srv help
list all available commands.
Feel free to play around and extend the script. For example, if srv
is called without a subcommand, make it invoke a default command instead of listing subcommands. Or improve the help
command to turn the call to srv help
into srv-
.
Quote of the Week: Code is like humor
Code is like humor. When you have to explain it, it’s bad.
More articles, videos, talks
How to Build a Multi-Workspace Slack Application in Go - Blink
Slack supports external applications that can be invoked from within a channel by typing a slash at the beginning of a line.
David Abramov has written one in Go and shares the steps to build your own Slack app.
GitHub - project-samples/go-sql-export
Exporting large volumes of data from a database can drain system resources considerably. Here are some tips for writing a performant SQL-DB-to-CSV export in Go.
Side note: Yes, this is an article, as the README states. The code is the article's PoC.
Go Beyond: Building Performant and Reliable Golang Applications
How GOMEMLIMIT helped the Zomato team cut down memory usage.
Let's stop editing go.mod manually – tpaschalis – software, systems
Do you edit go.mod manually? Paschalis Tsilias did this, too, until he realized that go mod edit
makes his life much easier.
Go sync.Pool and the Mechanics Behind It
Trashing and re-creating resources, especially exernal ones like database connections, is costly and puts an extra burden on the garbage collector. A sync.Pool
can save instantiated resource for re-use, especially across goroutines.
Phuong Le dives into the pool to uncover how it works.
Resilience in communication between microservices using the failsafe-go lib
Microservice communication can fail in many ways, and consequently, multiple strategies exists for preventing, mitigating, or fixing such failures. With Elton Minetto's article and sample code, you can actively inspect strategies like retry, circuit breaker, or fallback.
Standardize and Unify 7 Message Queues in GOLANG: Kafka, RabbitMQ, IBM-MQ, Active MQ, Google Pub/Sub, Amazon SQS, NATS
How to put an abstraction layer over message queue systems.
(If you'd rather use a ready-made module, Watermill might be a fit.)
Terminal Applications in Go
Cobra for command routing, Viper for configuration managment, Bubbletea for the UI—a true dream team for TUI apps, innit?
Projects
Libraries
lfmap package - github.com/Snawoot/lfmap - Go Packages
This map implmenetation achieves lock-free access by a creating shallow clone of itself on each operation. Goroutines can thus, for example, traverse a (snapshot of) the map without blocking other goroutines.
GitHub - jordyvanvorselen/go-templ-htmx-vercel-template: A template to use Golang + HTMX + Templ on Vercel 🚀
This GoETH (Go, Echo, HTMX, Templ) repository template is ready for getting deployed to Vercel. You only need to fill the template with life.
Tools and applications
GitHub - nitwhiz/omnilock: This is a locker. 🔒
Distributed lockers have a problem: To avoid stale locks, they usually imply a time to live (TTL) on each lock. What if a client is interrupted and continues after the TTL has passed?
The author of omnilock
replaces TTL by TCP connections to monitor the lock status. Processes can thus keep the lock engaged without any TTL limits. Still, when a process unexpectedly exits (and thus would not reclaim the lock anyway), the OS eventually closes the stale TCP connection.
GitHub - pijng/prep: Golang comptime. Pure blasphemy
'Just a few weeks ago, I was battling with some stuff in Go and I kept saying to myself "I wish Go had comptime like Zig!"'
Now it has.
To be clear, the only function in this package, Comptime()
does nothing. But that's enough for the accompanying preprocessor that can produce, well, preprocessed results from a function called by Comptime().
GitHub - willofdaedalus/yummychars
Need to kill time while waiting for a C++ project to compile? Play yummychars
, a TUI game that has no other goal than steering a snake that eats all the characters in your terminal.
GitHub - byawitz/ggh: Recall your SSH sessions (also search your SSH config file)
ggh
is like ssh
but remembers your previous SSH sessions. Useful if you have numerous different servers to connect to.
GitHub - onurhanak/TabStop: A cross-platform app to download Guitar Pro tabs easily.
You will want to take a look at this project if you
- want to download guitar tabs for Guitar Pro from Songsterr
- or want to learn Fyne by looking how others do it.
GitHub - coder/wush: simplest & fastest way to transfer files between computers via wireguard
Why wush
and not woosh
?!
Anyway. wush
was built to "transfer files and open shells over a peer-to-peer WireGuard connection".
Worth noting: wush
does not require to set up a relay server to help clients behind a firewall or behind NAT find each other. Instead, it relies on Tailscale's DERP servers. (No Tailscale account required.)
Completely unrelated to Go
No, really: YAGNI
You Ain't Gonna Need It, this time with an exclamation mark.
SQL Has Problems. We Can Fix Them: Pipe Syntax In SQ
Front to back from read be must SQL. No, wait: SQL must be read from back to front.
Look at any SQL query. Its subtasks are not listed in the order a human would execute them. Or would you select columns before you even know where these columns come from? And it gets worse with nested queries.
Google Research added a pipeline operator to standard SQL in the ZetaSQL project. This operator basically works like a pipe in a Unix shell: The output of a SQL query fragment is piped to another fragment. The result is a query statement that resembles the natural data flow but hardly looks like SQL As We Know It™.
What do you think? Cool or makes-my-hair-stand-on-end?
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