Optimizing for Reviewers: The Three Step AI Dev Loop

With AI writing a lot more of our code, we need to optimize for the human code reviewer.

The key to this is good test coverage and minimizing diffs in changes that humans need to verify.

We should strive to separate refactors that don’t change logic from changes that intentionally change logic (bug fixes, feature additions, etc). Separating the two makes it significantly easier to understand if a change is correct. This was always best practice, but it was often burdensome because of the additional human effort required. Now with AI to do the boring parts, it’s more practical to put into practice.

Read more →

Why Infer Types?

Series: Bite Sized Go

Someone at work asked the following question:

Why write code like this:

foo := getFoo()
bar, err := getBar()

instead of this:

var foo Type = getFoo()

var err error
var bar Type

bar, err = getBar(foo)

Isn’t the latter more explicit? Isn’t explicit better? It’ll be easier to review because you’ll be able to see all the types.

Well, yes and no.

For one thing, between the name of the function you’re calling and the name of the variable you’re assigning to, the type is obvious most of the time, at least at the high level.

Read more →

Safer Enums

Series: Bite Sized Go

How to “do” enums is a common problem in Go, given that it doesn’t have “real” enums like other languages. There’s basically two common ways to do it, the first is just typed strings:

type FlagID string
const (
    FooBar FlagID = “FooBar”
    FizzBuzz FlagID = “FizzBuzz”
)
func IsEnabled(id FlagID) bool {

The problem with this is that string literals (really, string constants) in Go will get converted to the correct type, so you’d still be able to call IsEnabled(“foo-bar”) without the compiler complaining.

Read more →