複数ショップを同じコードで動かす時、
最初は設定ファイルを増やせばいけると思っていました。
ショップ名、ロゴ、テーマカラー、商品取得先、メニュー。
それぞれを tenant ごとの config にしておけば良さそう。
ただ、少し進めると、
「設定で吸収するもの」と「コードを分けるもの」の境界が気になってきました。
なんでも config にすると読みにくいし、
なんでも component 分岐にすると増えた時に怖い。
最初に置いた形
ざっくりこういう設定を考えました。
interface TenantConfig {
id: string;
name: string;
domains: string[];
theme: {
primaryColor: string;
logoUrl: string;
};
commerce: {
shopDomain: string;
accessToken: string;
};
navigation: {
mainMenuHandle: string;
};
}
このくらいなら良さげです。
ショップごとに違うけど、アプリの構造は変わらないもの。
ここは設定で持っておくと楽。
だんだん迷うところ
迷ったのは、トップページやセクションの違いです。
あるショップだけ特別なヒーローを出したい。
あるショップだけランキングを出したい。
あるショップだけニュースを別の見せ方にしたい。
こういう要望が来た時に、
if (tenant.id === 'shop-a') {
return <SpecialHome />;
}
とやると早いです。
早いんですが、これを増やしていくと、たぶん後で読むのがつらい。
なので、設定で差し替えられるところは差し替えたい。
interface TenantConfig {
id: string;
components?: {
home?: 'standard' | 'magazine' | 'campaign';
};
}
でも、これもやりすぎると config が小さいCMSみたいになっていきます。
ああ、これは危ないなと。。。
config に向いているもの
触っていて、config に向いているのはこのあたりだと思いました。
- ドメイン
- API接続情報
- テーマカラー
- ロゴ
- メニューの取得キー
- feature flag
- 表示する/しない程度の切り替え
値で表せるもの。
あと、増えても読みやすいもの。
code に残した方が良さそうなもの
逆に、無理に config にしない方が良さそうなのはこのあたりです。
- 複雑なレイアウト差分
- 商品の並び替えロジック
- 特定ショップだけの導線
- APIレスポンスの解釈
- UIの状態管理
この辺りを JSON や TS object に押し込むと、
型はあるのに何をしているか分からない、みたいな状態になります。
それなら component として分けた方がまだ読める。
const homeComponents = {
standard: StandardHome,
magazine: MagazineHome,
campaign: CampaignHome
};
const Home = homeComponents[tenant.components?.home ?? 'standard'];
このくらいなら許せそう。
でも sections: [...] で何でも組めるようにするところまで行くと、
それはもう別の管理画面が必要な気がします。
tenant config が増える問題
テナントが少ないうちは、静的 import でも困りません。
import { shopA } from './shop-a';
import { shopB } from './shop-b';
export const tenants = {
[shopA.id]: shopA,
[shopB.id]: shopB
};
ただ、これが増えてくると、
「新しいショップを追加する時に、どこを触ればいいんだっけ?」となりがちです。
domain mapping に追加する。
tenant config を追加する。
テストデータを追加する。
E2E の対象にも入れる。
この手順が README にしかないと、たぶん漏れます。
チェックしたいこと
今なら、tenant config は書くだけじゃなくて、チェックも用意したいです。
for (const tenant of Object.values(tenants)) {
assert(tenant.id);
assert(tenant.domains.length > 0);
assert(tenant.commerce.shopDomain);
assert(tenant.navigation.mainMenuHandle);
}
本当は zod でも valibot でも JSON Schema でも何でもいいんですが、
「全テナントが最低限の設定を持っている」ことはテストしたい。
人間が見ているだけだと、増えた時に漏れそう。
おわり
マルチテナントの config は便利です。
でも、便利なので何でも入れたくなります。
そこが危ない。
2020年の自分なら、たぶん動いたところで満足していたと思います。
今はもう少しだけ先を見て、
「この設定が10個、20個に増えても読めるか」
「新しいショップを追加する時に、漏れを検知できるか」
を気にするようになりました。
全部を完璧に設計する必要はないけど、
設定の境界とチェックだけは、早めに置いておくと後で効きそうです。