功能开关开发者Skill feature-toggle-developer

本技能指导开发人员系统移除iOS应用中的功能开关,实现自动化代码清理,提升代码质量,避免孤儿代码。关键词:功能开关移除、代码清理、iOS开发、自动化检测、软件开发。

移动开发 0 次安装 0 次浏览 更新于 3/15/2026

name: 功能开关开发者 description: 指导系统地从代码库中移除功能开关,并进行自动清理检测。用于移除功能标志、永久启用开关或移除开关后清理未使用的代码。

功能开关开发者

状态: 活跃 自动激活于: 功能标志/开关移除,重构开关后的清理 相关技能: 代码生成开发者, ios开发指南, 代码审查开发者

目的

指导系统地从代码库中移除功能开关(功能标志),并进行自动清理检测。确保在移除开关后没有孤儿代码、未使用的组件或遗留文件。

当此技能激活时

  • 用户提及: “移除开关”, “删除功能标志”, “永久启用功能开关”
  • 用户编辑: FeatureDescription+Flags.swift
  • 完成开关移除后: 帮助识别清理机会

功能开关移除工作流程

阶段1: 移除前分析

在移除任何开关之前,收集完整信息:

  1. 找到开关定义:

    # 位置: Modules/AnytypeCore/AnytypeCore/Utils/FeatureFlags/FeatureDescription+Flags.swift
    rg "static let toggleName" --type swift
    
  2. 检查defaultValue 以确定保留哪个分支:

    • defaultValue: true → 保留TRUE分支,移除FALSE分支
    • defaultValue: false → 保留FALSE分支,移除TRUE分支
  3. 搜索所有使用情况:

    rg "toggleName" --type swift
    
  4. 识别使用模式:

    • 直接: if FeatureFlags.toggleName { ... }
    • 反转: if !FeatureFlags.toggleName { ... }guard !FeatureFlags.toggleName
    • 复合: if FeatureFlags.toggleName && otherCondition { ... }
    • 赋值: let value = FeatureFlags.toggleName ? a : b
    • 状态: @State private var toggle = FeatureFlags.toggleName
  5. 列出受影响文件 并供用户审查

阶段2: 开关移除

系统移除过程:

  1. 移除条件检查并简化:

    示例1 - 简单条件 (defaultValue: true):

    // 之前
    if FeatureFlags.toggleName {
        // 功能代码
    }
    
    // 之后 (保留true分支)
    // 功能代码
    

    示例2 - 三元运算符 (defaultValue: true):

    // 之前
    VStack(spacing: FeatureFlags.toggleName ? 8 : 0)
    
    // 之后
    VStack(spacing: 8)
    

    示例3 - 反转逻辑 (defaultValue: true):

    // 之前
    guard !FeatureFlags.toggleName else { return }
    oldCode()
    
    // 之后 (标志为true,所以guard失败,移除整个块)
    // [整个块删除]
    

    示例4 - 状态变量 (defaultValue: true):

    // 之前
    @State private var toggle = FeatureFlags.toggleName
    if toggle { newUI() } else { oldUI() }
    
    // 之后
    newUI()
    // 注意: @State变量在清理阶段移除
    
  2. 移除功能标志定义:

    // 从以下删除: Modules/AnytypeCore/AnytypeCore/Utils/FeatureFlags/FeatureDescription+Flags.swift
    static let toggleName = FeatureDescription(...)
    
  3. 运行代码生成:

    make generate
    

    这会自动更新 FeatureFlags+Flags.swift

  4. 验证移除:

    rg "toggleName" --type swift  # 应该返回无结果
    

阶段3: 自动清理检测 ⭐

关键: 移除开关后,系统检查孤儿代码:

3.1 未使用的状态变量

搜索仅用于开关的 @State 变量:

# 查找模式如: @State private var someToggle = FeatureFlags.toggleName
rg "@State.*=.*FeatureFlags" --type swift

操作: 如果不再使用,移除整个 @State 变量声明。

3.2 未使用的视图组件

当开关控制显示哪个UI组件时,一个组件可能现在未使用:

检测模式:

  • 开关在ComponentA和ComponentB之间切换
  • 移除后,只使用一个
  • 在整个代码库中搜索未使用组件的名称

