ARTICLE DETAIL

资讯详情

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

从代码重构到代码审查:技术强者如何助力新人成长

从代码重构到代码审查:技术强者如何助力新人成长 “我都变成强者了不侮辱一下弱者我变强还有什么意义”——这句网络热梗原本是短视频里荒诞的“大型纪录片”式标题但放在技术圈里却意外地写实。有人学了两年 Java看到刚入门的新人写出的代码第一反应是“这也叫代码”有人重构了同事一段逻辑混乱的代码转头就在群里嘲讽对方水平差还有人故意把代码写得晦涩难懂以此营造“高级感”。这些行为的背后都藏着同一个误区把“比别人强”当成了“变强”本身。今天这篇教程不打算讲复杂的架构也不准备介绍某个新框架。我想结合真实的代码示例聊一聊技术成长过程中一个更重要的命题——当你真的变强之后应该如何对待那些“比你弱”的开发者。全文会从一段典型的“初学者代码”出发完成一次完整的代码重构并在此基础上梳理代码审查、结对编程、新人培养等工程实践。这些内容既适合刚工作一两年的开发者也适合正在带新人的团队骨干。为了不让文章变成空谈下面所有内容都会结合可运行的 Python 示例展开。哪怕你平时写 Java 或 Go阅读这些示例也不会有负担核心思想是通用的。1. 背景与核心概念1.1 技术圈里的“强者”与“弱者”“强者”和“弱者”在编程圈并没有明确标准。有人把 GitHub Star 数量当作强弱依据有人把熟练使用某种冷门框架当作强者标志还有人把“能写出同事看不懂的代码”视为能力体现。但稍微推敲就会发现这些标准都很脆弱。GitHub Star 数量可能靠营销获得冷门框架熟练度可能只是因为工作中恰好用到至于写出别人看不懂的代码那不是“强”那是可维护性灾难。在真实的工程环境里衡量一个开发者是否强大看的不是写代码的速度有多快也不是用过多少框架而是他写出的代码别人是否容易阅读和维护面对线上故障他能否快速定位问题他是否愿意耐心解答新人的提问他能否通过合理的抽象和设计降低整个团队的维护成本。换句话说“强者”的核心能力不是压倒别人而是解决问题。技术圈真正值得尊敬的“强者”往往是那些愿意把复杂问题讲简单、把混乱代码理顺、把团队整体水平带上去的人。1.2 “鄙视链”的危害编程圈长期存在一条隐形的鄙视链C 开发瞧不上 Java 开发Java 开发觉得 Python 开发不够“底层”前端和后端之间更是互相不理解。当一个人进入“鄙视”状态时他会自动关闭学习和沟通的大门。从团队角度看“鄙视新人”的后果更加直接新人不敢提问问题被隐藏最终演变成线上事故代码审查流于形式新人不敢提出不同意见团队成员之间的信任消失协作效率快速下降新人要么离职要么变成下一个“鄙视者”形成恶性循环。所以如果你真的觉得自己“变强了”那么首先要修炼的科目不是技术而是心态。2. 环境准备与版本说明为了让文章中的示例可以实际运行我们先准备好最小实验环境。本文示例使用 Python 3.8 以上版本不需要安装任何第三方依赖。环境项说明操作系统Windows 10/11、macOS、Linux 均可语言版本Python 3.8IDEPyCharm、VS Code 或任意文本编辑器第三方依赖无仅使用 Python 标准库如果本机还没有安装 Python可以前往官网下载安装包。安装完成后在命令行输入python --version检查版本python --version预期输出类似Python 3.10.12本文后面的代码都围绕一个经典场景展开用户注册信息校验。这个场景逻辑足够简单适合展示“从差代码到好代码”的完整重构过程同时又足够贴近实际业务方便你迁移到自己的项目中。3. “弱者代码”的典型特征在展示重构案例之前我们先把初学者代码中常见的问题做一个系统化梳理。这不是为了嘲笑初学者而是为了在代码审查时我们能够“有的放矢”地指出问题。3.1 命名不规范初学者习惯用a、b、c、data、tmp这类词语命名变量和函数。命名一旦失去含义代码阅读者就需要在脑子里做一次“翻译”效率很低。举个例子check(name, age, email)这个函数名你很难一眼看出它检查了什么、在哪里使用、返回什么。3.2 魔法数字与魔法字符串直接在业务逻辑中写出18、2、admin这样的值会让代码行为变得难以理解。为什么是 18为什么是 2这些值在不同业务场景下随时可能变化散落在代码里会导致修改时漏改。3.3 缺少异常处理用户输入是不可信的。初学者代码往往假设输入一定是合法的一旦出现age abc或者email None程序直接崩溃。线上环境里这类问题造成的用户投诉往往最多。3.4 函数过长与代码重复一个函数动辄上百行里面写了登录、校验、日志、通知等所有逻辑。修改任何一个环节都可能影响其他环节。更重要的是这种函数无法进行单元测试因为每次测试都必须构造一整套完整的环境。3.5 返回结果不结构化函数返回一个字符串ok表示成功返回其他字符串表示失败。调用方无法区分“参数格式错误”和“业务规则不满足”也无法拿到错误码用于前端提示或日志监控。一旦字符串拼错整个逻辑就悄悄失效。3.6 典型特征汇总特征示例潜在风险命名不规范a 张三可读性差维护困难魔法值if age 18:需求变更时容易漏改缺少异常处理int(age)输入异常直接崩溃函数过长200 行函数无法测试和复用不结构化结果return ok调用方难以判断错误类型4. 实战案例一次完整的代码重构这一节是整篇文章的核心。我们将从一段典型的“初学者风格”注册校验代码出发分析存在问题然后逐步重构为具备工程质量的代码。整个过程也可以看作一次“从弱者到强者”的代码进化演示。4.1 起点初学者风格的原始代码先看第一版代码# 文件路径src/demo_v1.py def check(name, age, email): if len(name) 2: return 用户名太短 if name admin: return 用户名不允许 if age 18: return 未满18岁 if not in email: return 邮箱格式错误 return ok这段代码只有 10 行看起来非常简洁但问题非常多。问题 1函数名check太泛。是校验格式校验重复还是校验权限调用方看到这个名字完全不知道内部做了什么。问题 2参数名称name、age、email过于简单。如果是注册场景username比name更准确因为name可能还表示“姓名”。问题 3len(name) 2中的2是魔法数。如果产品经理提出“用户名最短是 3 个字符”你需要在代码里找到这个2并修改而代码里可能有很多个2。问题 4邮箱校验用 not in email实现过于粗糙。a可以通过校验也可以显然不是合法的邮箱格式。问题 5返回字符串ok。调用方写成if check(...) ok:一旦有人不小心把字符串改成OK整个逻辑就失效了。4.2 第一轮优化从可读性入手先解决命名、魔法值、返回结构的问题# 文件路径src/demo_v2.py USERNAME_MIN_LENGTH 2 ADULT_AGE 18 FORBIDDEN_USERNAMES {admin, root, test} class UserValidationError(Exception): def __init__(self, code, message): self.code code self.message message super().__init__(message) def check_username(username): if len(username) USERNAME_MIN_LENGTH: raise UserValidationError(USERNAME_TOO_SHORT, 用户名长度不能小于2个字符) if username in FORBIDDEN_USERNAMES: raise UserValidationError(USERNAME_FORBIDDEN, 该用户名不允许注册) def check_age(age): if age ADULT_AGE: raise UserValidationError(AGE_NOT_ADULT, 未满18岁不允许注册) def check_email(email): if not in email or . not in email: raise UserValidationError(EMAIL_INVALID, 邮箱格式不正确) def validate_user(username, age, email): check_username(username) check_age(age) check_email(email)这一版优化后函数被拆小每个函数只负责一类校验魔法值被提为常量错误统一通过UserValidationError异常抛出并且带上错误码。不过这里还有一个明显问题如果用户传入的age不是整数而是字符串abccheck_age中的age ADULT_AGE会直接抛出TypeError这会让调用方感到困惑。4.3 第二轮优化数据结构与结果对象在真实工程中我们通常不会把用户信息拆成三个独立参数传递而是封装成一个数据对象。同时校验结果也不一定采用抛异常方式因为“注册信息不合法”属于业务分支不是程序异常。使用结果对象会更清晰。# 文件路径src/demo_v3.py 用户注册信息校验模块。 该模块通过数据类组织用户输入并在校验时返回结构化结果 避免使用魔法字符串和裸抛异常提高代码可读性与可测试性。 from dataclasses import dataclass, asdict from typing import Optional import re import logging logger logging.getLogger(__name__) # 常量配置区 USERNAME_MIN_LENGTH 2 ADULT_AGE 18 FORBIDDEN_USERNAMES {admin, root, test} EMAIL_PATTERN r^[\w\.-][\w\.-]\.\w{2,}$ dataclass class UserInfo: 待校验的用户注册信息。 username: str age: int email: str dataclass class ValidationResult: 校验结果对象。 is_valid: bool error_code: Optional[str] None message: Optional[str] None def validate_username(username: str) - ValidationResult: 校验用户名。 Args: username: 用户名。 Returns: ValidationResult 对象。 if len(username) USERNAME_MIN_LENGTH: return ValidationResult( False, USERNAME_TOO_SHORT, 用户名长度不能小于2个字符 ) if username in FORBIDDEN_USERNAMES: return ValidationResult( False, USERNAME_FORBIDDEN, 该用户名不允许注册 ) return ValidationResult(True) def validate_age(age: int) - ValidationResult: 校验年龄。 if age ADULT_AGE: return ValidationResult( False, AGE_NOT_ADULT, 未满18岁不允许注册 ) return ValidationResult(True) def validate_email(email: str) - ValidationResult: 校验邮箱格式。 if not re.match(EMAIL_PATTERN, email): return ValidationResult( False, EMAIL_INVALID, 邮箱格式不正确 ) return ValidationResult(True) def validate_user(user: UserInfo) - ValidationResult: 对用户注册信息执行完整校验。 Args: user: 用户信息对象。 Returns: 汇总后的校验结果。校验失败时返回第一个失败项。 checkers [ validate_username(user.username), validate_age(user.age), validate_email(user.email), ] for result in checkers: if not result.is_valid: logger.warning( 用户校验失败, 错误码%s, 原因%s, 用户信息%s, result.error_code, result.message, asdict(user), ) return result return ValidationResult(True)这一版的主要提升点有以下几项UserInfo数据类把零散的三个参数组织成一个对象后续扩展字段如手机号、密码时不需要修改函数签名。ValidationResult作为结构化结果携带is_valid、error_code、message调用方可以直接根据error_code做前端提示或日志监控。校验函数职责单一validate_username、validate_age、validate_email各自独立方便单独测试。加入日志记录校验失败时可以快速定位原因。使用re.match校验邮箱比 in email可靠得多。4.4 运行与验证编写入口函数并运行# 文件路径src/main.py from demo_v3 import UserInfo, validate_user def main(): cases [ (张三, 20, zhangsanexample.com, 正常注册), (李四, 16, lisiexample.com, 未成年), (a, 20, aexample.com, 用户名过短), (admin, 20, adminexample.com, 禁止用户名), (王五, 20, wangwu, 邮箱格式错误), ] for username, age, email, desc in cases: user UserInfo(usernameusername, ageage, emailemail) result validate_user(user) print(f场景: {desc}, 结果: valid{result.is_valid}, ferror_code{result.error_code}, message{result.message}) if __name__ __main__: main()运行方式cd src python main.py预期输出场景: 正常注册, 结果: validTrue, error_codeNone, messageNone 场景: 未成年, 结果: validFalse, error_codeAGE_NOT_ADULT, message未满18岁不允许注册 场景: 用户名过短, 结果: validFalse, error_codeUSERNAME_TOO_SHORT, message用户名长度不能小于2个字符 场景: 禁止用户名, 结果: validFalse, error_codeUSERNAME_FORBIDDEN, message该用户名不允许注册 场景: 邮箱格式错误, 结果: validFalse, error_codeEMAIL_INVALID, message邮箱格式不正确4.5 两版代码的对比维度第 1 版第 3 版代码行数10 行约 80 行可读性差逻辑混在一起好每个函数职责单一可测试性低只能整体调用高可单测每个校验函数错误处理字符串返回易拼错结构化结果带错误码扩展性新增字段需改签名新增字段只需改数据类日志能力无内建日志你可能会问重构后代码变长了这算“变强”吗算的。工程代码的“强”不在于短而在于可维护。一段 80 行、结构清晰的代码其长期维护成本远低于一段 10 行、含义模糊的代码。真正的强者追求的是团队效率的最大化而不是个人表现的最小化。5. 强者如何做代码审查Code Review技术变强之后你大概率会成为团队里的代码审查者。代码审查是“强者”与“弱者”打交道最频繁的场景也是最容易暴露沟通方式的环节。5.1 一份实用的 Code Review 清单面对一段新人提交的代码建议按以下顺序检查检查项具体关注点功能正确性代码是否实现了需求边界条件是否覆盖代码可读性命名是否清晰逻辑是否容易理解安全性是否存在注入、越权、敏感信息泄露风险性能是否有不必要的循环、慢查询、大对象加载异常处理是否捕获了合适的异常是否有兜底逻辑可测试性核心逻辑是否可以单元测试兼容性数据库迁移是否兼容旧数据接口变更是否考虑老版本客户端上面每一项都值得展开但在实际审查时不需要一次全部讲完。新人一次能吸收的反馈数量有限抓重点即可。5.2 如何提问而不是攻击“你这段代码是错的。”——这是一句攻击。“这里在用户名为空的时候会直接走数据库的 NOT NULL 约束我们能提前做一层校验吗这样错误提示会更友好。”——这是一个建议。同一件事两种表达方式接受度完全不同。代码审查的目的不是证明“我比你强”而是帮助团队一起写出更好的代码。所以在实际沟通中可以遵循三个原则先用提问确认对方意图“这里的校验逻辑是基于什么考虑”再提出改进建议“如果改成 X 方案会不会更简单”最后补充理由“因为上线后这个报错会直接展示给用户提前校验可以避免 500 错误。”5.3 常见的错误示范错误示范问题“你这也叫代码”人身攻击毫无信息量“我以前写 XX 框架时从来不用这个”用个人偏好代替客观标准“这个 bug 很明显你用脑子想想”假设对方专业知识背景制造压迫感不回复、直接改动代码剥夺新人的学习机会破坏信任6. 帮助“弱者”成长的工程实践如果你真的想让身边的“弱者”变强除了心态上的尊重还需要一些具体的工程手段。下面介绍三个经过大量团队验证的做法。6.1 结对编程结对编程不是“你写我看着”而是两个人共同完成一个任务。推荐采用经典的“驾驶员—导航员”模式角色职责驾驶员负责写代码关注当前实现细节导航员负责思考整体方向提前规划下一步关注边界和潜在问题结对时要注意几个细节每 20 到 30 分钟交换一次角色强者不要急着抢键盘给新人留出足够的试错空间结束后花 5 分钟复盘记录这次结对中发现的问题和收获。6.2 文档与知识库建设新人适应一个项目最怕的就是没有文档。如果你已经“变强”可以为团队做一件长期有价值的事把常用的启动流程、部署流程、常见问题整理成文档。技术文档不需要写得像论文关键是准确和可操作。一个合格的快速开始文档应包含项目依赖的软件及版本从拉取代码到本地启动的完整命令首次启动时的常见报错及解决方案连接本地测试账号的方法。6.3 定期技术分享每周或每两周举行一次半小时的技术分享轮流主讲。新人可以讲“最近学到的知识点”强者可以讲“最近踩过的一个坑”。分享最重要的是营造安全氛围允许讲错允许追问但不允许嘲笑。7. 常见问题与排查思路在实际工作与成长过程中你可能还会遇到下面这些问题。问题现象常见原因解决思路新人不愿意向你提问你曾经在公开场合批评过新人私下 1 对 1 沟通重新建立信任代码审查流于形式大家害怕提意见引发冲突明确审查规范区分“必须改”与“建议改”重构后代码变多被同事质疑只展示了代码量没有解释维护成本用可测试性、错误码、扩展性等量化收益新人长时间无法接手项目缺少文档知识集中在强者脑中推动文档建设鼓励结对编程团队出现鄙视链氛围有“技术权威”带头嘲讽管理者介入建立“无嘲笑”的代码审查制度如果遇到“新人提交的代码问题非常多”的情况建议不要一次性把所有问题都提出来。先挑最容易引发线上事故的问题比如空指针、SQL 注入其余问题留到后续迭代逐步改进。一次审查指出 3 到 5 个关键问题远比列出 20 条意见更有价值。8. 最佳实践与工程建议8.1 用代码规范替代主观争论团队里关于代码风格的争论本质上是缺少统一规范。与其在心里鄙视同事的命名风格不如推动团队引入自动化检查工具。例如 Python 项目可以使用black统一格式使用ruff检查常见问题Java 项目可以使用Checkstyle和SpotBugs。自动化规范的好处是讨论由“人 vs 人”变成“代码 vs 规范”冲突成本大幅降低。8.2 把知识沉淀到代码里好的代码本身就是文档。命名使用有业务含义的单词函数拆分到合适的粒度常量使用语义化名称这些做法比事后补注释更有效。必要时再加注释说明“为什么这么做”而不是注释“这段代码做了什么”——后者只会增加噪音。8.3 善待“弱者”就是善待未来的自己这句话不是鸡汤。技术圈迭代速度很快你依赖的框架可能明年就被新方案替代今天刚入门的新人几年后可能就是你的上级或合作伙伴。以尊重、开放的心态与每一个开发者协作长期来看你积累的不仅是技术能力还有宝贵的人脉和口碑。8.4 技术成长与心态成长同步建议给自己定几条原则贴在工位旁边不主动评价任何人的代码水平除非对方希望你给出建议每次代码审查都至少提出一个肯定点面对新人重复提问时先想到“文档是不是不够清楚”而不是“这个人是不是太笨”每当产生“这人水平真差”的想法时提醒自己两年前你可能还不如他。9. 总结与学习路线这篇文章从一个网络梗切入聊了聊技术圈“强者与弱者”的话题。我们通过一个实际可运行的 Python 示例完整展示了从一段初学者风格的代码重构为具备工程质量的代码的全过程。学到这里你应该已经掌握初学者代码的典型问题特征如何通过命名规范、常量提取、结果对象、日志等手段提升代码质量代码审查的正确姿态与沟通技巧结对编程、文档建设、技术分享等帮助新人成长的手段团队中常见的沟通问题与解决思路。如果你的目标是在技术上真正“变强”那么下一步可以沿着这条路线继续深入学习更系统的代码风格规范例如 Google Python Style Guide掌握单元测试为重构后的代码补充测试用例阅读《重构改善既有代码的设计》学习更多重构手法参与开源项目在真实 Code Review 中体会沟通与协作的艺术。“变强”不是终点而是漫长的路。愿你在路上遇到“弱者”时能想起这篇教程的标题然后选择做那个拉人一把的人而不是踩人一脚的人。共勉。
返回列表