使用 Claude 删除 5600 行代码

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

软件工程通常被视为一个“加法”过程:增加功能、增加抽象、增加“灵活性”。然而,最深刻的改进往往来自于“减法”。最近,我对一个数据流水线平台的提供商注册系统(Provider Registry System)进行了大规模的架构清理,结果令人震惊:修改了 194 个文件,新增 8,798 行,删除 14,411 行。净结果是删除了约 5,600 行代码。这不仅仅是一次简单的清理,而是一次由 n1n.ai 提供的强推理模型辅助进行的“架构手术”。

过度设计的陷阱

我曾花费数周时间构建了一个自认为“精妙”的架构。初衷是管理 Google Cloud、AWS 和 Postgres 等提供商及其相关服务(如 BigQuery、Firestore、DynamoDB)。为了追求所谓的“企业级标准”,我构建了一个极其复杂的系统,每增加一个新提供商,都需要修改 8 个不同的文件:

  1. seeds/sources_seed.go: 包含嵌套服务数组的源实体。
  2. seeds/templates_seed.go: 带有 JSON Schema 的连接模板实体。
  3. seeds/constants.go: 充斥着硬编码 UUID 的常量文件。
  4. frontend/components/connections/index.ts: UUID 到 React 组件的映射。
  5. frontend/lib/services/google-cloud-capabilities.ts: 每个服务的硬编码 OAuth 范围。
  6. 数据库 (Firestore): 为 Source 和 ConnectionTemplate 维护的冗余集合。

我曾安慰自己这叫“可扩展性”。但实际上,我是在为一种永远不会用到的灵活性维护复杂度。例如,我设计了处理“部分服务访问”的逻辑(例如:该连接有 BigQuery 权限但没有 Firestore),但实际上 OAuth 权限通常在应用层面是统一的,凭证要么有效,要么返回 401。这种复杂度是在解决一个根本不存在的问题。

转型:从动态数据库到静态配置

当我意识到这些数据本质上是静态的配置时,我决定彻底废除旧系统,改用一个仅 20 行的 TypeScript 配置文件。通过 n1n.ai 访问 Claude 3.5 Sonnet,我得以快速评估这一变更的“爆炸半径”。

// frontend/lib/providers.ts
export const PROVIDERS = {
  'google-cloud': {
    name: 'Google Cloud Platform',
    auth: 'oauth2',
    services: ['bigquery', 'firestore', 'gcs', 'pubsub'],
  },
  aws: {
    name: 'Amazon Web Services',
    auth: 'iam',
    services: ['dynamodb'],
  },
  postgres: {
    name: 'PostgreSQL',
    auth: 'database',
    services: ['postgres'],
  },
} as const

export type ProviderId = keyof typeof PROVIDERS

我们将连接模型从基于 UUID 的复杂查找简化为基于字符串键的直接引用:

// 重构前:冗余且复杂
Connection = {
  id: 'abc123',
  sourceId: 'c7b3d8e9-5f2a-4b1c-9d6e-8a3b5c7d9e1f',
  templateId: 'template-google-cloud-oauth2',
  services: ['bigquery', 'firestore'],
  connectionConfig: { ... }
}

// 重构后:简洁明了
Connection = {
  id: 'abc123',
  providerId: 'google-cloud', // 直接使用 PROVIDERS 中的键
  config: { projectId: 'my-project' },
  credentials: { ... }
}

AI 辅助的架构手术

这并不是简单的“让 AI 帮我写代码”,而是将 LLM 作为精密的手术刀。我向 Claude 提供了整个代码库的上下文,并要求它识别旧系统的每一个引用。由于使用了 n1n.ai 稳定且高吞吐量的 API 接口,我能够一次性输入大量的 Go 后端文件和 TypeScript 前端文件,确保模型理解重构的全貌。

Claude 系统地识别了:

  • 所有旧类型的导入(Imports)。
  • 所有硬编码 UUID 常量的使用位置。
  • 依赖 sourceIdtemplateId 的前端组件。
  • 迁移后端以避免破坏前端的特定操作顺序。

后端重构 (Go)

在 Go 后端,我们几乎触及了整个技术栈。我们将 TemplateIdSourceId 替换为统一的 ProviderId 字符串。涉及的变更包括:

  • models/connection.go: 删除了冗余字段。
  • services/connection_service.go: 更新了校验逻辑,改为检查静态配置而非查询数据库中的“模板”。
  • daos/connection_dao.go: 简化了 Firestore 的查询逻辑。
  • routes/router.go: 删除了整个 /v1/sources/* 路由组,因为它们已不再需要。

前端重构 (TypeScript/React)

前端的变动更为显著。我们删除了多个自定义 Hook(如 use-sourceuse-connection-template)以及多个服务文件。超过 40 个 React 组件被更新以适配新的 ProviderId 类型。

为什么只产生了一个 Bug?

修改 194 个文件却只在端到端测试中发现一个 Bug,这并非运气,而是基于以下四个核心因素:

  1. 全面的测试覆盖:我没有删除测试,而是同步更新了它们。如果某个变更破坏了逻辑,测试套件会立即报错。
  2. 同步重构测试:每一次代码修改都会在同一个 Commit 中包含对应的测试更新。测试不是事后补救,而是重构的一部分。
  3. AI 的系统性优势:人类会疲劳。在修改到第 100 个文件时,开发者可能会漏掉一个属性重命名。而通过 n1n.ai 调用的 Claude 3.5 Sonnet 在处理 194 个文件时保持了近乎完美的逻辑一致性。
  4. 清晰的架构愿景:在动代码之前,我编写了详细的技术设计文档。AI 并不是在盲目猜测,而是在执行一份清晰的蓝图。

总结:迈向可维护的未来

现在,添加一个新的提供商只需在 PROVIDERS 配置中增加一行,并创建相应的 UI 组件。不再有数据库种子需要管理,不再有 UUID 需要追踪,也不再有“灵活性债”。

如果你正面对着一个臃肿的系统,请问问自己:这种复杂度是在解决真实问题,还是在应对假设的需求?如果是后者,请勇敢地删除它。配合完善的测试和像 Claude 这样强大的 AI 伙伴,你可以对架构进行深度手术,并让系统焕发新生。

n1n.ai 获取免费 API 密钥。