使用 Claude 删除 5600 行代码
- 作者

- 姓名
- Nino
- 职业
- Senior Tech Editor
软件工程通常被视为一个“加法”过程:增加功能、增加抽象、增加“灵活性”。然而,最深刻的改进往往来自于“减法”。最近,我对一个数据流水线平台的提供商注册系统(Provider Registry System)进行了大规模的架构清理,结果令人震惊:修改了 194 个文件,新增 8,798 行,删除 14,411 行。净结果是删除了约 5,600 行代码。这不仅仅是一次简单的清理,而是一次由 n1n.ai 提供的强推理模型辅助进行的“架构手术”。
过度设计的陷阱
我曾花费数周时间构建了一个自认为“精妙”的架构。初衷是管理 Google Cloud、AWS 和 Postgres 等提供商及其相关服务(如 BigQuery、Firestore、DynamoDB)。为了追求所谓的“企业级标准”,我构建了一个极其复杂的系统,每增加一个新提供商,都需要修改 8 个不同的文件:
- seeds/sources_seed.go: 包含嵌套服务数组的源实体。
- seeds/templates_seed.go: 带有 JSON Schema 的连接模板实体。
- seeds/constants.go: 充斥着硬编码 UUID 的常量文件。
- frontend/components/connections/index.ts: UUID 到 React 组件的映射。
- frontend/lib/services/google-cloud-capabilities.ts: 每个服务的硬编码 OAuth 范围。
- 数据库 (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 常量的使用位置。
- 依赖
sourceId或templateId的前端组件。 - 迁移后端以避免破坏前端的特定操作顺序。
后端重构 (Go)
在 Go 后端,我们几乎触及了整个技术栈。我们将 TemplateId 和 SourceId 替换为统一的 ProviderId 字符串。涉及的变更包括:
- models/connection.go: 删除了冗余字段。
- services/connection_service.go: 更新了校验逻辑,改为检查静态配置而非查询数据库中的“模板”。
- daos/connection_dao.go: 简化了 Firestore 的查询逻辑。
- routes/router.go: 删除了整个
/v1/sources/*路由组,因为它们已不再需要。
前端重构 (TypeScript/React)
前端的变动更为显著。我们删除了多个自定义 Hook(如 use-source、use-connection-template)以及多个服务文件。超过 40 个 React 组件被更新以适配新的 ProviderId 类型。
为什么只产生了一个 Bug?
修改 194 个文件却只在端到端测试中发现一个 Bug,这并非运气,而是基于以下四个核心因素:
- 全面的测试覆盖:我没有删除测试,而是同步更新了它们。如果某个变更破坏了逻辑,测试套件会立即报错。
- 同步重构测试:每一次代码修改都会在同一个 Commit 中包含对应的测试更新。测试不是事后补救,而是重构的一部分。
- AI 的系统性优势:人类会疲劳。在修改到第 100 个文件时,开发者可能会漏掉一个属性重命名。而通过 n1n.ai 调用的 Claude 3.5 Sonnet 在处理 194 个文件时保持了近乎完美的逻辑一致性。
- 清晰的架构愿景:在动代码之前,我编写了详细的技术设计文档。AI 并不是在盲目猜测,而是在执行一份清晰的蓝图。
总结:迈向可维护的未来
现在,添加一个新的提供商只需在 PROVIDERS 配置中增加一行,并创建相应的 UI 组件。不再有数据库种子需要管理,不再有 UUID 需要追踪,也不再有“灵活性债”。
如果你正面对着一个臃肿的系统,请问问自己:这种复杂度是在解决真实问题,还是在应对假设的需求?如果是后者,请勇敢地删除它。配合完善的测试和像 Claude 这样强大的 AI 伙伴,你可以对架构进行深度手术,并让系统焕发新生。
在 n1n.ai 获取免费 API 密钥。