尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI时代软件基本功:从代码整洁到人机协作的工程实践

AI时代软件基本功:从代码整洁到人机协作的工程实践 在 AI 工具日益普及的今天一个尖锐的问题摆在了每一位开发者面前当 AI 能够生成代码、重构函数甚至编写测试时我们过去所强调的命名规范、函数拆分、设计模式等“软件基本功”是否已经过时Matt Pocock 与《代码整洁之道》作者 Robert C. Martin 的这场对话恰好触及了这个时代最核心的焦虑。对于一线开发者而言这绝非一个理论问题而是直接关系到我们每天如何工作、如何评估代码质量以及如何规划个人技能树。本文将从一个工程实践者的视角深入探讨在 AI 辅助编程成为标配的背景下为什么软件基本功不仅没有贬值反而变得更加关键并会通过具体的代码对比、工具使用场景和团队协作案例来阐述如何将基本功与 AI 工具结合实现个人与团队效率的质变。1. 重新定义“AI 时代”的软件基本功在讨论重要性之前我们必须先厘清在 AI 深度介入开发流程的今天“软件基本功”的内涵发生了哪些演变。它不再仅仅是关于如何手写一个快速排序算法而是关于如何清晰地表达意图、如何设计可被理解和维护的结构以及如何建立一套人与机器都能高效协作的代码质量标准。1.1 从“实现能力”到“表达与评审能力”的转变传统的软件基本功其核心是“实现能力”给定一个明确的需求开发者能够运用编程语言、数据结构和算法知识将其转化为可运行的代码。AI 的出现尤其是像 GitHub Copilot、Cursor、Amazon CodeWhisperer 这样的工具正在极大地接管这部分“实现”工作。一个清晰的注释或函数名就能让 AI 生成出可用的代码块。因此基本功的重心发生了转移。现在的核心能力变成了“表达与评审能力”精准表达意图能否用清晰的命名、简洁的注释和合理的函数签名向 AI 准确描述你希望它生成什么。这要求你对问题域有深刻理解并能进行良好的抽象。高效评审与修正AI 生成的代码并非总是最优或正确的。你需要快速阅读、理解 AI 的“创作”判断其逻辑是否正确、边界是否覆盖、是否符合项目规范并给出精确的修改指令。这依赖于扎实的代码阅读能力、调试能力和架构嗅觉。例如一个基本功薄弱的开发者可能会给 AI 一个模糊的提示“写个函数处理用户数据”。AI 可能生成一个庞大、职责不清的函数。而基本功扎实的开发者会这样描述“请创建一个名为validateAndSanitizeUserInput的函数接收一个UserDTO对象依次进行非空检查、邮箱格式验证、密码强度校验并剔除首尾空格最后返回一个ValidationResult对象。” 后者能直接引导 AI 产出结构更清晰、职责更单一的代码。1.2 代码整洁从“个人风格”到“团队与AI的契约”Robert C. Martin 在《代码整洁之道》中强调的命名、函数、注释等规范在过去常被视为一种优秀的“个人风格”或“团队共识”。但在 AI 时代这些规范升级为“人与AI之间、以及AI与AI之间协作的契约”。对AI的契约一致的命名规范如camelCase变量、PascalCase类名和代码结构能让 AI 在补全、重构时保持上下文一致减少“风格漂移”。AI 在学习了大量遵循统一规范的代码后其生成结果也会更可预测。对后续AI的契约当你用 AI 修改一段由另一位开发者或之前的 AI编写的代码时整洁的代码意味着更低的认知负荷。你可以更准确地告诉 AI“修改calculateInvoiceTotal函数在其中添加税费计算逻辑”而不需要先花大量时间理清一个名为doIt的巨型函数到底在做什么。// 模糊的“契约”对AI和人都低效 public Object process(Object a, Object b) { // ... 50行混杂着各种逻辑的代码 } // 清晰的“契约”便于AI理解和操作 public Invoice calculateInvoice(Order order, TaxRate taxRate) { BigDecimal subtotal calculateSubtotal(order.getItems()); BigDecimal taxAmount calculateTax(subtotal, taxRate); BigDecimal total subtotal.add(taxAmount); return new Invoice(order, subtotal, taxAmount, total); }1.3 设计原则与架构驾驭AI生成代码的“缰绳”AI 擅长生成局部的、战术性的代码片段但在模块划分、系统边界、依赖关系等战略性的设计层面它目前仍需要人类的引导。SOLID 原则、设计模式、分层架构等知识成为了开发者驾驭 AI 这匹“快马”的缰绳。没有这些基本功AI 生成的代码很容易堆积成一个“大泥球”Big Ball of Mud各个部分高度耦合难以单独测试、理解和修改。开发者需要运用架构知识告诉 AI“请将认证逻辑抽离到一个独立的AuthService类中遵循依赖倒置原则通过接口TokenProvider注入。” 这样才能确保 AI 在正确的轨道上生成代码最终集成为一个可维护的系统而非一堆无法组合的碎片。2. 环境准备搭建一个AI辅助的整洁编码工作流理论需要实践来验证。我们首先搭建一个将 AI 工具与代码整洁实践相结合的个人开发环境。这里以 VS Code 配合主流 AI 插件为例。2.1 核心工具选择与配置主编辑器Visual Studio Code。它是目前生态最丰富、AI 插件支持最好的编辑器之一。AI 编码助手GitHub Copilot最普及的代码补全工具擅长根据上下文和注释生成代码片段。Cursor基于 GPT 的编辑器深度整合了 AI不仅限于补全还能进行对话、重构、解释代码非常适合进行“表达与评审”式开发。代码质量工具Linter FormatterESLint (JavaScript/TypeScript) / Pylint (Python) / Checkstyle (Java)静态代码分析工具用于检查代码中的潜在错误和不规范之处。Prettier / Black / Google Java Format代码格式化工具自动将代码格式化为统一的风格。2.2 项目初始化与关键配置创建一个新的 TypeScript 项目来演示整个工作流。# 初始化项目 mkdir ai-clean-code-demo cd ai-clean-code-demo npm init -y # 安装 TypeScript 和类型定义 npm install typescript types/node --save-dev # 初始化 tsconfig.json npx tsc --init # 安装代码质量工具 npm install eslint prettier eslint-config-prettier eslint-plugin-prettier typescript-eslint/eslint-plugin typescript-eslint/parser --save-dev创建.eslintrc.js配置文件集成 Prettier 并设置一些与代码整洁相关的规则module.exports { parser: typescript-eslint/parser, plugins: [typescript-eslint, prettier], extends: [ eslint:recommended, plugin:typescript-eslint/recommended, plugin:prettier/recommended, // 集成prettier避免规则冲突 ], rules: { // 代码整洁相关规则 typescript-eslint/naming-convention: [ error, { selector: variableLike, format: [camelCase] }, { selector: typeLike, format: [PascalCase] }, { selector: enumMember, format: [UPPER_CASE] }, ], complexity: [warn, 10], // 圈复杂度警告阈值 max-depth: [warn, 4], // 最大嵌套深度 max-lines-per-function: [warn, 50], // 函数最大行数 // 要求使用 和 ! eqeqeq: error, // 禁止未使用的变量 typescript-eslint/no-unused-vars: error, }, env: { node: true, es6: true, }, };创建.prettierrc配置文件{ semi: true, trailingComma: es5, singleQuote: true, printWidth: 100, tabWidth: 2 }在package.json中添加脚本{ scripts: { lint: eslint src/**/*.ts, lint:fix: eslint src/**/*.ts --fix, format: prettier --write src/**/*.ts, check: npm run lint npm run format } }这个环境确保了无论你手写代码还是 AI 生成代码最终都会经过一套统一的质量关卡强制保持代码库的整洁度。3. 实战演练与AI协作编写一个整洁的模块假设我们需要开发一个简单的用户注册模块。我们将演示如何运用基本功引导 AI 生成符合整洁规范的代码。3.1 第一步用清晰的意图描述定义需求不要直接打开文件就开始写或让 AI 补全。先在项目根目录创建一个docs/或requirements/目录用纯文本或 Markdown 写下清晰的需求描述。这个习惯本身就是一项关键的基本功——需求澄清。requirements/user-registration.md# 用户注册模块需求 ## 功能描述 1. 接收用户输入用户名、邮箱、密码。 2. 对输入进行验证 - 用户名非空长度3-20字符仅包含字母数字和下划线。 - 邮箱符合基本邮箱格式。 - 密码长度至少8位包含大小写字母和数字。 3. 密码需进行加盐哈希处理后再存储。 4. 检查邮箱是否已被注册。 5. 将验证通过的用户信息持久化。 6. 返回注册结果成功/失败及原因。 ## 设计约束 - 使用 TypeScript。 - 遵循分层架构Controller处理HTTP请求 - Service业务逻辑 - Repository数据访问。 - 使用依赖注入DI提高可测试性。 - 错误处理使用自定义异常或 Result 模式避免直接抛出基础 Error。 - 所有函数应保持单一职责圈复杂度低。3.2 第二步引导AI创建项目结构与核心类型在 VS Code 中打开src/目录。首先我们可以直接与 Cursor 的 AI 对话或者在有 Copilot 的编辑器里通过创建文件并添加清晰注释来引导。创建src/types/index.ts并输入以下注释// 定义用户注册相关的数据传递对象DTO和领域模型EntityCopilot 或 Cursor 很可能会补全出类似下面的代码。如果第一次生成不理想可以修改注释或直接与 AI 聊天“请定义UserRegistrationDto和UserEntity接口并添加 JSDoc 注释。”/** * 用户注册请求数据 */ export interface UserRegistrationDto { username: string; email: string; password: string; } /** * 用户领域实体 */ export interface UserEntity { id: string; // UUID username: string; email: string; passwordHash: string; // 存储哈希后的密码 salt: string; createdAt: Date; } /** * 统一操作结果类型用于清晰的错误处理 */ export type ResultT, E string { success: true; data: T } | { success: false; error: E }; /** * 注册结果 */ export type RegistrationResult ResultUserEntity, RegistrationError; /** * 注册可能出现的错误类型 */ export enum RegistrationError { INVALID_INPUT INVALID_INPUT, EMAIL_EXISTS EMAIL_EXISTS, USERNAME_EXISTS USERNAME_EXISTS, DATABASE_ERROR DATABASE_ERROR, }关键点解释这里我们使用了Result模式而非直接抛出异常。这是一种更函数式、更显式的错误处理方式使函数的成功和失败路径一目了然AI 在生成后续调用代码时也能更好地处理错误。这是“表达清晰”基本功的体现。3.3 第三步编写验证逻辑——展示单一职责与可测试性创建src/services/validation.service.ts。输入以下函数签名和注释import { UserRegistrationDto } from ../types; /** * 验证用户注册输入 * 遵循单一职责原则只做验证不涉及其他逻辑如查重、持久化 * param dto 用户注册数据 * returns 如果验证通过返回null否则返回错误信息字符串 */ export function validateUserRegistrationInput(dto: UserRegistrationDto): string | null { // TODO: 实现验证逻辑 }此时利用 AI 补全输入//或使用快捷键或直接让 Cursor AI 生成函数体。一个训练有素的 AI 在清晰上下文中可能会生成如下代码export function validateUserRegistrationInput(dto: UserRegistrationDto): string | null { const { username, email, password } dto; // 验证用户名 if (!username || username.trim().length 0) { return 用户名不能为空; } if (username.length 3 || username.length 20) { return 用户名长度需在3-20个字符之间; } if (!/^[a-zA-Z0-9_]$/.test(username)) { return 用户名只能包含字母、数字和下划线; } // 验证邮箱 const emailRegex /^[^\s][^\s]\.[^\s]$/; if (!email || !emailRegex.test(email)) { return 邮箱格式不正确; } // 验证密码 if (!password || password.length 8) { return 密码长度至少为8位; } if (!/(?.*[a-z])(?.*[A-Z])(?.*\d)/.test(password)) { return 密码必须包含大小写字母和数字; } return null; // 验证通过 }评审与修正生成后我们需要运用基本功进行评审。你会发现 AI 生成的验证函数虽然可用但违反了“单一职责原则”——它同时验证了用户名、邮箱和密码。我们可以重构它让每个验证规则独立更易于测试和维护。我们可以对 AI 下指令“请将validateUserRegistrationInput函数重构拆分成validateUsername、validateEmail、validatePassword三个纯函数并在原函数中组合调用它们。”3.4 第四步构建Service层——组合与依赖注入创建src/services/user.service.ts。这次我们尝试用更高级的提示让 AI 构建一个符合设计原则的 Service。在文件顶部输入import { UserRegistrationDto, UserEntity, RegistrationResult, RegistrationError } from ../types; import { validateUserRegistrationInput } from ./validation.service; /** * 用户服务接口遵循依赖倒置原则 */ export interface IUserService { registerUser(dto: UserRegistrationDto): PromiseRegistrationResult; } /** * 用户服务实现 * 依赖密码哈希工具、用户仓储库 */ export class UserService implements IUserService { constructor( private readonly passwordHasher: IPasswordHasher, private readonly userRepository: IUserRepository ) {} async registerUser(dto: UserRegistrationDto): PromiseRegistrationResult { // TODO: 实现注册逻辑调用验证、查重、哈希、持久化等步骤 } } // 提示AI需要定义以下依赖接口 // interface IPasswordHasher { hash(password: string, salt: string): Promisestring; generateSalt(): string; } // interface IUserRepository { findByEmail(email: string): PromiseUserEntity | null; save(user: UserEntity): Promisevoid; }然后将光标放在// TODO行使用 AI 补全或对话。一个良好的 AI 在清晰的接口定义和上下文下可能会生成类似下面的逻辑async registerUser(dto: UserRegistrationDto): PromiseRegistrationResult { // 1. 输入验证 const validationError validateUserRegistrationInput(dto); if (validationError) { return { success: false, error: RegistrationError.INVALID_INPUT }; } // 2. 检查邮箱是否已存在 const existingUser await this.userRepository.findByEmail(dto.email); if (existingUser) { return { success: false, error: RegistrationError.EMAIL_EXISTS }; } try { // 3. 密码哈希 const salt this.passwordHasher.generateSalt(); const passwordHash await this.passwordHasher.hash(dto.password, salt); // 4. 构建实体 const newUser: UserEntity { id: generateUUID(), // 假设有一个生成UUID的工具函数 username: dto.username, email: dto.email, passwordHash, salt, createdAt: new Date(), }; // 5. 持久化 await this.userRepository.save(newUser); // 6. 返回成功注意不返回密码哈希等敏感信息 const { passwordHash: _, salt: __, ...safeUser } newUser; return { success: true, data: safeUser }; } catch (error) { console.error(用户注册持久化失败:, error); return { success: false, error: RegistrationError.DATABASE_ERROR }; } }关键点解释这个生成的 Service 已经具备了较好的结构清晰的步骤、依赖注入、显式的错误处理。我们的基本功分层、DI、单一职责通过清晰的接口设计和代码结构成功地“约束”了 AI 的生成方向。4. 运行验证与质量检查代码生成后我们需要验证其功能并利用之前配置的工具检查其整洁度。4.1 编写单元测试AI辅助创建src/services/user.service.spec.ts。我们可以让 AI 基于UserService生成测试骨架。import { UserService } from ./user.service; import { IPasswordHasher, IUserRepository } from ./user.service; // 需要从实现文件导出接口 import { UserRegistrationDto, RegistrationError } from ../types; describe(UserService, () { let userService: UserService; let mockPasswordHasher: jest.MockedIPasswordHasher; let mockUserRepository: jest.MockedIUserRepository; beforeEach(() { mockPasswordHasher { hash: jest.fn(), generateSalt: jest.fn() }; mockUserRepository { findByEmail: jest.fn(), save: jest.fn() }; userService new UserService(mockPasswordHasher, mockUserRepository); }); describe(registerUser, () { it(应该成功注册有效用户, async () { // TODO: 编写测试用例模拟依赖行为断言返回成功结果 }); it(当输入无效时应返回 INVALID_INPUT 错误, async () { // TODO: 编写测试用例 }); it(当邮箱已存在时应返回 EMAIL_EXISTS 错误, async () { // TODO: 编写测试用例 }); }); });然后可以逐一对每个it块内的// TODO使用 AI 补全生成具体的模拟和断言代码。这个过程本身就是在训练你“评审与修正”AI 输出的能力。4.2 执行代码质量检查在终端运行我们之前配置的脚本npm run check # 这会依次运行 eslint 和 prettier如果 AI 生成的代码有任何不符合我们.eslintrc.js中定义的规范如函数过长、命名不规范ESLint 会给出警告或错误。Prettier 会自动格式化代码。这是基本功通过工具实现的自动化守护。4.3 人工评审要点自动化工具检查后仍需人工进行更高层次的评审这些是 AI 目前难以完全替代的逻辑正确性生成的业务逻辑是否符合需求边界条件如空值、极值是否覆盖架构一致性新生成的代码是否符合项目约定的分层和依赖方向如 Service 是否直接引入了数据库驱动可读性变量名、函数名是否清晰表达了意图复杂的逻辑是否有必要的注释异常处理错误是否被妥善处理并转化为对用户或上游友好的信息是否有资源泄漏风险如未关闭数据库连接5. 常见问题与精准排查在与 AI 协作并坚持代码整洁规范的过程中你会遇到一些典型问题。以下是排查清单。问题现象可能原因检查与解决思路AI 生成的代码风格与项目现有风格不一致1. 项目没有统一的格式化配置如.prettierrc。2. AI 训练数据混杂了多种风格。1. 确保项目根目录有.prettierrc和.eslintrc文件。2. 运行npm run format或配置编辑器保存时自动格式化。3. 在给 AI 的提示中明确风格要求如“请使用 async/await 而非 Promise.then”。AI 生成的函数过于庞大职责不清AI 倾向于根据简短描述生成“完整”但内聚性差的代码。1.在提示词中明确要求“请创建一个只负责验证逻辑的函数函数行数不超过30行”。2. 生成后立即使用 AI 的重构功能“请将此函数拆分为三个更小的函数分别处理 X、Y、Z。”3. 手动拆分并以此作为训练 AI 的上下文。生成的代码引入了未声明的依赖或类型错误AI 的上下文理解有限可能引用不存在的模块或错误类型。1. 确保生成代码前相关的接口、类型定义文件已经存在并已导入。2. 使用 TypeScript 编译器 (tsc --noEmit) 或 IDE 的类型检查立即发现错误。3. 提示 AI 时可以附带关键接口的定义。代码能运行但架构上产生了循环依赖或层级混乱AI 专注于局部功能实现缺乏系统级视图。1.这是基本功至关重要的地方。开发者必须拥有清晰的架构图景。2. 在编写模块前先用文字或图表定义好模块边界和依赖关系。3. 定期使用依赖分析工具如madge检查项目依赖图。AI 无法理解复杂的业务规则生成逻辑错误代码AI 对特定领域知识如金融规则、法律条款理解不足。1. 将复杂业务规则拆解为原子化的、可描述的步骤。2. 先为每个步骤编写清晰的函数签名和注释再让 AI 分别实现。3. 为关键业务逻辑编写详尽的单元测试用测试来验证 AI 的输出。6. 最佳实践让AI成为你基本功的“放大器”结合前面的实践我们可以总结出在 AI 时代强化和运用软件基本功的最佳实践。6.1 提示词工程就是需求分析与设计将给 AI 的提示词Prompt视为一种新的、更严格的“需求规格说明书”和“设计文档”来编写。坏提示“写个登录函数。”好提示“请用 TypeScript 实现一个login函数它接收username和password字符串参数。首先调用validateCredentials函数进行校验然后调用UserRepository.findByUsername查询用户接着使用bcrypt.compare验证密码哈希。如果任何一步失败返回Resultnull, LoginError类型的结果成功则返回ResultJwtToken。请遵循项目已有的错误处理模式。”6.2 将代码规范工具集成到CI/CD流水线基本功不能依赖人的自觉性。必须将 ESLint、Prettier、类型检查、单元测试覆盖率等作为 CI/CD 流水线的强制关卡。# 示例.github/workflows/ci.yml name: CI on: [push, pull_request] jobs: quality-check: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: actions/setup-nodev3 - run: npm ci - run: npm run lint # ESLint检查 - run: npx tsc --noEmit # 类型检查 - run: npm test -- --coverage --coverageThreshold{global:{lines:80}} # 测试与覆盖率 - run: npm run build # 构建检查这样无论是人工提交的代码还是 AI 生成的代码都必须通过质量门禁确保代码库的整洁度不会随着迭代而腐化。6.3 建立团队内部的“AI-整洁”协作模式制定团队提示词指南共享那些能生成高质量、符合团队规范的代码的提示词模板。代码评审中关注“AI生成痕迹”评审时不仅要看功能还要看代码是否具有清晰的意图、合理的拆分避免出现“AI 黑箱代码”无人能解释其复杂逻辑。定期重构 AI 生成的代码将重构尤其是提升可读性和可维护性的重构作为一项常规任务而不是等到代码难以维护时才进行。6.4 持续投资于底层理解AI 可以帮你写一个快速排序但如果你不理解时间复杂度和空间复杂度你就无法判断在数据量剧增时它是否还是最佳选择。AI 可以生成一个使用Redis缓存的代码片段但如果你不理解缓存穿透、击穿、雪崩的概念你就无法设计出健壮的缓存策略。因此以下基本功需要持续深化数据结构与算法理解不同选择的性能影响。操作系统与网络基础理解 I/O、进程、内存、TCP/IP才能优化性能、排查深层次问题。数据库原理理解索引、事务、锁才能写出高效的 SQL 和设计合理的表结构。设计模式与架构模式理解何时该用工厂、策略、观察者何时该用微服务、事件驱动。7. 结论与扩展方向对话中 Matt Pocock 和 Robert C. Martin 达成的共识在工程实践中得到了印证AI 不是软件基本功的终结者而是它的“力量倍增器”。它将开发者从繁琐的、机械的代码录入工作中解放出来让我们能更专注于更高层次的价值创造问题定义、系统设计、质量保障和复杂逻辑的梳理。那些认为 AI 时代无需学习基本功的观点是危险的这会导致开发者沦为 AI 的“提示词调试员”和“错误代码缝合者”无法掌控最终产出的质量。相反基本功扎实的开发者能通过精准的指令让 AI 生成更优质的代码并通过专业的评审能力确保代码的可靠性、可维护性和可扩展性。下一步你可以将本文的实践扩展到更复杂的场景尝试让 AI 辅助进行大规模重构例如将回调风格的代码改为async/await并观察它能否保持逻辑正确。探索 AI 在编写集成测试和 E2E 测试中的应用看它能否基于你的业务逻辑生成有效的测试用例。研究如何将领域驱动设计DDD的概念通过提示词灌输给 AI让它生成更符合领域模型的代码。在团队中推行“整洁代码 AI”的协作规范并收集数据看看在代码复杂度、Bug 率和开发速度上带来了哪些实际变化。最终人与 AI 的最佳协作模式是让人类负责战略、意图和质量标准而让 AI 负责战术、实现和重复劳动。而清晰、严谨、可维护的代码正是连接战略与战术确保意图被准确实现的那座桥梁。这座桥梁的建筑学就是软件基本功。
返回列表