A news publisher's shared story-teaser component has grown to forty properties; what does that signal, and how would you restructure it?
answer
- properties that only work together
- one component, many surfaces
- primitives, slots, recipes
- invariants move into composition
- migrate by usage clusters
basics
~20 sForty properties signal over-configuration: one component absorbing every surface's needs as flags, with interactions nobody tests. Restructure into primitives, named slots for extension, and a few prebuilt recipes, keeping editorial invariants enforced inside the pieces.
solid answer
~40 sIt signals **over-configuration**: the teaser serves the homepage, section fronts, newsletters and the app, and every request was answered with one more property — show-kicker, kicker-text, image-position, hide-image-on-small-screens, is-live, is-sponsored, sponsor-logo. Many only make sense in combination, the test matrix is unmanageable, and teams have started forking. I would split it into **primitives** (container, media, kicker, headline, standfirst, meta, labels), give the teaser **named slots** — defined regions where consumers place their own content — and ship a handful of **recipes** (standard, opinion, live, sponsored, compact) built from those pieces with few properties each. Invariants must survive the split: the headline stays a link, and a sponsored teaser cannot omit its sponsorship label. I would migrate by finding property clusters in consumer code and mapping each cluster to a recipe.
go deeper
Recognise that a component with dozens of interacting properties is a warning sign, and that primitives and recipes are the usual cure.
Explain why properties accrete, name the symptoms — combined properties, surface names, content fragments — and describe primitives, slots and recipes.
Lead the restructure: find usage clusters, map them to recipes, keep editorial invariants inside the pieces, and migrate without breaking every call site at once.
Set the library rule that configuration is never the only extension point, so new product requests are met by composition and the system's surface stops growing with demand.
## Recognising the smell **Over-configuration** is a component that tries to serve every use through properties. A shared story-teaser in a news publisher's library is the classic case: the homepage, section fronts, topic pages, the newsletter, the app's home feed and partner widgets all use it, and each request was met with one more property. At forty properties the symptoms are usually all present: - **Properties that only make sense together** — a kicker flag, kicker text and kicker colour; a sponsored flag and a sponsor logo. - **Properties that toggle layout regions** — hide image, image position, image ratio on small screens. - **Properties named after surfaces** — is-homepage, is-newsletter — which means the component knows who is calling it. - **Properties carrying content fragments** — extra text or pre-formatted snippets passed as values because there is no place to put real content. - **An untestable matrix** — forty booleans and enums allow more combinations than any team can check. - **Forks** — teams copying the teaser because adding "just one more property" takes too long. ## Why it happens Each property was the cheapest *local* change: one line in the component, one line at the call site. Nobody decided to build a forty-property component; it accreted. The cause is structural — one component is being asked to express many layouts, and properties are the only extension mechanism it offers. ## Restructuring into three layers 1. **Primitives** — small pieces with one job each: teaser container, media, kicker, headline, standfirst, byline and timestamp, and labels such as live or sponsored. 2. **Slots** — named regions in the teaser (media, top label, headline, meta, trailing action) where consumers place content. How a framework projects content into a slot is the framework's mechanics; the library decides *which regions exist* and *what each guarantees*. 3. **Recipes** — a handful of ready-made teasers built from the primitives: standard, opinion (with author portrait), live (with pulsing label), sponsored, compact list item. Each has a few properties, because anything unusual uses the primitives directly. | Before | After | |---|---| | kicker flag, kicker text, kicker colour | a kicker primitive placed in the top-label slot | | hide image, image position, image ratio | the media slot, filled or left empty; layout decided by the recipe | | is-homepage, is-newsletter | a recipe per surface family, or composition by the caller | | sponsored flag plus sponsor logo | the sponsored recipe, whose sponsorship label is not optional | ## Keep the invariants Flexibility must not dissolve the rules that the forty properties, clumsily, protected. Some are editorial or legal rather than visual: - A **sponsored** teaser must always show its sponsorship label; no slot arrangement may omit it. - The **headline** is always a heading that links to the story, whatever surrounds it. - **Timestamps** use the publisher's format and time-zone rules. The design move is to push invariants *into* the primitives and recipes — the sponsored recipe renders the label itself — rather than trusting each caller. ## Migrating without a big bang - **Measure first.** Search every consuming codebase for how the teaser is called; property combinations cluster into a few real layouts. - **Map each cluster to a recipe.** Most call sites land on three or four recipes. - **Re-implement the old teaser on the new pieces**, so both paths render the same during the transition. - **Retire the old properties** under the system's deprecation policy once usage drops. ## The general lesson Over-configuration is what happens when **configuration is the only extension point**. Primitives and slots give consumers a second way to get what they need — composition — and recipes keep the common case short. The component's surface stops growing with every new product request.
- How do you stop a slot-based story teaser from letting a team omit the sponsorship label?Do not make the label a slot at all in the sponsored recipe: the recipe renders it itself from the sponsorship data, and the slots it exposes sit around it. Invariants belong inside the pieces that the library controls, not in guidance that every caller must remember.
- What evidence tells you which recipes to build when restructuring an over-configured component?Usage data from the consuming code. Searching every call site shows which property combinations actually occur; they cluster into a few layouts, and those clusters become the first recipes. Anything rare stays a composition of primitives rather than earning its own recipe.
saying these in an interview costs you the question
- Forty properties is fine as long as each one is documented
- The fix is splitting the teaser into forty separate components
- Slots mean the library no longer guarantees anything about the content
- Properties named after surfaces are a clean way to handle variations
- Restructuring means rewriting every call site at once