Field

One App, Two Shops — If the Second Shop Is a Code Change, You Have Lost

Two cafés share the same counter screen. Prices, hours and menus differ, and one quotes tax-inclusive while the other adds it at the counter. Not one character of either shop's name appears inside the bundle, and the verification protects that with a single grep.

By makemind · Aug 18, 2026

This is not a specific business. We constructed the common shape of one person running two cafés. The shop names, prices and menus are invented; the code, screens and logs actually ran.

A second shop has opened. You want to use the first shop's app as it is.

Here is what usually happens.

if (shopName == 'Riverside') { ... } else { ... }

And again at the third shop, and again at the fourth. Two years later the file still holds a branch for a shop that closed, and nobody dares delete it.

The app must not know the shop

This sample has one rule.

/// The tempting shape is a `shopName` switch somewhere. Then the second shop
/// is a code change, the third shop is a code change, and eventually the file
/// has a branch for a shop that closed two years ago.
///
/// So nothing here knows any shop's name. The config file is an argument.

A shop is a config file, and the config file lives outside the app.

shop.mbd/          ← the app. shared by both shops
configs/
  riverside.json   ← shop 1
  hilltop.json     ← shop 2

Same files, different shops

RIVERSIDE · Counter · 07:00 - 20:00 — the shop name in the shop's own colour, the board, the basket and tax, DUE 7000 won, and a button that says `Charge 7000 won`
RIVERSIDE · Counter · 07:00 - 20:00 — the shop name in the shop's own colour, the board, the basket and tax, DUE 7000 won, and a button that says Charge 7000 won
The same screen file, the other shop — HILLTOP · 09:00 - 18:00. Different menu, different prices, a different tax rule, DUE 12100 won, and the footer reads "10% tax added at the counter"
The same screen file, the other shop — HILLTOP · 09:00 - 18:00. Different menu, different prices, a different tax rule, DUE 12100 won, and the footer reads "10% tax added at the counter"
shop.mbd — 3 files, sha256:f5f905958eac

[riverside.json] RIVERSIDE · 07:00 - 20:00 · 3 items on the menu
[hilltop.json]   HILLTOP   · 09:00 - 18:00 · 4 items on the menu
same screen file, two shops: RIVERSIDE due 7000 won vs HILLTOP due 12100 won

The whole bundle is hashed. Whatever differs between the two shops, it is not in there.

The verification is one grep

This piece's claim reduces to a single check.

for NAME in Riverside Hilltop; do
  if grep -RIiq "$NAME" shop.mbd shop_server/bin; then
    echo "   \"$NAME\" appears inside the app — the difference has leaked in"; exit 1
  fi
done
   neither shop name appears in shop.mbd or shop_server/bin

If a shop name appears inside the app, it fails. This check goes red the moment somebody in a hurry adds one line of if (shop == 'Hilltop'). That is why it exists — that line always arrives when somebody is in a hurry.

Press something that is not on the menu

The screen file is the same, so the carrot cake button is on both shops' screens.

Riverside does not have carrot cake.

[riverside.json] add CK -> "CK is not on this menu"
[hilltop.json]   add CK -> "added Carrot cake"

The server refuses.

// A sku that is on one shop's menu and not the other's must be refused
// here, not hidden by the screen. The screen is the same file in both
// shops and cannot know.
if (item.isEmpty) {
  return _state(notice: '$sku is not on this menu');
}

This is the other face of the same story as Who May Press This. There, authorisation lived outside the screen; here, the catalogue lives outside the screen. What they share is that the screen is the same file, and the same file cannot decide anything.

This content requires Developer or above

Sign in and upgrade your plan to continue reading.

View Plans
Twitter