161 lines
4.2 KiB
Markdown
161 lines
4.2 KiB
Markdown
|
||
UI Engineering Principles v1(for Code Agents)
|
||
|
||
目标:在不指定框架/库细节的前提下,让 agent 自主做正确的 UI 工程决策。
|
||
输出要求:每次改动必须同时满足 可维护 / 可测试 / 可演进 / 可回滚。
|
||
|
||
1) 先决策再动手(Decision Log)
|
||
|
||
在修改前,agent 必须在 PR 描述或注释里输出一段 Decision Log(最多 10 行):
|
||
|
||
组件边界如何划分(为什么)
|
||
|
||
状态放哪(为什么)
|
||
|
||
哪些是公共骨架,哪些是 slot/children
|
||
兼容性策略(是否破坏现有 API)
|
||
风险点与回滚点
|
||
|
||
不求长,但求明确。没有 Decision Log 视为不合格提交。
|
||
|
||
2) 组件设计准则(边界与组合)
|
||
2.1 单一职责
|
||
|
||
一个组件只负责一个“稳定职责”
|
||
|
||
如果组件名需要用 “And/With/Plus” 连接多个职责 → 必须拆分
|
||
|
||
2.2 优先 Composition(组合)而不是 Config(配置)
|
||
|
||
优先通过 children / slots 组合 UI 结构
|
||
|
||
禁止为“结构差异”引入大量 boolean/enum props
|
||
|
||
只有在“结构稳定但样式/行为轻微差异”时才允许 variant
|
||
|
||
2.3 公共骨架 + 可插拔区域
|
||
|
||
抽取稳定的 Layout Skeleton 为 Root/Wrapper
|
||
|
||
差异点必须落在 children/slots(Header/Nav/Footer/Actions 等)
|
||
|
||
3) 状态管理准则(少、近、可注入)
|
||
3.1 状态最小化
|
||
|
||
不新增“可从现有数据推导”的 state(用 derived/computed)
|
||
|
||
不新增“只服务渲染”的 state(用 CSS/DOM 或 memo)
|
||
|
||
3.2 状态就近原则
|
||
|
||
UI 局部状态(open/collapsed/hover)放组件内部
|
||
|
||
跨多个子组件共享但局部范围内 → Context(组件树内)
|
||
|
||
全局业务状态 → store/server(仅必要时)
|
||
|
||
3.3 可测试性要求
|
||
|
||
关键 UI 状态必须可通过 props 注入或通过 context mock
|
||
|
||
逻辑优先放 hook,视图保持“纯 render”
|
||
|
||
4) 样式与可覆盖性(不锁死)
|
||
4.1 className 可组合
|
||
|
||
所有可复用组件必须接受 className 并合并
|
||
|
||
禁止写死样式导致无法覆盖(除非明确是私有组件)
|
||
|
||
4.2 语义优先
|
||
|
||
使用语义标签:nav/aside/header/main/button
|
||
|
||
可交互元素必须可键盘操作(button/link,不用 div 冒充)
|
||
|
||
4.3 选择器稳定
|
||
|
||
使用 data-* 或有限的 class 作为状态标记(如 collapsed/active)
|
||
|
||
避免复杂层级选择器导致脆弱
|
||
|
||
5) 兼容性与演进(不破坏用户)
|
||
5.1 默认向后兼容
|
||
|
||
任何改动尽量不破坏旧 API(props/DOM 结构/路由)
|
||
|
||
若必须破坏:提供迁移方式或兼容层,并在说明中写清
|
||
|
||
5.2 小步可回滚
|
||
|
||
每个提交尽量原子化(Atomic Commit)
|
||
|
||
重构必须可分阶段:先抽公共,再迁移,再清理旧代码
|
||
|
||
6) 性能准则(先可读,后优化)
|
||
6.1 不做“预优化”
|
||
|
||
禁止在没有证据时引入复杂 memo/useCallback/useMemo
|
||
|
||
若新增 memo:必须说明为什么必要(避免不必要渲染/昂贵计算)
|
||
|
||
6.2 可见性能问题再优化
|
||
|
||
性能优化必须是“局部、可验证、可回滚”的
|
||
|
||
7) 测试准则(最小但关键)
|
||
7.1 测试优先覆盖“行为”,不是“实现”
|
||
|
||
测试用户可感知行为:导航高亮、折叠、权限可见性等
|
||
|
||
不测试内部实现细节(class 名、组件层级等)
|
||
|
||
7.2 最小覆盖要求
|
||
|
||
重构 UI:至少补 1 个关键路径测试(unit 或 integration)
|
||
|
||
引入新状态/交互:必须有测试覆盖
|
||
|
||
8) 文档与可读性(未来的你也是用户)
|
||
8.1 代码即文档
|
||
|
||
组件 API 清晰可读(prop 名可解释)
|
||
|
||
复杂逻辑提取为函数/hook,并用短注释解释“为什么”
|
||
|
||
8.2 禁止“聪明代码”
|
||
|
||
避免迷宫式条件渲染
|
||
|
||
避免过度抽象(抽象必须带来复用或一致性收益)
|
||
|
||
9) 输出格式要求(agent 必须遵守)
|
||
|
||
每次提交/变更输出:
|
||
|
||
Decision Log(≤10 行)
|
||
|
||
变更摘要(改了什么)
|
||
|
||
风险点(可能破坏什么)
|
||
|
||
验证方式(如何验证:命令 + 预期)
|
||
|
||
回滚方式(如何快速退回)
|
||
|
||
10) 最终验收(Self-check)
|
||
|
||
Agent 在结束前必须自检并明确回答(是/否):
|
||
|
||
是否减少了重复,而不是引入更多分支?
|
||
|
||
是否让新增需求更容易通过组合实现?
|
||
|
||
是否状态更少、更近、更可测?
|
||
|
||
是否可覆盖样式并保持语义化?
|
||
|
||
是否可回滚(原子提交/分阶段)?
|
||
|
||
任意一项为“否”,必须解释原因或调整实现。
|