← All writing
Craft · · 5 min

A simple new field

On the schema that stores everything in one table sideways, why adding a column isn't adding a column, and the estimate I now give for anything with the word "just" in it.

Ecommerce Agency

“Can we add a field to products for the grind size?”

Half a day, I said. It’s a text field.

It was four days. Not because anybody moved the goalposts and not because I hit something exotic. Four days is roughly what that request costs on this platform, every time, and the only thing that had gone wrong was me answering before I understood the shape of the thing I was answering about.

Where a product actually lives

I’d assumed, without examining the assumption, that there was a products table with a column per attribute. Name, SKU, price, weight. Add a field, add a column. That’s how I’d have built it and it’s how the last few things I’d worked on did it.

It isn’t that.

The catalog is stored in an entity-attribute-value layout, which means the product doesn’t have columns. It has rows, in other tables, one per attribute per product. There’s a row saying “product 4021, attribute 73, value ‘Medium’” and attribute 73 is defined somewhere else entirely as a text field called grind_size, and its label, its input type, whether it’s required, whether it’s searchable, whether it appears in listings, and which of the six product types it applies to are all separate rows in separate places.

roughly
entity          4021   sku: CB-1kg-med
attribute         73   code: grind_size, type: varchar, input: select
value_varchar   4021 / 73 / store 0  →  "Medium"
value_varchar   4021 / 73 / store 2  →  "Mittel"      ← the German store
attribute_set     12   "Coffee"      →  includes 73
Text

Once you see it, the reasons are obvious and good. A store can have 40,000 products of nine different kinds, where a coffee has grind size and a grinder has a burr material and neither has the other. A columnar table would be mostly null and would need a migration every time merchandising has an idea. This design lets a non-developer add an attribute through the admin, in the afternoon, without a deploy, and that is a genuinely valuable property.

The flexibility isn't accidental complexity, it's the feature. It just gets paid for in a currency I hadn't been counting.

What the four days actually were

Not one hard problem. Eight small ones, none of which I’d priced.

The attribute has to be created by an install script rather than by hand, because otherwise it exists on my machine and on staging and not in production, and discovering that at 6 pm on a release day is a rite of passage I have now completed.

It has to be assigned to the right attribute sets, and only those, or grind size turns up on the grinders.

It needs a scope decision: global, per-website, or per-store-view. Get this wrong and the German store either can’t translate it or can’t share it, and changing your mind later means a data migration rather than a config change.

It has to be flagged for anywhere it’s meant to appear: listings, layered navigation, search, the comparison table. Each of those is a separate boolean, each of them defaults to no, and each of them silently does nothing until you also reindex.

Then the template work, which was the only part I’d estimated, and which was half a day.

Then the import format changes, because the client updates products by spreadsheet and the spreadsheet now needs a column, and somebody has to tell the person who maintains it.

Estimating a piece, not a job

I wrote a post about estimates being distributions rather than numbers a few weeks ago, and then immediately demonstrated the failure mode it describes: I gave a confident single number for the part of the job I could picture.

I could picture the template. The template was accurate, half a day, as quoted. Everything else was work I didn’t know existed, and you cannot put error bars on a thing you haven’t conceived of.

So the useful heuristic isn’t “add a buffer.” A buffer implies you know the shape and are hedging the size. It’s to notice when you’re estimating a piece of something and to say so out loud: “the front end is half a day, and I don’t yet know what it takes to get the field into the system, so let me look for 20 minutes before I give you a number.”

Nobody has ever refused me the 20 minutes. I just don’t reliably ask for them, because the question arrives in a meeting and “half a day” is a much more socially comfortable sentence than “I don’t know yet.”

Beware the word “just”

Grind size shipped. It’s on the coffee, it’s not on the grinders, it translates, it filters, and the spreadsheet has a column.

And I now have a genuine physical reaction to the word “just” in a sentence about data, which colleagues have started to find funny and which is the only estimating technique I’ve ever had that actually works 🫠

Read similar posts
6 min

The replatform nobody calls a replatform

Moving a store from a server we controlled to one we don't was sold internally as an infrastructure decision, and it is not an infrastructure decision, it's a decision about which problems you're allowed to have.

7 min

The offboarding document

I took over a project in June where the previous developer had left properly, with everything written down, and it was so unusual that I spent the first morning slightly suspicious of it.