How would you model products, variants and attributes for a catalogue that spans very different categories?
Separate the product a customer shops for from the variant that carries a barcode and stock, decide which attributes are variant-defining rather than merely descriptive, and hold the rest in a typed per-category schema, because a fixed column set cannot grow and an untyped bag cannot be trusted.
What the interviewer is scoring
- Does the candidate separate the shoppable product from the stock-keeping unit, and say which one carries price and inventory
- That they can distinguish attributes that define a variant from attributes that only describe one
- Whether the answer explains why a wide table and a schemaless blob fail for different reasons rather than picking one on taste
- Does the candidate treat the attribute schema itself as governed content with an owner
- Whether enrichment and data quality are described as continuous operations with measurable coverage, not a one-off import
Answer
Two entities that get conflated into one
Start by naming the two things that a single "product" record is usually trying to be at once. There is the thing a customer shops for, browses to, reads reviews about and shares a link to. There is also the thing that has a barcode, sits on a specific shelf, has a weight for shipping and can be counted. Those are different objects with different lifecycles, and merging them is the root of most catalogue pain.
Call the first a product and the second a variant. The product owns the title, the description, the category, the brand, the marketing imagery and the review aggregate. The variant owns the identifier, the price, the inventory, the dimensions and the images that differ by colour. A product with no variants is meaningless to fulfilment, and a variant with no parent is meaningless to merchandising, so both exist always, even where a product has exactly one variant.
Identity deserves a sentence of its own because it is where migrations go wrong. Your internal variant identifier should be opaque and permanent, and it should never be reused when a variant is discontinued, because order history, returns and financial records point at it for years. External identifiers such as a GTIN or a manufacturer part number belong alongside it as attributes, not in place of it, since they are assigned by someone else, are sometimes absent, and are occasionally wrong.
Which attributes create a variant, and which only describe one
This is the distinction that separates a candidate who has modelled a catalogue from one who has read about modelling a catalogue. Colour and size on a T-shirt are variant-defining: they are the axes a customer picks along, they must be selectable in the UI, and every combination is a separate purchasable unit. Fabric composition, care instructions and the neckline are descriptive: they vary by product but not within it, and putting them on the variant duplicates them across every row.
Get this wrong in either direction and it hurts. Promote a descriptive attribute to a variant axis and you multiply your variant count for no commercial reason, and someone has to maintain stock levels for combinations that do not exist. Demote a genuine axis to a description and you cannot sell size 10 separately from size 11, which is not a modelling inconvenience but a broken shop. Note also that the axes are a property of the category, not the platform: apparel varies by size and colour, paint varies by finish and volume, memory varies by capacity, and a laptop may vary along five axes at once.
Why the rigid schema and the free-for-all both fail
The tempting first design is a wide table with a column for every attribute the business currently cares about. It fails on change, not on correctness. Every new category needs a migration, most rows are null for most columns, and within two years the table has three hundred columns of which any given product uses twelve. Worse, the null-heavy shape makes it impossible to distinguish "this attribute does not apply to this category" from "nobody has filled it in yet", and those two states need completely different operational responses.
The equally tempting second design is a single untyped document per product, and it fails on trust. Nothing stops one supplier feed writing "weight": "1.2kg" while another writes "weight": 1200 and a third writes "Weight": "approx 1.2 kilos". You cannot filter on it, you cannot sort on it, you cannot validate it, and the faceted navigation that search depends on becomes a set of one-off string-cleaning rules. Flexibility that permits contradictory values is not flexibility, it is deferred work.
What survives is a middle position where flexibility is bounded by declaration. An attribute is a first-class record with a code, a data type, a unit where relevant, an allowed-value list where the type is an enumeration, and a per-category assignment saying whether it is required, optional or inapplicable. Values are stored against that definition, so validation happens on write rather than in a nightly report.
// An attribute definition, versioned and owned like any other reference data.
{ "code": "shoe_width",
"type": "enum",
"values": ["narrow", "standard", "wide"],
"variantDefining": true, // this axis creates purchasable units
"categories": ["footwear"], // inapplicable elsewhere, not merely absent
"requiredFrom": "2026-01-01" } // existing rows are non-compliant, not invalid
The requiredFrom line matters more than it looks. Tightening a rule on a live catalogue cannot retroactively invalidate a hundred thousand existing products, so a new requirement has to create a backlog of work rather than a wall of validation failures that blocks unrelated edits.
Enrichment is an operation, not an import
The final third of a strong answer is that the catalogue is never finished. Supplier feeds arrive incomplete, arrive in the wrong units, arrive with marketing copy in the specification field, and arrive again next month with the same product described differently. So enrichment is a standing pipeline: ingest the raw feed, keep it immutably as received, map it into your attribute definitions, and record the provenance of every value so that when a value is wrong you know whether to fix the supplier, the mapping or the manual override.
That in turn requires a precedence order, because the same attribute will arrive from several places. A typical order is manual editorial override, then a trusted data pool, then the supplier feed, then a derived or inferred value, each labelled as such. Inferred values in particular must be marked, because the day you start filling gaps with a model's best guess is the day someone reads an invented dimension as fact.
Measure the result rather than asserting it. Useful measures are attribute completeness by category weighted by traffic, the count of values failing their own declared type, the age of the oldest unreviewed override, and the rate at which support tickets or returns cite wrong product data. The last one is the only measure that connects catalogue quality to money, which is what makes it the one worth showing a business stakeholder.
Completeness weighted by traffic is the number to optimise, not completeness overall. Ninety-five percent coverage across the catalogue can still mean the twenty products on your homepage are the ones missing a size chart.
Likely follow-ups
- A supplier starts selling shoes in half sizes in one region only. What changes in your model?
- How would you handle a bundle or kit that is sold as one item but picked as four?
- Two suppliers send the same physical product under different identifiers. How do you detect and merge them?
- Where would you put localised attribute values, and what happens when a translation is missing?
Related questions
- Why does a bank end up knowing the same person as six different customers, and what does it take to give them one identity?hardAlso on data-quality5 min
- One machine's clock is ninety seconds ahead of the rest of the plant. Which of your numbers are wrong, and how would you have found out?hardAlso on data-quality6 min
- How do you match patient records across systems when there is no shared identifier?hardAlso on data-quality6 min
- You are mapping data from a legacy system into a replacement and the two define a customer differently. How do you work that out?hardAlso on data-quality4 min
- A supplier sends you a feed of ten thousand products. How many of them are already in your catalogue?hardAlso on data-quality5 min
- A dashboard has been showing the same temperature for two days and nobody noticed. Walk the path and tell me what would have caught it.hardAlso on data-quality6 min
- The operations team says there is no rule for this, they just use judgement. How do you model that?hardSame kind of round: design6 min
- You have been handed a scope and a budget, and the budget cannot buy the scope. What do you put in front of the customer?hardSame kind of round: design5 min