My Web App Stack? Go. • The Applied Go Weekly Newsletter 2024-07-28
Your weekly source of Go news, tips, and projects
Go is said to be the language for backend infrastructure and CLI tools. Nevertheless, countless projects relentlessly work on establishing Go in other spaces: Game engines like Ebitengine, blockchain software like go-ethereum
, embedded Go editions like TinyGo, or AI frameworks like Ollama and langchaingo
show how versatile Go is.
In the web application space, classic stacks are prevalent. A database "at the bottom", Go for the backend, and any of the myriad frontend frameworks for the user-facing parts. Which typically means HTML, JavaScript and/or Typescript, a JS/TS framework, and CSS or a CSS framework. Examples are Wails, Gio, go-app
, and the GoTH stack that is made of Go, Templ, and HTMX (see also the Gothem stack in the projects section below that adds Echo and Mage).
If you started as a backend developer, turning full-stack may seem a daunting task. Various projects work on reducing the height of the stack. Go modules like gomponents
or a-h/Templ
simplify the web stack by internalizing frontend code into Go.
But why stop here? GUI toolkits like Fyne or the new Cogent Core (see Featured Articles below) eliminate all non-Go code and description languages, leaving you with just Go (and the respective toolkit).
Now add a Go-powered database like CockroachDB, DoltDB, or modernc/sqlite
, and you can say:
"My web app stack? Just Go."
Featured Articles
Initial release • Blog • Cogent Core
Cogent is a new GUI framework kid on the block, positioning itself as an alternative to established frameworks like Fyne, Wails, Gio, and go-app.
The blog page behind the link is a Cogent app running as a Web Assembly module.
git-spice
Stacking Git, or PR stacking, is a Git workflow that stacks pull requests on top of each other, to minimize delays caused by slow PR reviews. Without specific tooling, however, PR stacking can become tedious to manage.git-spice
is such a stacking tool. In contrast to gh-stack
, git-spice
creates a PR for every new branch rather than every new commit.
GitHub - sathwikreddygv/redis-written-in-go: A Redis-like Database in Go
Creating Redis clones seems to become increasingly popular. I remember Redka, a Redis clone with Go and SQLite, being released earlier this year, and now we have godisDB
that replaces Redis' single-threaded event loop with concurrency.
Fun fact: "godis" means "candy" in Swedish, and "god is" means "good ice" in Danish. Yummy!
Podcast corner
Don't skip the gym! 🏋️ And interview Alice Merrick, UX researcher on the Go team
User Experience design (or UX design for short) is for apps, right? Nope. Even programming languages have a user experience to be designed. Alice Merrick is UX researcher on the Go team and talks to Jonathan about her work.
Aha moments reading Go's source: Part 2
Don't read Shakespeare, read Go sources! Round 2.
Go tip of the week: Range-over-func in a nutshell
Quite a few blog articles have discussed the upcoming range-over-func mechanism already, but what I miss is a concise how-to document. So here we go.
Problem
The situation: You created a custom container type for a library you are working on:
type MyCollection []string
Your library's client code shall be able to iterate over a collection's elements.
(Ignore for a moment that the custom type is just a slice in disguise and that you'd be able to just range
-loop over it. I want the code to stay minimal, so I refrained from constructing something more complex than that. As a homework assignment, try building a range-over-func iterator for a linked list.)
Solution #1: before Go 1.23
With Go releases before 1.23, you would probably write a Loop()
method that receives a func()
from the client. Let's call the client's function yield()
, because at every iteration, we yield the current key and value to this function:
func (m MyCollection) Loop(yield func(int, string) bool) {
for k, v := range m {
if !yield(k, v) {
break
}
}
}
The Loop()
method iterates over the elements of the collection and calls the client's yield()
function at each iteration. (Yes, that's exactly how fs.WalkDir()
iterates over a directory tree.)
The client's yield()
function receives the key (in our example, it's just the slice index) and the value of each element of your container. If the client's func
decides to break the loop, it returns false
, else true
. In case of false
, the Loop()
code would exit.
The client's code would look like:
m := MyCollection{...}
m.Loop(func(k int, v string) bool) {
// Do something with k and v here
fmt.Printf("%d: %s\n", k, v)
// If you want to break the loop,
// return false
return true
}
This client loop is a bit ugly, isn't it? If we must create ugly code, we'd want to hide it in the library rather than forcing it upon the client.
Moreover, your library users surely would love to be able to use the well-known for range
loop.
But how can we magically summon key and value inside the client's loop body, at each iteration?
Solution #2: range-over-func
With the help of Go 1.23, we simply delegate the calling of Loop()
to the range
iterator. The difference to the pre-Go-1.23 code is entirely on the library client's side:
for k, v := range m.Loop {
fmt.Printf("%d: %s\n", k, v)
}
Here you have it: a custom loop function used by the standard range
operator. Now let your imagination go wild and write iterators for the weirdest collection types you can imagine!
(Play with this code in the Go Playground.)
Yield has variants
The yield
function above has two parameters, key and value. You can also define and use yield
with one parameter only, where you can either yield the current key or the current value to the loop body. Or you can even use yield
with zero parameters! The loop body would neither receive a key nor a value. That would probably be good for just counting elements.
Further reading
- The For statements with range clause section of the language reference has two interesting examples (scroll down in this section to see them):
- An iterator function that endlessly generates Fibonacci numbers (the client has to break the loop),
- and an iterator method that traverses a binary tree. (Just from looking at the code, can you tell the sequence in which the tree nodes' keys and values are yielded to the loop body?) - Go range iterators demystified | DoltHub Blog
- First impressions of Go 1.23's range-over-func feature - Boldly Go
- Iterators in Go — Bitfield Consulting
Quote of the week: Pointers are not confusing
For people coming from dynamic scripting languages, pointers are not the confusing thing. In a dynamic scripting language, everything is a pointer. What is confusing is having direct values that aren't accessed through a pointer.
– /u/jerf
More articles, videos, talks
GitHub - NewstellerBot/chimp-type: A minimal typing test for terminal written in go.
Are you learning how to touch type (aka blind type), or do you plan to do so? This cli app is your typing trainer. It presents text that you must type within a selected time frame. From the correctly typed words, it calculates your WPM (words per minute). Small caveat: If you are red-green-blind, you probably won't enjoy the app.
What's the best Static Analysis tool for Golang?
What do you do if golint
and go vet
aren't able to catch the issues you need to know about? The Go Analysis API provides a uniform way of running all kinds of checks against your code. golangci-lint
is perhaps the most prominent collection of linters that uses this API.
Go features by version
When was that particular Go feature introduced? Anton Zhiyanov's timeline lists every major feature, the Go version it appeared first, and any related proposal or commit.
Projects
Libraries
GitHub - MichaelMure/channel: a wrapper around the normal golang's channel, with several improvements
This channel wrapper library claims to make channels easier to use. Is this worth the efforts of having to learn a new channel API? You decide.
GitHub - grindlemire/gothem-stack: An end to end htmx and go-templ template using echo for the web server and mage for deployment.
The trinity of Go, Templ, and HTMX is known as the GoTH stack. Here is the next level: Go, Templ, HTMX, Echo, and Mage.
GitHub - mikestefanello/backlite: Type-safe, persistent, embedded task queues and background job runner w/ SQLite
Do you need a peristent task queue without the overhead of running a separate service? Backlite is an in-process, persistent task queue with scheduled execution, retry&backoff functionality, and a Web UI.
GitHub - jftuga/DateTimeMate: Golang package and CLI to compute the difference between date, time or duration
Calculating and manipulating times and durations is easy—except when it isn't. DateTimeMate is here to help.
Tools and applications
GitHub - otaxhu/go-closed-src-example: Go closed source example
Go strives in the OSS world, but there are valid reasons to protect your source code from prying eyes. This repo demonstrates how to compile a command without access to the full source code. In the main branch, the full source code is available, but in branch closed
, a part of the source code is replaced with a precompiled. .a
file.
GitHub - sathwikreddygv/redis-written-in-go: A Redis-like Database in Go
Creating Redis clones seems to become increasingly popular. I remember Redka, a Redis clone with Go and SQLite, being released earlier this year, and now we have godisDB
that replaces Redis' single-threaded event loop with concurrency.
Fun fact: "godis" means "candy" in Swedish, and "god is" means "good ice" in Danish. Yum!
GitHub - moeenn/projects-cli: A CLI tool for initializing projects in different languages.
Wait—Go has the gonew
tool for creating a new project from a template, so why another tool? Well, projects
expands the idea to other languages. Create projects for Go, C, C++, JavaScript, TypeScript, Java, and Python.
GitHub - murrrda/goSweep: Command-line tool for network scanning that includes features like SYN/stealth port scanning and ping sweeping.
Package google/gopacket
in action! (And another "my first Go app" project. What was your first Go project?)
GitHub - MrIceman/tchat: An oldschool, terminal based chatting application written in Go. 100% anonymous, no GUI
Chat like it's 1990!
GitHub - plutov/ultrafocus: CLI tool to block distracting websites and boost productivity.
Yes, there are browser plugins that block websites, but what about desktop apps like WhatsApp, Discord, etc? This CLI tool tweaks /etc/hosts to block websites independently of the app that tries to reach these sites.
GitHub - julez-dev/chatuino: A (hopefully soon) feature rich TUI Twitch IRC Client
A Bubbletea-based CLI app for Twitch chat: Join multiple channels with multiple identities (even as an anonymous user), persist sessions, and more.
GitHub - intincrab/GoDocHive: a simple document server/search engine for local HTML docs. Powered by Go + Bleve + html/template
Bleve is an indexing library that supports various non-exact searches (including fuzzy search). GoDocHive uses Bleve to make your local HTML docs searchable.,
GitHub - eduardolat/pgbackweb: 🐘 Effortless PostgreSQL backups with a user-friendly web interface! 🌐💾
A Web app for backing up (small) PostgreSQL databses. It uses pg_dump
, rather than a WAL-based approach, to keep the mechanism simple.
Completely unrelated to Go
Rust doesn't solve the CrowdStrike outage
If an epic software failure like CrowdStrike happens, language aficionados are quick to say, "this would not happen with language X!" However, the problem is much more nuanced than just being a shortcoming of a programming language.
TIL: testing in the future using the faketime command
Do you sometimes have to test what a program does at a certain time? If so, the CLI tool faketime
might become your new friend. Nicole Tietz-Sokolskaya explains how to use it.
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