This Go code is bad • The Applied Go Weekly Newsletter 2024-05-12
Your weekly source of Go news, tips, and projects
This week, let's start with two actionable articles. Write a Web app with JetBrains and explore a coding problem that has no optimal solution (but at least, it has one).
Also worth noting: Encore goes open source! In the recent months, we have seen the opposite happening. First, Hashicorp changed the licenses for Terraform and other tools from FOSS to BSL (a mere "source code availabe" license) , then, Redis followed. It is relieving to see that there are companies that see the power of free and open source and build their business model around freedom instead of building moats.
Whatever you're hacking on this week, happy coding!
Web App with Go and React - Part 1 - JetBrains Guide
In this four-part tutorial, you'll learn to write a chat app using Go, SQLite, Gin, and React.
Web App with Go and React - Part 1 - JetBrains Guide
Constraining Go type parameter pointers | Mero's Blog
In which Axel "The Merovious" Wagner explains an unfortunate conflict between a type parameter and a method with a pointer receiver, describes a pattern that works, and then recommends to avoid that pattern by all means.
Spoiler: The article ends with a nice and readable solution, and this solution contains no type parameters.
Constraining Go type parameter pointers | Mero's Blog
Encore is now fully Open Source — Launch Week Day 2 – Encore Blog
Encore, the development platform for Go and TS, is approaching the masses! They open-sourced their core tools, making it easy for everyone to self-host their deployments. Even if you are a happy user of Encore's services, knowing that you have a fallback in case their business grinds to a halt (which hopefully never happens, fingers crossed) can give you some peace of mind. Moreover, Encore offers a new Pro plan that is much cheaper than the preceding Teams plan.
Encore is now fully Open Source — Launch Week Day 2 – Encore Blog
[security] Go 1.22.3 and Go 1.21.10 are released
New security patches for Go 1.22 and Go 1.21 have been released. The patches fix an issue where a Go module containing CGO can trigger arbitrary code execution at build time when using the Apple version of ld
. Also, an issue is fixed in the net
package where malformed DNS message in response to a query can cause the Lookup functions to get stuck in an infinite loop.
[security] Go 1.22.3 and Go 1.21.10 are released
Podcast corner
Cup o' Go
Jamie Tanna is the guest of this week's episode, and Jonathan, Shay, and Jamie talk about OpenAPI (NOT OpenAI) and Go, specifically about deepmap/oapi-codegen
.
Cup o' Go | A quick tour of some proposals, and a long chat about OpenAPI with Jamie Tanna
Go Time
Tuesday, a few years from now. The unthinkable has happened: Google has laid off the entire Go team! Is this an earthshaking catastrophe, or would everybody just shrugh their shoulders and move on? Kris, Ian, and Johnny discuss an imaginative future of Go without Google.
What if Google lays off the Go team? (Go Time #315)
go podcast()
Should you choose Go for your startup? If looking at the langauge only: yes, absolutely. But there is more to picking a programming language than the language itself.
037: Is Go a good choice for your Startup?
Go tip of the week: 3 Go anti-patterns
One of the Go proberbs says:
Clear is better than clever.
Trying to write clever code always backfires when others have to maintain your code (where "others" include your future self four weeks from now). Yet, I continue to see "clever" coding being suggested as cool trick or advanced programming. Here are three "clever Go tricks" that are, in fact, anti-patterns.
Anti-pattern: Dot imports
How dot imports work
Dot imports let you import a package and use its exported identifiers without prefixing them with the package name.
So if you import fmt
as dot import, you can call Println()
and friends without the fmt.
prefix.
import . "fmt"
func main() {
Println("Look ma! no prefix")
}
Why this is an anti-pattern
The identifiers exported from this package appear as if they are defined in the current package. This is bad in two ways:
- Readers get confused while searching through source files looking for a definition of the identifier in the current package.
- Some packages have drop-in replacements that export the same identifiers. If those drop-in packages are imported through a dot import, readers may, after falling victim to problem #1, start thinking that the identifiers belong to the original package where in fact they belong to the drop-in package.
So if you get asked in your next job interview about the advantages of dot imports, tell them there are none.
Anti-pattern: Chaining
How chaining works
If a method updates its receiver, and nothing can go wrong with this update, the method does not need to return anything. Multiple such methods are called one after the other:
type num int
func (n *num) Add(delta num) {
*n = delta
}
func (n *num) Mult(m num) {
*n *= m
}
func main() {
var n num = 6
n.Add(4)
n.Mult(3)
//...
}
Too boring for cl3vr c0drs! Let's chain the methods together! We only need to have each method return its receiver. Then we can dot-call a second method on the result of the first method:
type num int
func (n *num) Add(delta num) *num {
*n = delta
return n
}
func (n *num) Mult(m num) *num {
*n *= m
return n
}
func main() {
var n num = 6
n.Add(4).Mult(3)
fmt.Println(n)
}
Whoa, we've saved a line!
Why this is an anti-pattern
Three reasons:
- We have not gained anything. Really, chaining does not give us anything we need and don't have already.
- Chained methods cannot return errors. So if you have errors, you need to fall back to the normal pattern. Now you have two different styles in your code: chaining and normal.
- Go code prefers to keep the reading focus to the left edge of the code. This means short lines, and few nesting levels (ideally only one). Method call chains can easiy travel across the whole screen and even cause a line break that looks ugly and makes the code even harder to read.
Method chaining is unidiomatic Go and should be avoided.
Anti-pattern: Defer as initialization
Pop quiz: What does the following code print?
func mysteriousDefer() func() {
fmt.Println("f runs")
return func() {
fmt.Println("func returned by f runs")
}
}
func main() {
defer mysteriousDefer()()
fmt.Println("main runs")
}
main
calls mysteriousDefer()
as a deferred function, so everything that mysteriousDefer()
prints should be printed after main
has done its prints.
However, if you run this code, you'll get the following output:
f runs
main runs
func returned by f runs
So one part of the deferred function runs before main!
Why this is an anti-pattern
This "clever trick" allows things like putting initialization and cleanup into one function.
Did you notice the double parentheses in the defer call?
defer mysteriousDefer()()
You typically would call a deferred function like so:
defer mysteriousDefer()
The second pair of parentheses calls mysteriousDefer()
before it is evaluated by the defer
directive. Then mysteriousDefer()
prints its message and returns another function, which is the actual function to be deferred.
This convoluted mess of immediate function calling, function returning and deferring a function is hard to grok, and the double pair of parentheses is really easy to miss when glancing over the code.
What's wrong with writing out an initialization function and a cleanup function?
Conclusion
If you learn a new language, it is just too natural (and completely fine!) to be curious and explore every feature of the language, to see how it works. It is also natural to carry over the patterns that you learned in your previous language. But every language has its specific rules and idioms, for a reason. Patterns taken over from other languages may not work well in Go and only lead to convoluted code that is hard to understand and harder to maintain.
Remember the Go proverb cited above, and strive to deliver clear code. All the readers of your code, including your future self, will thank you.
Overheard on Reddit
Some praise for Go:
Go is an excellent choice if you've never worked with a compiled, statically typed language or pointers. The pointers are safe and as simple as they get. And the typing is excellent, very flexible.
More articles, videos, talks
Golang Programming by Packt (pay what you want and help charity)
Packt offers a Humble Bundle of Go books. The complete bundle of 17 books costs $16,80 USD, with the option to pay more, and some of the revenue goes to the charity "Save the Children." (Expand the Adjust your Donation box on the bundle page for details.) The offer is valid until May 27th (if my "remaining days" calculation is correct).
notebox
The creator of notebox.cloud open-sources their works, parts of which are implemented in Go.
Creating a more sustainable model for oapi-codegen
in the future · Jamie Tanna | Software Engineer
The oapi-codegen
project shall receive one full day of dedicated work per week and is looking for sponsors.
using golang's crypto/aes and crypto/cipher packages · Aran Wilkinson
"Don't roll your own crypto" is a piece of cryptographer wisdom. Luckily, the standard library comes with pre-packaged cryptography. Here is an introduction to AES encryption and decryption.
Domenico Luciani - Create a DNS Resolver with Golang
Domenico Luciani implemented one of John Crickett's coding challenges with Go and test-driven development.
GitHub - ManitVig/GoTHAM-stack: A tech stack for creating modern web applications in the simplest way possible.
Remember the GoTH stack (Go, Templ, HTMX)? Here is the GoTHAM stack (Go, Tailwind, HTMX, AlpineJS and MySQL/MariaDB/MongoDB).
Devlog I: Foundations
Willem Schots builds a reference Web app. This blog post is an overview of the app's parts.
Projects
Libraries
GitHub - aminedakhlii/topGgraph: A Go-based graph management library for efficient handling and persistent storage of graph data using BadgerDB. Ideal for applications requiring complex data relationships and graph traversal operations.
In short: "create, persist, manage, search a graph in Go."
GitHub - anuragkumar19/binding: Go request binding for std lib
Echo's binding feature, extracted and made available for stdlib net/http
and Chi.
GitHub - WangYihang/gojob: Go(od) Job is a simple job scheduler that supports task retries, logging, and task sharding.
A task scheduler with an intentionally simple UX: "All you need to do is just implement the Task
interface, only one func Do() error
function is enough, the gojob scheduler will do the rest tedious work (retry on failure, logging results, etc.) for you."
GitHub - pijng/moonject: Wrapper for simple golang preprocessors
moonject
lets you do nastyinteresting things with your code at compile time, such as adding a Println()
call to the beginning of each function, or implementing #ifdef
-like macros.
Tools and applications
GitHub - unklnik/bitty_knight: Source code for the first game I made with Go on Steam
Bitty Knight is a fast, 2D, top-view, retro-style game. The author shares the source code upon request in an /r/golang
thread.
GitHub - jankammerath/servertag: Proof-of-concept server-side JavaScript webserver supporting the -tag
If you ever wanted to add JavaScript to your HTML pages that gets executed at the server, this is your chance. (PoC)
GitHub - dkorunic/pktstat-bpf: TC and XDP eBPF based simple Ethernet interface traffic monitor and reporting tool
This tool was written as an eBPF-based alternative to the ncurses/libpcap-based https://github.com/dleonard0/pktstat
, aiming for smooth operation even under high traffic.
GitHub - sdrshnv/tjern: A happy little journaling app
Quickly save your thoughts with this TUI app built with Bubbletea and utilizing a Turso database (basically a hosted version of libsqlite, a fork of SQLite)
GitHub - sgatu/chezz-back: Golang chess engine with api - used together with chezz-front
An API-based chess sever. The corresponding frontend is here.
GitHub - sharpvik/snapsound: Play sound from PNG images
"Everything is just bytes under the hood!" The author took this bit of wisdom by its word and wrote an app that interprets an image file as music. But it's just a trick: The PNG file to be played must be a repackaged MP3 file. Still, the claim holds: It's just bytes after all.
Ryan Wiley / texty: A demo for user authentication using wish and bubbletea · GitLab
The author felt that the Bubbletea/Wish combo lacks a good example of the Wish server sharing an ssh key with a Bubbletea client app, so he wrote one.
GitHub - nobotro/Go_emu: Go lang risc-v 5 stage pipeline emulator
What was your first Go project? I can definitely say that mine was not as RISC-V stage pipeline emulator.
GitHub - worlpaker/gitty: Download GitHub File & Directory
Do you frequently need to download a small subtree from a large GitHub repository? gitty
is your new friend.
GitHub - f01c33/noter: notifies you after some time about what you want to remember when you want to remember
Forgetful? Noter will remind you of your errands.
GitHub - dunkbing/kana: Terminal app to practice typing Kana (Japanese characters) in Romaji
Romaji is a system for writing Japanese using roman characters.
GitHub - Sieep-Coding/todo-htmx-alpine-go: Todo app in HTMX, Alpine.js, Air, and Go
A super-simple Todo app, ideal for exploring how writing Web apps with HTMX works.
GitHub - distantmagic/structured: [WIP] structured data extractor with llama.cpp
(1) Describe the desired data structure as JSON. (2) Let lama.cpp
extract relevant data from unstructured input, such as English sentences.
GitHub - oq-x/qusic: Free music app written in Go
With the only non-Go dependency being MPV, an open-source media player.
Completely unrelated to Go
Building a social network from scratch on a whiteboard
Why do even seemingly simple Web services evolve into an unmaintainable mess of microservices, proxies, databases, and storage layers? In this article, Xe Iaso dissects the process that leads from a simple idea to mind-boggling server bloat.
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