vaultBackToRoots示例:

// 之前
if !vaultBackToRootsToggle {
    SpaceCardLabel(...)  // 这个变得未使用
} else {
    NewSpaceCardLabel(...)
}

// 之后
NewSpaceCardLabel(...)

// 清理: SpaceCardLabel 现在未使用
rg "SpaceCardLabel" --type swift  # 检查是否在其他地方使用
# 如果仅在其自己的文件中找到 → 删除文件

操作:

  1. 搜索未使用组件名称: rg "UnusedComponentName" --type swift
  2. 如果仅在定义文件和注释中找到 → 删除文件
  3. 更新注释中的引用

3.3 未使用的ViewModels / 服务类

开关移除可能留下整个类未使用:

检测:

# 对于每个有条件使用的主要组件:
rg "UnusedViewModel" --type swift
rg "class UnusedViewModel" --type swift

操作: 删除未使用的ViewModels、它们的文件和DI注册。

3.4 未使用的导入

简化后,import AnytypeCore 可能仅用于 FeatureFlags

检测:

  • 文件导入 AnytypeCore
  • 仅使用 FeatureFlags.toggleName
  • 移除后,没有其他 AnytypeCore 使用

操作: 移除未使用的导入。

3.5 孤儿参数 / 属性

开关门控功能可能有不再需要的参数:

示例:

// 之前
func configure(showFeature: Bool) {
    if showFeature && FeatureFlags.toggle { ... }
}

// 开关移除后
func configure(showFeature: Bool) {
    if showFeature { ... }
}

// 潜在清理: showFeature 是否仍然需要?

操作: 审查函数签名并移除不必要的参数。

3.6 测试清理

开关移除影响测试:

检查:

  1. 具有开关相关属性的模拟对象
  2. 专门针对开关行为的测试用例
  3. 带有开关配置的测试设置代码

要检查的文件:

rg "toggleName" AnyTypeTests/ --type swift
rg "toggleName" "Anytype/Sources/PreviewMocks/" --type swift

操作: 更新或移除已删除代码路径的测试。

阶段4: 最终验证

提交前:

  1. Grep验证:

    rg "toggleName" --type swift  # 应该为空
    
  2. 编译检查:

    • 提醒用户在Xcode中验证编译
    • Claude由于缓存无法验证此点
  3. 生成更新的提交消息:

    IOS-XXXX 移除了 [toggleName] 开关
    
  4. 审查清理摘要:

    • 列出所有修改的文件
    • 列出所有删除的文件
    • 注意任何剩余的手动检查需要

清理检查清单模板

每次开关移除后使用此检查清单:

## [toggleName] 的清理验证

- [ ] 从FeatureDescription+Flags.swift中移除开关定义
- [ ] `make generate` 成功运行
- [ ] 所有条件使用移除
- [ ] 没有grep结果针对开关名称
- [ ] 未使用的@State变量移除
- [ ] 未使用的视图组件识别并删除
- [ ] 未使用的ViewModels/服务删除
- [ ] 未使用的导入移除(尤其是AnytypeCore)
- [ ] 孤儿函数参数移除
- [ ] 测试更新(检查AnyTypeTests/和PreviewMocks/)
- [ ] 引用旧组件的评论更新
- [ ] Xcode编译验证(由用户完成)

常见模式与陷阱

反转逻辑

注意 !FeatureFlags.toggle:

// 如果defaultValue: true
if !FeatureFlags.toggle {
    oldCode()  // 这个分支从不运行,删除它
}

复合条件

正确简化 条件:

// 之前 (defaultValue: true)
if FeatureFlags.toggle && userHasPermission {
    showFeature()
}

// 之后
if userHasPermission {
    showFeature()
}

Guard语句

小心 guards:

// 之前 (defaultValue: true)
guard !FeatureFlags.toggle else { return }
performOldBehavior()

// 之后 (开关为true,guard返回,整个块是死代码)
// 删除整个块

与其他技能的集成

  • 代码生成开发者: 引用make generate命令和故障排除
  • ios开发指南: Swift重构模式,导入管理
  • 代码审查开发者: 清理标准,确保PR中没有孤儿代码