Don't Mess With That Property! • The Applied Go Weekly Newsletter 2024-12-01
Your weekly source of Go news, tips, and projects
Don't Mess With That Property!
Hi ,
Unit tests usually follow a simple pattern: Pass some test values and compare the observed output to the expected one. But what if the property to be tested is not a direct relation between input and output? For example, a property to test for could be, "the output of this serialization function should be readable by the corresponding deserialization function." This week's spotlight describes a quick
way of writing property tests.
But first, read some articles about ducks, simple or incomplete generics, and pointers to constants (huh?).
Enjoy!
Featured articles
Don't sleep on inline interfaces
When a duck is not a duck: Identical interfaces from different packages are not interchangeable in every situation.
Are Golang Generics Simple or Incomplete? A Design Study
The title is a bit of an attention-grabber. No language (or one of its features) can be "complete" in any reasonable meaning of the word. Moreover, asking for completeness only leads to bloated languages with all (well-known) disadvantages.
But let my little rant not keep you from reading the article; it's an interesting journey in building a family of map types and make the code document and assert the relationship between these types.
Getting a pointer to a constant in Go - Xe Iaso
A constant has no address in memory, hence you cannot get a pointer to a constant. But what if a function expects a pointer to a string, and you want to pass a literal string?
Xe Iaso shows several solutions to this problem, from least to most hacky.
Podcast corner
go podcast() | 048: Lea Anthony on Wails
Dominic St-Pierre's guest is Lea Anthony, the creator of the Wails project. Lea shares his early exposure to IT and explains how Wails aims to simplify the development of desktop applications.
Spotlight: Property Testing
Typical unit tests take an input value and an expected result, run the function to be tested, and compare the actual and the expected results.
This can happen through a hand-crafted test, a table-driven test, or with fuzz testing.
There are cases, though, where comparing expected versus actual output cannot verify a certain behavior of a function. Functions may have properties that are true (or rather, should be true, because that's what we're going to test) regardless of the input.
Examples:
- Formatting an already formatted phone number should not change that number.
- A date range is valid if the start date is earlier than the end date, independent of the actual input values.
- A hash function must always return the same hash for a given input.
Property Testing
As the focus is on properties of a function, rather than specific input/output values, this kind of testing is called Property Testing. (Another test strategy to tuck at your testing toolbelt!)
The TL;DR of writing property tests is:
- Find a property that must be true for given pairs of input and output.
- Generate input/output pairs in advance or on the fly.
- Assert that the property is true for every generated input/output pairs.
Assume you write a function for sanitizing HTML. If the function receives already sanitized HTML, it should return the HTML unchanged. (Here is something to spout off about at parties: A function that, when receiving its own output as input, doesn't change that output anymore, is called idempotent.)
To test this property, you'd need to either provide a hard-coded list of input values (not so good) or generate lots of random input values (better). Or you save yourself the trouble and use package testing/quick
, specifically, its Check()
function. Check()
takes a function (and an optional config) as input and calls this function repeatedly with random input, to see if the function returns false
on any given input.
So all you need to do is write the property "the HTML sanitizer does not change already sanitized HTML" as a function and pass this function to Check()
:
package main
import (
"testing"
"testing/quick"
)
func SanitizeHTML(html string) string {
return "Sanitized:" + html // not idempotent!
}
func TestHtmlSanitizerIdempotency(t *testing.T) {
prop := func(html string) bool {
sanitized1 := SanitizeHTML(html)
sanitized2 := SanitizeHTML(sanitized1)
return sanitized1 == sanitized2
}
if err := quick.Check(prop, nil); err != nil {
t.Error(err)
}
}
(See a failing instance of this test on the Go Playground. If you want, fix the tested function to make the test pass.)
A truly quick way to property testing, if you allow me the pun. Note that property testing cannot replace standard tests. You can trivially write a SanitizeHTML()
function that passes the property tests without actually sanitizing anything. It could, for example, always return the original input string, or an empty string, or any hard-coded string.
So, property testing is always an addition to standard unit tests, and not a replacement or simplification. See it as a tool to make your tests more comprehensive.
Quote of the Week: No great programming languages
There are no great programming languages. If a language doesn’t apply to your constraints, move on if you can. More broadly, tech is a free market of ideas and implementations so we can avoid designing everything by committee. No need for hard feelings. Use what works the best.
(I consider myself lucky in this regard: Go works best for me, for so many use cases.)
More articles, videos, talks
Contextual Logging in Go with Slog | Better Stack Community
slog
is Go's structured logging package. Percy Bolmér shows how to use slog
to add meaningful context to log output, so that debugging an error is more than just taking a stab in the dark.
Go upgrade checklist - by Hakan Koklu - Trial and error
Upgrading to a new Go version should be straightforward and painless. However, most real-world projects aren't clean-and-pure Go projects, so keep this checklist around when Go 1.24 (or any new Go release) comes out.
Building a Database from Scratch in Go (part 01) - File Manager - YouTube
This video series is going to implement a simple relational database management system called SimpleDB, originally implemented by professor Edward Sciore in his book "Database Design and Implementation".
First part: a file manager in Go.
Essential tools for Go developers
Do you use these Go tools in your development workflow? If not, give them a try.
Go and Java: Rethinking Type Safety for the Pragmatic Age
For many teams, Go has proven to be the language that unites juniors and seniors in understanding each other's code and writing code each other can understand. Or as the author of this article, Rohan Ganapavarapu, states it, "Hats off to Rob Pike and Ken Thompson for their understanding of the (below?) average dev."
But is Go a "better Java"? Rohan sees a few features missing that would make Go the ultimate Java successor.
Introducing Glu: Deployment Coordination as Code
Introducing Glu, a framework aiming at codifying deployment pipelines in an intuitive, maintainable way.
Projects
Libraries
GitHub - Puchungualotsqui/Grizzly
Go is slowly entering the world of data science. This package can manipulate DataFrames, so no more need for installing Python versions and dependencies to fiddle with DataFrames
GitHub - notnil/rowboat: RowBoat is a Go package that provides a struct based csv reader and writer
Read and write CSV files directly to or from a struct
.
GitHub - rdalbuquerque/viewsearch: Bubbletea's viewport with vim-like search feature
Make views of your Bubbletea CLI apps searchable.
GitHub - rdbende/Azure-ttk-theme: A stunning modern theme for ttk inspired by Fluent Design 💠
Modernc.org's tk9.0 GUI toolkit now supports themes, starting with a port of the Azure-ttk theme.
vnc package - modernc.org/tk9.0/vnc - Go Packages
The TK toolkit, and its Go variant tk9.0
, are meant for building desktop GUIs, not web GUIs. With an integrated VNC server and an in-broswer VNC client, however, tk9.0
apps can be run in a browser like a web app.
Tools and applications
GitHub - netmute/ctags-lsp.nvim: Neovim configuration for ctags-lsp
Do you frequently write code for languages that don't have a language server? ctags-lsp
is a lightweight language server based on the good old ctags
tool. Currently, the only editor integration is a plugin for Neovim.
GitHub - grishy/gopkgview: Interactive web-based visualization of a Go package's dependency graph
go mod graph
... doesn't show... a graph. gopkgview
does.
GitHub - manish-mehra/govibes: A mechanical keyboard sound simulator CLI/TUI tool
Make your keyboard produce the sound of a classic, mechanical keyboard, even if it has rubberdome switches. The author created it because "thanks to Wayland’s security and Electron’s 150MB memory footprint, [the original tool Mechvibes] stopped working."
GitHub - pabloerhard/pogo
A Pogo compiler written in Go. More interesting than the code is perhaps the story behind it.
GitHub - softika/gopherizer: Web project template for Go
Another Go project starter template... which is a good thing, as such templates are inadverently biased, and the more starter templates there are, the higher the chances to find the one that fits one's needs.
GitHub - Phillip-England/gtml: Convert HTML to Golang 💦
After Go templates, Templ and gomponents, another HTML-as-code system enters the scene: GTML
generates Go functions from HTML (guided by custom HTML attributes).
Completely unrelated to Go
Underrated ways to change the world
Changing the world does not require a superhero. Seven ways of making this world a better place, one step at a time.
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