launchdarkly-flag-cleanup

launchdarkly-flag-cleanup

安全地从代码中移除功能开关,同时保持生产环境行为不变。当用户想要从代码中移除开关、删除开关引用,或在功能发布完成后创建将获胜变体硬编码的PR时使用。

20Star
7Fork
更新于 2026/7/25
SKILL.md
readonly只读
name
launchdarkly-flag-cleanup
description

安全地从代码中移除功能开关,同时保持生产环境行为不变。当用户想要从代码中移除开关、删除开关引用,或在功能发布完成后创建将获胜变体硬编码的PR时使用。

LaunchDarkly 开关清理

你正在使用一项技能,它将指导你安全地从代码库中移除功能开关,同时保持生产环境行为不变。你的任务是探索代码库以了解开关的使用方式,查询 LaunchDarkly 以确定正确的正向值,干净地移除开关代码,并验证结果。

如果你尚未确定要清理哪个开关,请先使用开关发现技能来审计全局并找到候选开关。

前提条件

此技能需要在你的环境中配置远程托管的 LaunchDarkly MCP 服务器。

必需的 MCP 工具:

  • check-removal-readiness:详细的安全检查(并行协调开关配置、跨环境状态、依赖关系、代码引用和过期目标)
  • get-flag:获取特定环境的开关配置

可选的 MCP 工具:

  • archive-flag:在代码移除后归档 LaunchDarkly 中的开关
  • delete-flag:永久删除开关(不可逆,建议优先归档)

核心原则

  1. 安全第一:始终保留当前生产环境行为。
  2. 以 LaunchDarkly 为真相源:切勿猜测正向值。查询实际配置。
  3. 遵循约定:尊重现有代码风格和结构。
  4. 最小化变更:仅移除与开关相关的代码。不进行无关重构。

工作流程

步骤 1:探索代码库

在接触 LaunchDarkly 或移除代码之前,了解该开关在代码库中的使用方式。

  1. 查找所有对开关键的引用。 在代码库中搜索开关键字符串(例如 new-checkout-flow)。检查:

    • 直接 SDK 评估调用(variation()boolVariation()useFlags() 等)
    • 引用该键的常量/枚举
    • 抽象 SDK 的包装器/服务模式
    • 配置文件、测试和文档
    • 参见 SDK 模式 获取按语言分类的完整模式列表
  2. 理解分支逻辑。 对于每个引用,确定:

    • 当开关为 true(或变体 A)时运行哪些代码?
    • 当开关为 false(或变体 B)时运行哪些代码?
    • 是否存在副作用、提前返回或嵌套条件?
  3. 注意影响范围。 该开关涉及多少文件、组件或模块?一个在单个 if 块中使用的开关比贯穿多个层的开关更简单。

步骤 2:运行移除就绪检查

使用 check-removal-readiness 获取详细的安全评估。此单一工具调用并行协调多项检查:

  • 开关配置和定位状态
  • 跨环境状态
  • 依赖开关(前置条件)
  • 过期目标
  • 代码引用统计

该工具返回就绪判定:

safe:无阻塞或警告。可以继续移除。

caution:无硬阻塞但存在警告(例如,其他仓库中的代码引用、已计划的过期目标、标记为永久的开关)。显示警告并让用户决定。

blocked:硬阻塞阻止安全移除(例如,依赖开关、正在接收请求、定位已开启且有活跃规则)。显示阻塞项:用户必须先解决它们。

步骤 3:确定正向值

使用 get-flag 获取每个关键环境中的开关配置。正向值是替换代码中开关的变体。

场景 正向值
所有关键环境 ON,相同 fallthrough,无规则/目标 使用 fallthrough.variation
所有关键环境 OFF,相同 offVariation 使用 offVariation
关键环境 ON/OFF 状态不同 不安全:停止并告知用户
关键环境提供不同的变体 不安全:停止并告知用户

步骤 4:呈现清理计划

