A few weeks after YAAG, another small Go annoyance started to grate — and this one shows up in basically every program that ever touches JSON.
The most boring code you write all day
Go convention says struct fields are exported in CamelCase:
FirstName, CreatedAt, IsActive. But the
moment those structs cross a wire — marshalled to JSON for an API, to XML for
some legacy integration, mapped to SQL columns — you almost always want
snake_case: first_name, created_at,
is_active. Go lets you bridge the two with struct tags,
the little backtick-delimited strings after each field:
type User struct {
FirstName string
CreatedAt time.Time
IsActive bool
}
…becomes the thing you actually have to type, by hand, for every field, in every struct, forever:
type User struct {
FirstName string `json:"first_name" xml:"first_name"`
CreatedAt time.Time `json:"created_at" xml:"created_at"`
IsActive bool `json:"is_active" xml:"is_active"`
}
Notice what you just did: you wrote each field name a second time, in a different case, twice over. It's mechanical, it's error-prone (one typo and a field silently serializes under the wrong key), and it's exactly the kind of work a computer should be doing for you.
So we made the computer do it
EasyTags is a tiny CLI that reads your Go source, walks every struct declaration it finds, and writes the tags in for you — converting each field name to snake_case (camel and pascal cases are supported too, if that's your house style). Point it at a file:
easytags {file_name} {tag_name_1:case_1, tag_name_2:case_2}
# the simplest form — defaults to json, snake_case:
easytags file.go
Run that against the first User above and the tags appear,
correctly cased, no typing required.
Even better: let go generate run it
Reaching for the terminal every time is still friction. The nicer way is to let Go's own tooling drive it. Drop a directive at the top of your source file:
//go:generate easytags $GOFILE json,xml,sql
Then any time you run go generate, EasyTags sweeps every struct in
that file and writes the json, xml, and sql tags for you. It becomes part of
the same reproducible step that already generates your mocks, your protobufs,
your stringers — no special-snowflake workflow, no human in the loop.
It respects your intentions
Automation that overwrites your deliberate choices is worse than no automation
at all, so EasyTags is careful about one important case: if you've already set
a tag's value to "-" (Go's idiom for "never serialize this
field"), it leaves that tag exactly as it is. Your opt-outs stick. It only fills
in what's missing; it doesn't bulldoze what you meant.
It also grew up with the language — it now supports Go modules, so it slots into
a modern project just as cleanly as it did into a GOPATH one back
in 2015.
Small tool, big quality of life
EasyTags will never make a highlight reel — it's about 75 stars and 19 forks worth of quiet "oh, that's nice." But removing a small, constant friction from everyday coding compounds in a way that flashy features rarely do. You stop thinking about tags entirely; they're just always correct.
That's the whole philosophy, really: the best tools are the ones you forget you're using. EasyTags is one of those — a Betacraft side-quest that turned a daily papercut into a directive you write once and never think about again.