9.3 KiB
ETAF 开发约束
本文件适用于 ETAF 及其联调范围内的 etaf-ui、ebox、tp、
etaf-sqlite、etaf-playground。实现与性能优化必须从最终产品目标倒推,
不得用局部完成、容易通过的替代目标缩小原始范围。
最终目标驱动
开始工作前先明确最终可观察结果、硬性指标、不可牺牲的功能、权威验证方式 和停止条件。架构、算法、缓存、预编译与局部优化都只是达到目标的手段,不能 反过来成为交付物本身。
ETAF 当前性能工作的最终结果是:通用性能工具能解释每次操作跨包各阶段的 耗时;固定真实场景在功能、文本属性、身份、生命周期和回滚语义不缩水的前提 下,p95 与 max 都不超过 50ms。
架构与抽象准则
- 先从复杂现象中识别最小、稳定、可命名的领域模型及其不变量,再写代码; 不把偶然的调用顺序、示例名称或当前数据形状伪装成抽象。
- 一个模块只拥有一项完整职责,并为这项职责提供少量、精确、正交的接口。 接口之间通过明确数据契约组合,不读取彼此的内部状态,不复制彼此的规则。
- 用户心智成本是公共 API 的硬指标。同一能力只能有一个规范名称和一条推荐路径; 内部算法、后端节点、兼容别名和便捷 wrapper 不得伪装成并列公共概念。常用路径 只要求学习最小模型,高级能力通过逐层展开获得,不能让用户先理解包内部实现。
- 区分语义身份、视觉槽位、布局坐标、绘制层和发布权限。只有模型本身允许时 才能合并概念;不能为了减少代码把不同生命周期的身份混在一起。
- 复杂系统通过小模块的组合与复用逐步形成。新增能力应优先扩展已有模型的 输入域或组合方式,不平行创建第二套状态、第二条渲染链或只服务一个例子的 特殊协议。
- 架构必须满足性能可组合性。每层只处理变化集合,成本应为
O(changed)或有 明确上界的小常数;模块增加时,总成本应接近各层小常数之和,不能因每层都 重新扫描O(all)而相乘。 - 上一层输出的稳定身份、坐标、依赖、布局证书和绘制贡献就是下一层的输入。 下游不得丢弃这些中间产物后重新推导;一次事务中的同一全量遍历最多发生 一次,多个模块应组合在同一遍历或直接消费保留状态。
- 数据只 materialize 一次。跨层优先传递不可变中间产物、稳定句柄或精确操作 批次;重复建树、重复复制文本、重复合并属性和重复证明都必须有独立收益证据。
- 每个模块都要有独立性能预算和基准。模块单独合格但组合后超标,说明接口 泄漏了重复工作,必须修正边界,不能把额外耗时解释为“架构层数的正常代价”。
- 每条快速路径都必须是普通正确路径的严格子集:入口条件可判定、保留状态可 验证、失败可精确回退、提交与回滚仍由原有权限边界控制。
- 代码量不是进度。没有清晰模型、独立测试和真实收益的辅助层、兼容分支、 预留接口、重复证明与缓存都属于 slop,应删除而不是继续包装。
纵向最小可运行版本
面对架构级任务,先选择一个真实、代表性强、可以端到端运行的最小切片。这个 切片必须同时经过“输入 → 核心机制 → 运行时消费 → 用户可见结果 → 验证”, 不能只交付数据结构、接口空壳、设计文档或与真实应用脱节的玩具示例。
例如 App 预编译应先打通一个真实 View:编译阶段产生中间 blueprint,运行时 只填动态洞,不支持的语法精确回退,真实应用实际使用该产物。只有这个闭环 可运行、结果等价且确有性能收益,才扩展语法和覆盖面。
最小验证循环
每个实现假设都采用下面的短循环:
- 写出本次最小假设以及它应改善的一个可测指标。
- 只实现证明该假设所需的最小代码,不提前铺设后续层次。
- 立即运行最小但有判定力的验证:可运行、结果等价、目标指标改善。
- 验证通过才保留并扩展;失败则先定位原因,无法证明价值的实验立即完整撤掉。
- 每次只扩大一个维度,例如一种语法、一个组件或一个缓存层,然后重复验证。
最小验证不能偷换最终目标。微基准只能证明局部机制;真实跨包场景和完整门禁 仍是最终证据。
可验证的小赌注与反馈控制环
不要把一次无法控制、无法快速证伪的“大赌注”当作工程推进方式。任何跨包、 跨阶段或“国民级应用”尺度的大 gap,都必须拆成一组彼此有清晰因果关系、能够 独立验证和独立回退的小 gap。每个小 gap 只承载一个主要假设,并在扩大范围前 得到新鲜证据。
这不是三条孤立技巧,而是一条完整的反馈控制环:
- 拆解缩短因果距离:一次只改变一个可命名机制,使失败能直接指向假设, 不让多个变量同时变化后再靠猜测定位;
- 验证限制错误传播:定向测试、静态编译、CI、事务回滚和真实 GUI 门禁必须 放在对应边界上,不能等到最终集成时才第一次发现问题;
- 迭代提高反馈频率:小步实现、立即运行最小有判定力的检查,通过后才扩大 一个维度,并在完整子目标证明后及时提交 Git 基线。
工程目标不是假装“零错误”,而是让错误出现得早、扩散得不远、定位有证据、 回退代价低。一个实验若不能快速回答“假设是否成立”,就说明切片仍然过大; 一个门禁若失败后不能指出责任边界,就说明验证粒度仍然过粗。不得用继续堆代码、 增加兼容分支或推迟集成来掩盖反馈环已经失效。
凡目标涉及用户可观察的 Emacs 界面、文本属性、交互或性能,只有在目标版本的 真实 GUI Emacs 中实际渲染并执行对应操作所得的视觉结果、动态过程和耗时数据, 才称为反馈。batch ERT、静态编译、CI、mock、结构检查和微基准只是进入 GUI 前的 预检或定位工具,不能替代 GUI 反馈,也不能据此宣称功能正确、视觉合格或性能收敛。 GUI 反馈失败时,以 GUI 为当前事实,回到最小假设重新定位;不得用逻辑测试绿色 反驳用户实测。
控制变更规模
- 避免一次编写大段跨层代码后才首次运行测试。
- 优先提交或保留小而完整的纵向切片;每个切片都应可独立解释、回退和验证。
- 新抽象必须服务于当前已验证的下一步,不为尚未证明的未来需求预建框架。
- 不因已有方案投入较多就继续扩建;数据否定假设时及时收缩或删除。
- 同一轮不要同时改变编译协议、Runtime 语义、Ebox 发布算法和 TP 权限边界, 除非最小闭环确实无法拆分,并且有逐层验证点。
Git 基线与完成提交
- 每个完整目标在新鲜验证通过后、开始下一个目标前,必须提交所有受影响仓库, 让已证明正确的状态成为可比较、可回退的基线;工作树中“已经完成但未提交” 不算真正收敛。
- 提交只包含当前已经完成并验证通过的目标。下一目标的失败测试、实验代码、 临时诊断和未验证实现必须与基线提交分离,不能为了清空工作树混进同一提交。
- 多仓库目标按依赖顺序分别提交,每个仓库使用与其实际改动相符的 message;
不用
update、changes、work一类无法说明结果的含糊描述。 - commit message 应以可观察结果或稳定的架构能力为中心,例如
perf: retain native frame updates across ETAF commits,而不是罗列实现步骤。 - 提交前至少运行该目标约定的定向测试、静态检查和最终门禁;验证失败时继续修复, 不得通过提交把失败状态包装成完成。
- 完成汇报列出各仓库 commit hash、验证证据和仍未提交的下一目标改动,确保后续 性能对比能够明确指出基准版本。
性能优化纪律
- 先用通用记录面板确认真实热区,再选择架构或算法改动。
- 一次优化只绑定一个主要瓶颈和一个预期收益,记录优化前后的相同口径数据。
- 不用示例名称或业务概念污染通用工具、编译器和底层包协议。
- 不以关闭校验、减少功能、弱化文本属性、破坏身份或回滚语义换取数字。
- 缓存和预编译提示不能自行授权快速路径;运行时仍负责验证和精确回退。
- 如果最小切片没有改善真实目标场景,不继续实现持久化、原生后端或更复杂缓存。
每轮汇报格式
进度更新应明确说明:最终目标、当前最小切片、已经验证的证据、未通过的指标、 下一次只准备验证的一个假设。不得把普通字节编译、局部优化或设计计划描述成 尚未实现的 App 预编译能力。
完成条件
只有当前工作树中的真实实现和新鲜验证同时证明最终要求,任务才算完成。计划、 部分测试、单个微基准、一次偶然的低耗时或“没有发现错误”都不是完成证据。