DEV Community

A column changed type 8 days after I mapped it, and nothing told me

I was rewriting a Java/Spring backend to Go. The database wasn't going anywhere - it already existed, with real data in it, and eighteen tables' worth of history behind it. The plan was simple: keep the schema, replace the service layer. Early on, asset looked like this: CREATE TABLE asset ( id bigint NOT NULL AUTO_INCREMENT, ... value int NOT NULL, PRIMARY KEY (id) ); I mapped it to a Go struct by hand, the way you do when you're moving fast and the table is right there on the screen: type Asset struct { ID int64 Value int64 ... } Eight days later, a migration I wasn't looking at changed it: ALTER TABLE asset CHANGE value value DECIMAL(19, 2) NULL DEFAULT NULL; int NOT NULL became decimal(19,2) NULL . Two changes at once, and my hand-written struct still said int64 , no pointer, no way to represent NULL. Nothing failed loudly - GORM will happily scan a decimal into an int64 and either round it or blow up on a NULL, depending on the day. It's the kind of bug that shows up as "why is this value off by a few cents" three weeks later, not as a compile error. That's when it clicked: I don't need a unit test for "does my Go struct still match the asset table." I need something that reads the table and tells me if it doesn't. So instead of writing the struct by hand, I pointed a small code generator I'd built for exactly this - reads live schema over JDBC, spits out Go structs - at the same database, and diffed the output against what I had. It caught value immediately: wrong type, wrong nullability, no compile error to warn me. None of this is exotic. If you're doing DB-first Go with GORM, this is just what happens when the schema evolves and your structs are maintained by hand, by a human, on a Tuesday. The fix isn't "write more tests" - it's "stop hand-maintaining the mapping between a table and a struct, and regenerate it from the table instead." A unit test only catches what you thought to test. A schema read catches what actually changed. I ended up formalizing this into SQL DAL Maker - it reads live JDBC metadata and generates the DAO/model layer for Go (and a few other languages) from it, so the struct-vs-schema gap can't quietly reopen every time someone runs a migration. But the generator isn't really the point of this post. The point is: if your models are hand-typed and your schema isn't frozen, you already have this bug somewhere. You just haven't hit it yet. Top comments (0)

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.