健身练习渲染用Array of Arrays和array of objects两种结构是否合理?
你的现有设计逻辑本身是自洽的,针对两种场景的存储设计也符合业务需求,但是确实存在几个潜在的风险点:
潜在bug风险
- 类型判断容错性差:一旦
type字段出现拼写错误、枚举值不统一(比如同时存在circuit和superset两种标记),会导致组件加载错误,普通组件拿到数组套数组的sets数据时,访问对象属性会直接抛出未定义错误。 - 公共逻辑重复易出错:统计总训练组数、计算训练容量、导出训练记录这类和
sets相关的通用逻辑,需要针对两种数据结构写两套处理分支,漏写任意分支的边界处理都会出现异常。 - 序列化/持久化风险:如果数据需要存入后端、本地缓存或者做跨端同步,没有严格的结构校验的话,很容易出现嵌套数组被扁平化、对象属性丢失的问题,读取后直接打乱训练数据逻辑。
- 开发阶段易出现属性访问错误:如果没有用TypeScript定义严格的可辨识联合类型,开发时很容易混淆两种
sets的结构,错误的访问方式不会在开发阶段提示,上线后才会触发bug。
新功能不兼容的处理方案
针对后续新功能不兼容的问题,可按照改动成本从低到高选择以下方案:
- 优先做统一适配层,避免业务逻辑直接接触原始结构:封装一批和exercise操作相关的公共工具函数,比如
getExerciseSets、deleteExerciseSet、addNewSet,内部自动根据type处理不同的sets结构,对外输出统一格式的返回值,所有新功能只调用这些工具函数,不需要关心底层存储结构。 - 上层逻辑统一结构,加载时做自动转换:如果新功能对数据结构的一致性要求很高,可以在exercise数据加载完成后,先做一层格式转换:把普通练习的
sets也转换成数组套数组结构,每个子数组只包含当前单个练习的对象,后续所有业务逻辑都按照统一的嵌套数组结构处理,渲染时判断子数组长度,长度为1走普通练习组件,长度>1走superset组件即可,从根源消除结构差异。原有的渲染判断逻辑也可以简化为:
{exercises.map((exercise) => exercise.sets[0].length > 1 ? <RenderCircuit/> : <RenderRegularExercise/>}
- 增加严格的运行时校验:不管是新老数据,加载时都用校验逻辑(比如Zod、自定义校验函数)检测结构合法性,结构不匹配的情况要么自动修正为标准格式,要么抛出明确的异常提示,避免错误数据流入业务流程。
- 历史数据灰度迁移:如果最终要替换为统一的新数据结构,可以给数据加版本号标记,加载时识别低版本的旧结构,自动转换成新结构后再做后续处理,存储时也直接存新结构,待全量旧数据都迁移完成后,就可以完全移除旧结构的兼容逻辑。

内容的提问来源于stack exchange,提问作者Lukas Vis
相关产品推荐
相关产品推荐

