SSOT相關經驗分享
問題描述
在專案推進過程中,我遇到的難點是同一類配置需求逐漸擴散到多個情境,若各處各自維護,規則容易分歧,調整時也會產生連動修改與一致性風險。
這類問題在需求持續變動時會快速放大維護成本,因此需要用更集中、可控的方式管理。
實際使用情境
因為會涉及到動態切換需求規則的問題,因此這個案例我是使用 Vue 的 Composable 來進行實作。
實作方式
以 SystemPreset 為單一來源,面板再用 PanelPreset 映射子集;usePanelPreset 用 unref 讀目前方案,再以 對照表(map) 取出標題/描述/標籤文案,並保留未知值時的回退組合。下方為教學專案中的實作整理。
注意:以下程式碼經過優化與再改善(並非公司專案中所使用的程式碼),會比實際上在專案中使用的程式碼還要簡單且易懂。
ts
export const SystemPreset = {
BASIC: 1,
ADVANCED: 2,
COMPACT: 3,
EXTENDED: 4,
QUICK: 5,
FULL: 6,
DEFAULT: 7,
LITE: 8,
} as const;
export type SystemPreset = (typeof SystemPreset)[keyof typeof SystemPreset];ts
// composable/usePanelPreset.ts — 面板方案:明確子集 + 型別
import { computed, unref, type Ref } from "vue";
import { SystemPreset } from "@/lib/enum";
export const PanelPreset = {
BASIC: SystemPreset.BASIC,
ADVANCED: SystemPreset.ADVANCED,
COMPACT: SystemPreset.COMPACT,
EXTENDED: SystemPreset.EXTENDED,
QUICK: SystemPreset.QUICK,
DEFAULT: SystemPreset.DEFAULT,
} as const;
export type PanelPreset = (typeof PanelPreset)[keyof typeof PanelPreset];
type PanelPresetTokens = {
title: string;
description: string;
badge: string;
};
/** 各 PanelPreset 對應的一組 UI 文案規則(單一對照表,避免三份 switch 重複) */
const panelPresetMap: Record<PanelPreset, PanelPresetTokens> = {
[PanelPreset.BASIC]: {
title: "基本方案",
description: "適合一般使用情境",
badge: "General",
},
[PanelPreset.ADVANCED]: {
title: "進階方案",
description: "提供更多可調整選項",
badge: "Advanced",
},
[PanelPreset.COMPACT]: {
title: "精簡方案",
description: "聚焦核心操作流程",
badge: "Compact",
},
[PanelPreset.EXTENDED]: {
title: "擴充方案",
description: "支援更多延伸情境",
badge: "Extended",
},
[PanelPreset.QUICK]: {
title: "快速方案",
description: "適合快速設定與導入",
badge: "Quick",
},
[PanelPreset.DEFAULT]: {
title: "預設方案",
description: "提供穩定且通用的預設值",
badge: "Default",
},
};
const PANEL_PRESET_FALLBACK: PanelPresetTokens =
panelPresetMap[PanelPreset.DEFAULT];
export const usePanelPreset = (panelPreset: Ref<PanelPreset> | PanelPreset) => {
const preset = computed(() => {
const value = unref(panelPreset);
return panelPresetMap[value] ?? PANEL_PRESET_FALLBACK;
});
const title = computed(() => preset.value.title);
const description = computed(() => preset.value.description);
const badge = computed(() => preset.value.badge);
return {
title,
description,
badge,
};
};