序幕:一个表单引发的思考
在某个金融数据分析系统的开发过程中,我们遇到了一个看似简单的需求:在多个页面展示包含业务名称和时间区间的搜索表单。初始实现如同大多数项目的起点——一个全功能的SearchForm组件,搭配近100行的逻辑代码。
// 初始实现:集所有功能于一身的单体组件
export function useSearchParam() {
const enumMap = ref(new Map());
const searchParam = reactive({});
const searchFormItems = reactive([...]);
const finalParam = computed(() => {...});
// 业务名称加载、参数重置等逻辑混杂其中
onMounted(async () => {...});
const reset = () => {...};
return { enumMap, searchParam, searchFormItems, finalParam, reset };
}
这种设计短期内快速满足了需求,但当第二个需要类似表单的页面出现时,问题开始显现——就像试图用同一块乐高积木拼出不同造型,我们不得不复制80%的代码,再修改20%的差异。
第一次重构:发现代码的"积木颗粒"
1.1 识别通用逻辑
通过分析两个页面的表单组件,我们发现三个稳定的核心元素:
- 业务名称加载:从Store获取数据并初始化
- 参数管理:响应式参数对象与重置逻辑
- 时间处理:时间区间到时间戳的转换
// 提取出的核心逻辑模块
function useCore(initSearchParam) {
const enumMap = ref(new Map());
const searchParam = reactive(initSearchParam);
onMounted(async () => {
// 业务名称加载逻辑
});
return { enumMap, searchParam, reset };
}
1.2 构建组合接口
将通用逻辑封装为useCore
后,表单组件蜕变为:
export function useSearchParam() {
const { enumMap, searchParam, reset } = useCore();
const searchFormItems = reactive([...]); // 页面特有配置
const finalParam = computed(() => {...}); // 特有转换逻辑
return { enumMap, searchParam, searchFormItems, finalParam, reset };
}
这如同将乐高套装拆分为基础底板和可更换的装饰件。项目经理可以这样理解:我们建立了标准化的生产线(useCore),允许不同产品(页面)使用相同的核心部件,仅定制外观设计(表单字段)。
第二次重构:参数的"变形金刚"
当时间参数处理逻辑需要复用时,我们进行了更精细的拆分:
// 独立的时间处理模块
export default function useFinalParam(searchParam) {
const finalParam = computed(() => ({
...removeTimeKey(searchParam),
...convertTimeRange(searchParam)
}));
return { finalParam };
}
此时的组件结构呈现出清晰的层次:
hooks
├── useCore(核心引擎)
├── useFinalParam(参数转换器)
└── 页面配置(外观设计)
组合式设计的双重价值
对开发者的技术价值
- 可维护性:当时间格式需要调整时,只需修改
useFinalParam
一处 - 可测试性:核心逻辑可脱离UI进行单元测试
- 演进自由:新增页面时,可选择组合现有模块或者替换现有模块,由于没有修改,因此,不会对已有的其它逻辑造成冲击。
对管理者的战略意义
- 风险控制:修改影响范围明确,降低变更成本
- 资源优化:新人只需掌握模块接口,无需理解全部实现
- 进度可视:功能开发转化为模块拼装,进度预估更准确
“好的架构应该像城市供水系统——核心管道稳定可靠,末端接口灵活多变。”
平衡的艺术:简洁与扩展的博弈
在是否要创建超灵活useFinalParam
的讨论中,我们最终选择保持适度简洁:
// 适度简洁的实现
export default function useFinalParam(searchParam) {
// 明确处理时间参数,不引入过度配置
const finalParam = computed(() => {...});
return { finalParam };
}
这个决策体现了软件工程中的重要原则:
- YAGNI原则 (You Ain’t Gonna Need It):不为假设的未来需求编码
- KISS原则 (Keep It Simple, Stupid):用最简单的方案解决问题
- 渐进式复杂化:当变化真正发生时再扩展架构
结语:构建可生长的系统
通过这个案例,我们见证了组合式设计如何让代码库像生物体般有机生长:每个模块都是可独立进化的"细胞",通过明确定义的接口与其他模块协作。这种设计不仅提升了开发效率,更重要的是构建了一个可持续发展的系统——既能快速响应当前需求,又能从容面对未来变化。
对技术团队而言,这是提高交付质量的工程方法;对管理者来说,这是降低技术债务的战略投资。当代码的拼图艺术遇上软件工程的最佳实践,我们收获的不仅是优雅的代码,更是可预期的项目未来。
相关文章: