現場

アプリひとつで二店舗 — 二軒目がコード修正になったら負けだ

同じカウンター画面を二軒のカフェが使う。価格も営業時間もメニューも違い、一方は税込表記、もう一方は税別だ。バンドルの中には二店舗の名前が一文字もなく、検証がそれを grep 一行で守る。

著者: makemind · 2026年8月18日

二軒目が開いた。一軒目のアプリをそのまま使いたい。

ここでたいていこうなる。

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

そして三軒目でもう一度、四軒目でもう一度。二年後にはすでに閉めた店舗の分岐がファイルに残り、誰も消せない。

アプリは店舗を知ってはならない

このサンプルの規則はひとつだ。

/// 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.

店舗は設定ファイルであり、設定ファイルはアプリの外にある。

shop.mbd/          ← アプリ。二店舗共用
configs/
  riverside.json   ← 店舗1
  hilltop.json     ← 店舗2

同じファイル、違う店舗

RIVERSIDE · Counter · 07:00 - 20:00 — 店名はその店の色で。メニューの下にかごと税、DUE 7000 won、ボタンは `Charge 7000 won`
RIVERSIDE · Counter · 07:00 - 20:00 — 店名はその店の色で。メニューの下にかごと税、DUE 7000 won、ボタンは Charge 7000 won
同じ画面ファイル、別の店 — HILLTOP · 09:00 - 18:00。メニューも価格も税の扱いも違い、DUE 12100 won、下段は "10% tax added at the counter"
同じ画面ファイル、別の店 — HILLTOP · 09:00 - 18:00。メニューも価格も税の扱いも違い、DUE 12100 won、下段は "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

バンドル全体をハッシュで焼いた。二店舗の間で何が違おうと、あの中にあるのではない。

検証は grep 一行だ

この編の主張は検査ひとつに要約される。

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 (shop == 'Hilltop') を一行入れた瞬間に赤くなる。それがこの検査の存在理由だ — その一行はいつも急いでいるときに入る。

メニューにないものを押したら

画面ファイルが同じなのでキャロットケーキのボタンは二店舗の画面に同じようにある。

リバーサイドにキャロットケーキはない。

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

拒否はサーバーがする。

// 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');
}

これはこれは誰が押していいのかと同じ話の別の顔だ。あちらでは権限が画面の外にあり、ここではカタログが画面の外にある。共通点は画面が同じファイルだということであり、同じファイルは何も決定できない。

このコンテンツは開発者以上が必要です

サインインしてプランをアップグレードすると続きを読めます。

プランを見る
Twitter