我曾经以为,改造一个大型工作台,最难的是把页面做得足够完整。既要有首页,也要有搜索、内容源、评论、版本、素材和审看;最好再加上命令面板、深链和手机布局。只要这些功能都出现,工作似乎就完成了一大半。
后来我参与了一次连续多期的工作台改造,才发现“完整”是一个很容易误导人的词。一个页面可以看起来很丰富,背后的数据却没有边界;一个按钮可以点开,深链却不能恢复上下文;桌面上很漂亮,手机上却无法审看。真正难的不是把功能堆到一起,而是让每一次变化都能被确认、被回退、被解释。
这次改造从数据基础开始,经过内容源扩展、视觉与交互重做、验收返工,最后再集中处理安全缺陷和代码整理。测试数量从第 2 期的 30 项,到第 3 期的 43 项、第 4 期主体的 50 项,返工后增至 51 项,第 5 期全量回归达到 69 项。数字本身不是成绩单,它们更像一条轨迹:范围变大了,检查也必须跟着变细。
先把不能突破的边界画出来
第一期改造最值得保留的经验,并不是新增了哪些面板,而是动手前先把边界写清楚。可写数据独立落盘,写接口必须同时满足请求头、权限和审计要求;服务只接受本机访问;外部内容源只索引,不复制、不改写;不登录、不操作发布平台;每次开始前先保存快照。
这些要求在当时看起来不像“产品功能”,甚至会让页面推进慢一点。但我选择先做它们,是因为工作台一旦拥有写入能力,错误就不再只是页面上的小瑕疵。一次错误请求可能覆盖数据,一次不受约束的静态访问可能暴露审计记录,一次把外部源当成本地目录处理的便利,可能让原始资料失去可追溯性。
大型工作台的第一条验收标准,不是能显示多少内容,而是出了问题以后还能不能知道发生了什么、恢复到哪里。
第 2 期先完成权限和审计,再接评论、版本对比和审看面板。评论支持新增、完成、重开和软删除,版本可以并排对比,发布台账也只读导入。最后完成了 30 项测试,同时留下 50 条无法精确匹配的台账,以及因排期或证据不足暂时跳过的记录。这种“未完成也要留账”的做法很重要,因为没有证据的匹配,表面上让列表更整齐,实际上会把猜测伪装成事实。
扩源不是把目录越接越多
第 3 期要接入更多内容源。最容易误判的地方,是把“能查到”当成“已经接入”。如果一个工作台可以从多个位置读取内容,就必须回答几个更基础的问题:源数据是否只读,挂载是否安全,查询是否会无限等待,导入是否幂等,无法匹配的记录怎么显示。
所以这期采用独立的只读适配方式,让视频库和全局索引共享派生清单,不直接改动源。查询过程增加路径限制和 12 秒超时,不调用会刷新归档、切片或导出的动作。实测中,本地归档和 HTTP 镜像都能播放;文稿、成片和 Skill 页面入口也都接入了工作台。最终测试为 43 项通过,但照片地点查询超过 12 秒、照片缩略图缺少安全映射,这些限制仍然被保留在报告里。
如果不处理这些边界,后果不是“某个页面偶尔加载慢”这么简单。用户会分不清空结果、数据不存在和查询超时;系统也可能为了让页面看起来有内容,擅自猜一个路径或把源文件复制进本地。错误一旦进入索引,后面每一层都会把它当成可靠事实继续使用。
扩展内容源的本质,是扩展可验证的来源,而不是扩展页面上的数量。
这件事让我重新意识到,数据边界其实也是产品体验的一部分。页面明确显示“暂无可播放位置”,比展示一个猜出来的播放器更诚实;明确标记某类资料只是二手整理,也比把它混进本人实录更能帮助用户做判断。
先统一结构,再追求好看
第 4 期进入视觉和交互重做时,页面问题变得更直观:首页层级混乱,卡片展开会破坏媒体墙,审看区域和评论信息互相争夺空间。这里最容易走的错误捷径,是直接逐页调颜色、字号和间距,看到哪处不顺眼就改哪处。
我没有这么做,是因为局部修补解决不了结构冲突。先确定统一的设计方向和共享组件,再实现首页、内页模板、命令面板和独立审看大窗,才能让每一页遵守相同的空间规则。审看时视频占据主要区域,评论和版本操作进入侧栏;桌面和手机不再只是等比例缩小,而是采用不同的信息排列。
随后在 1440、1024 和 375 这 3 种视口逐页检查。检查的不只是截图是否好看,还包括键盘操作、深链直达、后退关闭、版本切换、时间跳转、实际视频播放、横向溢出和脚本报错。主体完成时 50 项回归通过,0 个脚本报错、0 张坏图、0 处横向溢出。
但验收并没有因此结束。返工阶段发现,深链只带入当前资产,首页等待身份接口后才绘制,手机仍沿用桌面卡片,某些页面还有元数据裁切和固定高度留白。修复后,桌面首屏稳定显示 14 张卡,手机首屏显示 7 张卡;无缓存且接口延迟 8 秒时,首页生产数字仍在 154 毫秒内出现;专项测试增至 51 项通过。
表面上看,这是视觉返工;实际上,它是在验证用户是否能从一个入口抵达完整上下文。所谓交互一致,不是每个页面长得一样,而是用户在不同入口都不会丢失方向、状态和下一步。
验收意见要变成证据
返工最考验的不是修复速度,而是能不能区分“意见”和“问题”。一句“手机上不舒服”,需要被拆成卡片尺寸、首屏密度、文字是否溢出、点击区是否足够等可检查的条件;一句“深链不对”,需要明确是没有加载列表、没有恢复高亮,还是后退行为不符合预期。
这也是为什么每期都要先快照,再按用户路径自测。快照让人知道变化从哪里开始;逐项测试让人知道哪一个条件被满足;未匹配台账和数据限制则防止报告把未知写成完成。一个成熟的流程不会因为“最终看起来差不多”就跳过这些记录,因为审看时的感觉很难在下一次复现,量化条件却可以。
如果把所有需求塞进一次大重构,最后才补权限、数据边界和回归,返工会变得非常昂贵。页面改动、安全修复、数据迁移和视觉调整会互相覆盖;出了问题以后,也很难判断是哪个决定引入了缺陷。更糟的是,团队可能为了保住“整体完成”的印象,选择忽略那些暂时无法解释的异常。
每个阶段都应该有自己的完成定义,阶段之间靠快照和回归连接,而不是靠记忆连接。
安全修复要先于重构
第 5 期的顺序尤其说明问题:先处理安全 P1,再做其余缺陷和纯代码整理。修复集中在请求入口,包括静态文件白名单、Host 与同源校验、媒体扩展名限制,以及挂载检查。隔离回归覆盖大小写、编码遍历、双斜杠、软链逃逸、恶意来源和禁止的文件类型。
这项修复没有被“先把代码整理漂亮”打断,是因为安全问题和视觉问题的风险等级不同。重构可以在行为不变的前提下慢慢做,边界缺失却可能让不该访问的内容先暴露出去。实际迁移中,白名单曾漏放某个内容源必需的台账文件,旧测试也需要调整预期。只有把这些具体问题跑通,才能证明安全规则没有把正常功能一起挡掉。
最后的回归覆盖 69 项 Python 测试、32 个页面视口、15 个页面按钮操作、命令面板、审看流程和缺陷专项检查;坏图、横滚和浏览器报错均为 0。数据完整性也被单独核对,1769 个资产标识保持不变,旧链接逐行比对,仍被引用的旧地址继续保留。
我更愿意把这看成一种工作习惯:先处理会造成不可逆损失的边界,再处理影响理解的交互,最后处理让代码更容易维护的整理。顺序不是形式,它决定了出了问题以后还能不能保住原来的证据。
下次我会怎么做
下次遇到类似的大型工作台,我会先把需求分成 4 张表:不可突破的安全边界、只读或可写的数据源、这一期唯一要交付的用户路径、可以量化的验收指标。没有这 4 张表,我不会因为页面已经搭出来就宣布进入下一步。
每个阶段开始前保存快照,完成后只验收本阶段范围。数据源扩展时,先问它能否解释来源、权限、超时和失败状态;交互重做时,先统一结构,再看局部样式;收到返工意见时,把形容词翻译成尺寸、数量、时间和行为;涉及安全时,把修复放在重构之前。
最后用跨页面、跨视口和接口级回归收口,并单独记录未匹配项、超时项和暂时缺少映射的内容。一个流程成熟的标志,不是它能把项目一次跑通,而是它能让下一次少依赖临场记忆。
大型改造之所以必须按阶段推进,不是因为人没有能力一次做完,而是因为系统里的风险、数据和判断不能同时被看清。阶段化让每次变化都有边界,让每个缺陷都有出处,也让“看起来完成”最终变成“可以被证据支持”。