In the before times, I typically used a small, curated handful of git worktrees. Now the worktrees grow like bermuda grass, to the extent that they’ve become a disk space problem. Git worktrees do share their git objects, but they don’t share their working tree. That’s the whole point: you can edit them independently. But conveniently, if you are using a filesystem that supports…
Whenever possible, I leave my webcam off during internet meetings. It is almost always possible. There are a few reasons. In decreasing importance: Attention Screens are attention-destroyers. There are so many things to look at and to do. I was probably deep into a task when the meeting started. So tempting to just nudge it along. Or I might stare at myself on camera. If I turn the webcam off, I…
I’ve played nearly every NYT Connections . The core game is rock solid, but category colors sap some of the joy. To maximize your score, you’re supposed to submit categories from purple to yellow . But: After spotting an easy category, I waste mental energy filtering it out. When I’ve solved the whole thing in my head, I must still guess which category is which color. I use…
When writing a service, it’s very easy to accidentally forget to check permissions or ownership of an object. This code has a gaping security hole in it: func ( s * Server ) deletePhoto ( w http . ResponseWriter , r * http . Request ) { id := r . URL . Query (). Get ( 'id' ) s . db . DeletePhoto ( id ) } Anyone who gets ahold of a photo ID can delete that photo. Developers often address this…
Lots of people don’t want to read about AI. I respect that. But I’m currently steeped in the world of AI, for better or for worse, and I want to blog about it. So I’ve split this blog in half. The normal blog, which you are reading, is now AI-free. There’s another, at /ai that contains only AI posts. It has its own RSS feed.
I have started a podcast, Significant Bits. The goal is to have substantive technical discussions about software engineering, very broadly defined. You can listen at https://sigpod.dev/
I didn’t sit down this morning planning to write a grouchy blog post about Hugo. When I first used Hugo I loved it. It was fast. It was simple. It just worked, as much as any software does, and it solved a real problem. It was done. But people kept working on it. I’m sure that it has been improved in countless ways. But along the way it has gotten bigger and more complicated, and has…
This post was originally tweets but then things happened, and it needed a new linkable home. Btw, I’m now @commaok@inuh.net on Mastodon. This post is about manual type specialization, which can make a big difference in some hot code. Consider this: type Gopher interface { Goph () } func f ( x Gopher ) { // ... if t , ok := x .( * T ); ok { t . Goph () } else { x . Goph () } // ... }…
Go templates ( text/template , html/template ) accept a single argument to render. That’s generally enough when you’re executing them from Go code. But when invoking a template from another template, you often want to pass multiple things to it. For example, we might have a template that renders a nav bar item. It requires a title, a url, and an “enabled” bool. We want to…
Linus’s Famous Law: “Given enough eyeballs, all bugs are shallow.” Linus’s Less Famous Law : “Files grow.” One of the hardest things programmers do is keep code readable. Splitting code up into separate files is a basic tool for that. And yet, crazy as it sounds when you say it out loud, our tools pressure us not to. PHP My first software job was for a company…
Around this time in the Go release cycle , the Go team asks people to test Go betas and release candidates . Please help! It is easy, fast, and important. This post is about how, what, and why to test. Installation Pre-releases can be downloaded using go get . For example: $ go install golang.org/dl/go1.17beta1@latest $ go1.17beta1 download $ go1.17beta1 test your/favorite/package A complete list…
Lookup tables are powerful micro-optimization tools, because they implement arbitrary transformations in cheap constant time. And yet we often do not use them to their full potential. This post is the story of one example. A good starting point In a recent blog post, Daniel Lemire rediscovered a technique for calculating the base ten length of a uint32 . Start by calculating integer log2(x) , do…
A small thing of which I am irrationally proud: I was the proximate cause for the addition of a sentence to the RISC-V ISA spec . Here’s the sentence: Loads with a destination of x0 must still raise any exceptions and cause any other side effects even though the load value is discarded. It’s OK if you have no idea what that means. You will soon. Here’s the story. Background In…
This is the first blog post I’ve written that isn’t about Go, and it’s pretty weedy. Feel free to stop reading now. This is a git experience report based on something that bit me hard today, despite being quite experienced with git. Play along! Prologue Initialize a repo. Create two commits. $ git init . Initialized empty Git repository in <redacted> $ touch readme $ git add…
It’s easy to forget to call go generate when you need to. Failure to regenerate can mean nasty bugs. Venerable gopher Rog Peppe found an excellent technique for guarding against this class of bugs. Like many good ideas, it is obvious in retrospect. Generate code that will not compile if needs to be regenerated. I’ll illustrate this with two examples. stringer The first example comes…
As of Go 1.15, the Go runtime’s memory allocator doesn’t always allocate exactly the number of bytes required for an object. Instead, it rounds up to the nearest size class . type T struct { i int64 b byte } Type T has a size of 9 bytes, but allocating a T will use 16 bytes. If you’re trying to reduce the memory usage of a program that allocates a lot of one particular type of…
If you are desperate for 6% smaller Go binaries, this blog post is for you. (I did this experiment to help out Tailscale . Disclosure: I’m an investor.) If binary size doesn’t worry you, well, maybe you’ll find it entertaining. In order to get example numbers for this post, I grabbed a random item from my GOPATH. All the hard numbers in this blog post are for…
This blog post covers string interning in Go. What is a string? In Go, a string is a (possibly empty) immutable sequence of bytes . The critical word here for our purposes is immutable . Because byte slices are mutable, converting between string and []byte generally requires an alloc and copy, which is expensive. Under the hood, strings in Go are (currently) represented as a length and a pointer…
My favorite new API in Go 1.13 is testing.B.ReportMetric . It allows you to report custom metrics from within your benchmarks. When the API was proposed , the motivating example was package sort . The package sort benchmarks, like all benchmarks, measure elapsed wall time and (optionally) allocations. But wall time measurements can be noisy, and the sort routines don’t allocate much. There…
The Go 1 compatibility promise was designed to ensure “that Go 1 will be a firm foundation for the development of Go and its ecosystem.” Go 2 is coming. Ian Lance Taylor has written a masterful, thoroughly researched design document about “how to make incompatible changes from Go 1 to Go 2 while breaking as little as possible”. Interestingly, both documents are clearly…
Go program execution doesn’t start at func main . First is a bit of bootstrapping . Then the runtime gets initialized . Then, package by package, the program initializes global variables and runs init functions. Then it’s time for main . Usually, the startup time for a Go program is negligible, and irrelevant compared to its steady state performance. For short-lived programs, though,…
This post is about some new compiler optimizations scheduled for Go 1.9, but I want to start with logging. A couple of weeks ago, Peter Bourgon started a thread on golang-dev about standardizing logging . Logging is pervasive, so performance came up quickly. The go-kit log package uses structured logging, centered on this interface: type Logger interface { Log ( keyvals ... interface {}) error }…
If you work on a short-lived, allocation heavy program and care about a tiny (maybe 0.5%) performance improvement, this post is for you. I was looking at a CPU profile of the Go compiler when I noticed something odd: An entry in mprof.go . mprof.go contains the memory profiling implementation, but I was doing cpu profiling. Was there a bug in compilebench , perhaps? Nope. The variable…
This post is about a little-known way to make compile-time assertions in Go. You probably shouldn’t use it, but it is interesting to know about. As a warm-up, here’s a fairly well-known form of compile-time assertions in Go: Interface satisfaction checks. In this code ( playground ), the var _ = line ensures that type W is a stringWriter , as checked for by io.WriteString . package…
I’m going to try this blogging thing again. I’ve failed at it a few times before. I’m going to try Julia Evans style this time. Maybe this one will stick?