在修改任何代码之前,向用户呈现摘要并等待确认:

  1. 正向值——将硬编码哪个变体及其原因(基于开关的当前状态)。
  2. 找到的所有代码引用——步骤 1 中的文件路径和行号。
  3. 计划变更——对于每个引用,描述将移除什么以及保留什么。
  4. 就绪判定——check-removal-readiness 的结果(safe、caution 或 blocked)以及任何警告。
  5. LaunchDarkly 操作——确认在代码更改完成后将归档开关。

在用户明确确认之前,不要进行代码更改。

步骤 5:从代码中移除开关

现在使用步骤 1 中学到的知识执行移除。

  1. 将开关评估替换为正向值。

    • 保留与正向值匹配的代码分支
    • 完全移除死分支
    • 如果开关值被赋值给变量,将变量替换为字面量或内联它
  2. 清理死代码。

    • 移除仅用于该开关的导入、常量和类型定义
    • 移除仅用于死分支的函数、组件或文件
    • 检查孤立的导出、钩子、辅助函数、样式和测试文件
    • 如果仓库使用了未使用导出工具(Knip、ts-prune、lint 规则),运行它并移除任何与开关相关的孤立项
  3. 不要过度清理。

    • 仅移除直接与开关相关的代码
    • 不要重构、优化或“改进”周围代码
    • 不要更改未触及代码的格式或样式

示例转换(布尔开关,正向值 = true):

// 之前
const showNewCheckout = await ldClient.variation('new-checkout-flow', user, false);
if (showNewCheckout) {
  return renderNewCheckout();
} else {
  return renderOldCheckout();
}

// 之后
return renderNewCheckout();

步骤 6:创建拉取请求

使用 references/pr-template.md 中的模板编写结构化的 PR 描述。PR 应清晰传达:

  • 移除了哪个开关及其原因
  • 正向值是什么以及为什么正确
  • 就绪评估结果(来自 check-removal-readiness
  • 移除了哪些代码以及保留了哪些行为
  • 其他仓库是否仍引用此开关

步骤 7:验证

在认为工作完成之前:

  1. 代码编译并通过 lint。 运行项目的构建和 lint 步骤。
  2. 测试通过。 如果开关在测试中使用,应更新测试以反映硬编码的行为。
  3. 无剩余引用。 再次搜索代码库中的开关键,确保没有遗漏。
  4. PR 完整。 描述涵盖就绪评估、正向值理由以及任何需要的跨仓库协调。

边缘情况

情况 操作
在 LaunchDarkly 中未找到开关 告知用户,检查键是否有拼写错误
开关已归档 询问是否仍需要代码清理(开关已从 LD 中消失,但代码可能仍引用它)
代码库中存在多种 SDK 模式 搜索所有模式:variation()boolVariation()variationDetail()allFlags()useFlags() 以及任何包装器
动态开关键(flag-${id} 警告自动移除可能不完整:需要人工审查
代码与 LD 中的默认值不同 在 PR 描述中标记为不一致
移除后仍有孤立的导出/文件 运行未使用导出检查并移除死文件

禁止事项

  • 不要更改与开关清理无关的代码。
  • 不要重构或优化超出开关移除的范围。
  • 不要移除仍在积极发布中的开关。
  • 不要猜测正向值:始终查询 LaunchDarkly。

清理之后

一旦 PR 合并并部署:

  1. 在 LaunchDarkly 中归档开关,使用 archive-flag。归档是可逆的;删除则不可逆。始终先归档。
  2. 通知其他团队,如果 check-removal-readiness 报告了其他仓库中的代码引用。
  3. 如果开关有未决的定位更改,可以忽略:开关正在被移除。

参考

  • PR 模板:用于开关移除的结构化 PR 描述
  • SDK 模式:按语言/框架分类的开关评估模式
  • 开关发现:在使用此技能前查找清理候选开关
  • 开关定位:如果需要更改定位而不是移除