Bootstrap

从乐高积木到代码拼图:组合式设计在Vue3项目中的实践智慧

序幕:一个表单引发的思考

在某个金融数据分析系统的开发过程中,我们遇到了一个看似简单的需求:在多个页面展示包含业务名称和时间区间的搜索表单。初始实现如同大多数项目的起点——一个全功能的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(参数转换器)
└── 页面配置(外观设计)

组合式设计的双重价值

对开发者的技术价值

  1. 可维护性:当时间格式需要调整时,只需修改useFinalParam一处
  2. 可测试性:核心逻辑可脱离UI进行单元测试
  3. 演进自由:新增页面时,可选择组合现有模块或者替换现有模块,由于没有修改,因此,不会对已有的其它逻辑造成冲击。

对管理者的战略意义

  1. 风险控制:修改影响范围明确,降低变更成本
  2. 资源优化:新人只需掌握模块接口,无需理解全部实现
  3. 进度可视:功能开发转化为模块拼装,进度预估更准确

“好的架构应该像城市供水系统——核心管道稳定可靠,末端接口灵活多变。”

平衡的艺术:简洁与扩展的博弈

在是否要创建超灵活useFinalParam的讨论中,我们最终选择保持适度简洁:

// 适度简洁的实现
export default function useFinalParam(searchParam) {
  // 明确处理时间参数,不引入过度配置
  const finalParam = computed(() => {...});
  return { finalParam };
}

这个决策体现了软件工程中的重要原则:

  • YAGNI原则 (You Ain’t Gonna Need It):不为假设的未来需求编码
  • KISS原则 (Keep It Simple, Stupid):用最简单的方案解决问题
  • 渐进式复杂化:当变化真正发生时再扩展架构

结语:构建可生长的系统

通过这个案例,我们见证了组合式设计如何让代码库像生物体般有机生长:每个模块都是可独立进化的"细胞",通过明确定义的接口与其他模块协作。这种设计不仅提升了开发效率,更重要的是构建了一个可持续发展的系统——既能快速响应当前需求,又能从容面对未来变化。

对技术团队而言,这是提高交付质量的工程方法;对管理者来说,这是降低技术债务的战略投资。当代码的拼图艺术遇上软件工程的最佳实践,我们收获的不仅是优雅的代码,更是可预期的项目未来。

相关文章:

;