功能开关需求说明:写清默认值、失败行为与回退
本文目录
功能开关的需求说明,应写清求值成功、尚未就绪和求值失败时,用户分别会看到什么。它还应说明谁有权扩大开放范围、怎样退回旧流程,以及何时移除开关。仅给一个布尔开关起名字,并没有完成这些决定。
以虚构的 export_preview 开关为例:它只在新的导出预览界面与现有导出界面之间作选择,不授予数据访问权、不改变导出权限,也不修改文件格式。范围明确,回退就容易理解:现有导出流程仍然可用。
定义四种应用状态
本例采用以下应用内部策略:
| 应用状态 | 条件 | 用户看到的流程 |
|---|---|---|
ON |
已就绪、无错误,值为布尔 true |
新的导出预览界面 |
OFF |
已就绪、无错误,值为布尔 false |
现有导出界面 |
NOT_READY |
无错误,但适配器尚未就绪 | 现有导出界面 |
ERROR |
求值出错或值的类型无效 | 现有导出界面 |
这些是本例选定的应用状态,并不表示每个服务提供方都会暴露这四个枚举值。适配器需要将所选提供方的就绪状态、求值结果和错误详情,映射到这份约定。
OpenFeature 的开关求值规范定义了带有调用方默认值的类型化求值,以及更丰富的求值详情。其类型定义区分了错误与其他结果元数据。这可以作为接口参考,但具体提供方的启动和缓存行为仍需分别检查。仅返回一个 false,未必能让应用分辨:开关是有意关闭,还是在求值出错后使用了回退值。
用代码明确回退规则
下面的纯 Python 函数用于说明应用怎样选择分支,并非 SDK 接入:
def choose_export(ready, value, error=None):
if error is not None:
return {"path": "legacy", "state": "ERROR"}
if not ready:
return {"path": "legacy", "state": "NOT_READY"}
if type(value) is not bool:
return {"path": "legacy", "state": "ERROR"}
return {
"path": "preview" if value else "legacy",
"state": "ON" if value else "OFF",
}
判断顺序很重要。已经报告的错误,应优先于就绪状态和缓存值处理。内容为 "false" 的字符串属于无效类型;若把它当成真值,就会选错界面。
英文原稿记录了以下五个虚构用例使用 Python 3.12.14 在本地执行的结果:
| 是否就绪 | 值 | 错误 | 实际状态与流程 |
|---|---|---|---|
| 是 | true |
无 | ON,preview |
| 是 | false |
无 | OFF,legacy |
| 否 | null |
无 | NOT_READY,legacy |
| 是 | true |
PROVIDER_ERROR |
ERROR,legacy |
| 是 | 字符串 "false" |
无 | ERROR,legacy |
这些结果只验证了辅助函数中列出的分支,没有验证服务提供方的启动、网络恢复、分批开放的目标选择或真实导出行为。接入提供方之前,应规定怎样识别过期值,以及是否允许使用它们。本例要求适配器不能把尚未获准使用的过期结果标记为已就绪;缓存策略定义并检查完成之前,应用使用 legacy 流程。
区分界面回退与撤销副作用
关闭开关,会在下一次求值时选择旧界面,但不会自动关闭已经打开的预览、收回已经生成的文件、撤销数据迁移,或部署旧版代码。
对这个虚构功能,将求值时机设为打开导出流程时;流程打开后,保持已经选定的路径。如果严重缺陷要求中断已经打开的流程,就应另行规定处理行为和提示信息,而不是把它藏在“立即回滚”这种含糊承诺里。
两条界面流程都必须继续使用现有的同一套权限检查。功能开关可以决定提供哪种界面,但它不是授权边界;隐藏按钮也无法保护按钮背后的操作。
改变开放范围前,先写清开放决定
使用一张人工决策卡,按你的项目填写姓名和证据字段。下面的空白是有意保留的,并不意味着已获批准。
英文锁定原文:
Flag: export_preview
Change controlled: new preview screen only
Default and fallback: legacy screen
Evaluation point: opening a new export flow; stable within that flow
Decision owner: [named person or role]
Implementer: [named person or role]
Initial audience: [explicitly approved cohort]
Current deployment and provider configuration: [identifiers]
Before initial exposure:
- Confirm all four application states in the actual adapter.
- Confirm export permission checks apply on both paths.
- Confirm representative files match the agreed export contract.
- Confirm the legacy path is present and usable.
Before expanding the audience:
- Record which cohort and checks were observed, with actual results.
- Record unresolved errors and the decision owner's decision.
- Define the next cohort explicitly; do not infer approval from silence.
Return to legacy if:
- A preview chooses or exports the wrong records, or
- Required permission behavior differs between the two paths, or
- A blocking preview failure has no accepted workaround.
Rollback action: authorized owner disables the preview for new flows.
Verify: a newly opened flow selects legacy using the real adapter.
Open-flow handling: [separate decision if interruption is required]
Other recovery needed: [files, data or deployment actions, if applicable]
完整中文对照:
开关:export_preview
控制的变更:仅新的预览界面
默认与回退:legacy 界面
求值时机:打开新的导出流程时;同一流程内保持选择不变
决策负责人:[具体人员或角色]
实施者:[具体人员或角色]
初始用户范围:[明确获准的用户群]
当前部署与服务提供方配置:[标识符]
首次开放前:
- 在真实适配器中确认四种应用状态。
- 确认两条流程都执行导出权限检查。
- 确认代表性文件符合约定的导出规则。
- 确认 legacy 流程存在且可用。
扩大用户范围前:
- 记录实际观察了哪个用户群、做了哪些检查,以及真实结果。
- 记录尚未解决的错误和决策负责人的决定。
- 明确下一批用户群;不要因无人反对就视为获准。
出现以下任一情况时,退回 legacy:
- 预览选错或导出了错误记录;或
- 两条流程所需的权限行为不一致;或
- 阻断使用的预览故障没有已获接受的替代处理办法。
回退动作:有权作出决定的负责人,为新打开的流程关闭预览。
验证:通过真实适配器,确认新打开的流程选择 legacy。
已打开流程的处理:[如果需要中断,另行作出决定]
其他恢复工作:[如适用,填写文件、数据或部署方面的操作]
项目可以增加经过明确定义的运行阈值,但必须有已知的测量来源和负责人。不要为了填满模板而编造错误率,或开启新的遥测采集。没有实际观察的事项,就记录为尚未观察。
为开关设定退出条件
“以后再删”往往会让两个分支一直留在代码里。应明确移除前必须满足的条件:新流程已经面向预定用户群获接受;仍需支持的客户端或部署不再依赖旧分支;负责人接受失去通过开关回退的能力;剩余引用可以一并移除。
移除开关本身也是一次需要检查的代码变更。如果客户端仍在求值,只删除远端开关,可能会让客户端改用各自配置的默认值。删除配置前,先说明预期行为。
给实施者的需求说明
英文锁定原文:
Add the fictional export_preview branch using the four-state table.
Keep the change limited to selecting preview vs legacy export UI.
Implement the pure selection policy and a separately identified adapter.
Use legacy when not ready, on evaluation error or for an invalid type.
Check errors first. Never coerce the string "false" to a Boolean.
Resolve readiness/error/cache mapping from the chosen provider's docs.
Do not accept stale data as ready without an explicit checked policy.
Evaluate on opening the flow; keep that choice stable inside the flow.
Preserve existing permission checks, export data rules and the legacy path.
Do not change live flag settings, target cohorts, deployments or telemetry.
Deliver the implementation, five branch cases, provider-specific unknowns,
and a filled decision card for review. Report helper tests, adapter tests
and real UI checks separately. Leave rollout and flag removal as explicit
owner decisions rather than taking those actions during implementation.
完整中文对照:
按照四状态表,加入虚构的 export_preview 分支。
变更仅限于在 preview 与 legacy 导出界面之间作选择。
实现纯分支选择策略,并把适配器作为独立部分明确列出。
尚未就绪、求值出错或值类型无效时,使用 legacy。
先检查错误。绝不将字符串 "false" 强制转换成布尔值。
根据所选提供方的文档,确定就绪、错误及缓存的映射。
没有明确且检查过的策略,不得把过期数据当成已就绪结果。
打开流程时求值;同一流程内保持选择不变。
保留现有权限检查、导出数据规则及 legacy 流程。
不要修改线上开关配置、目标用户群、部署或遥测采集。
交付实现、五个分支用例、提供方相关的未明事项,
以及填好的决策卡供审阅。辅助函数测试、适配器测试
和真实界面检查分别报告。分批开放及移除开关,
由负责人明确决定,不在实施过程中直接执行。
有用的交付是一项受控选择,并且失败时的行为清楚可理解。开关只是用于作出这个选择的机制。