多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

从代码评审看Java工程化习惯的养成

从代码评审看Java工程化习惯的养成 代码评审不是找茬是照镜子。有人对着镜子看到一个又一个丑陋的if分支有人却看到自己从“会写Java”到“懂工程化”的进化轨迹。在评审台上没有哪一行代码是无辜的每一个命名、每一个空行、每一次异常的吞掉都在替你回答一个问题你真的想过要长期维护这套系统吗评审现场的真实尴尬我见过最典型的评审场景是开发者自信满满地讲解一个功能实现突然有人问“如果这个Redis调用超时了怎么办”他愣了一下“不会吧Redis很快的。”这句话一出整个会议室安静了三秒。那种安静不是认可是礼貌地替你感到悲哀。因为“不会超时”不是技术判断是运气赌博。而工程化习惯恰恰是把“不会发生”变成“发生了也不怕”的能力。代码评审最残酷的地方是它会把你的潜意识摆上台面。你以为封装得很好的工具类别人一眼看出你在复制粘贴了三次之后才想到抽象你以为精心设计的继承体系别人指出超类的一个字段变更会偷偷影响八个子类。这些都不是能力问题是习惯问题。能力可以通过学习补齐习惯必须通过一次次被挑战、被质疑、被打脸来重塑。命名工程化习惯的第一道分水岭评审单上出现频率最高的批注往往不是算法复杂度而是变量名。tmp、data、list、obj这些名字本身就在宣告写代码的人根本没想清楚这个变量在业务中代表什么。一次评审中我盯着一个叫result的List看了五分钟最终还是得顺着调用链逆推才发现它是“上个月逾期用户的ID集合”。如果命名能直说评审时间至少缩短一半。命名是写给未来同事的情书也是写给未来自己的免责声明。一个叫paymentRetryCount的字段三周后你看到它就知道该在什么场景下重置叫num的字段三周后你只能靠猜。工程化习惯不是从设计模式开始而是从拒绝使用a1、a2这种变量名开始。你在命名上省下的三秒钟思考会在未来某个凌晨三点的故障排查中以三十分钟的代价连本带利地还给你。更进一步命名习惯会倒逼你思考领域边界。当你为一个方法取名validateOrder时你会下意识地问它校验了状态吗校验了金额吗校验了库存吗如果不够你就会拆分它。命名质量从来不是修辞问题而是建模能力的直接映射。代码评审中我常以“这个名字如果不看实现你能猜到它做什么吗”为标准。猜不到就得改。异常处理暴露工程成熟度的试金石Java开发者之间最快速的分级方法就是看他写catch块。新手喜欢catch (Exception e)然后打印一行e.printStackTrace()或干脆吞掉老手会精准捕获、区分可恢复与不可恢复、向上抛带上下文的业务异常。评审中最刺眼的代码往往不是逻辑错误而是那种catch (Exception e) { log.error(xxx failed, e); }——然后方法继续优雅地执行好像什么都没发生。吞掉异常不是容忍错误是对故障的默许。你可以在评审时问一句“如果这里失败了系统的降级方案是什么用户会看到什么链路追踪里能查到吗”三个问题问下来大部分吞异常的场景都会原形毕露。工程化习惯要求你养成的第一反应是异常不只代表“出事了”还代表“有人需要知道出事了”。这个“有人”可能是用户、可能是运维、可能是下一个排查问题的你自己。更微妙的是受检异常与运行时异常的选择。Java的受检异常曾被视为工程严谨性的象征但在实际评审中我看到太多throws Exception的上抛习气把调用方的每一个方法签名都搞得像一场灾难预警。工程化不是把异常扔给所有人看而是确定谁才是真正需要处理它的人。如果一个异常不需要调用方做任何决策它就是运行时异常如果需要你就必须把它变成一个能够携带业务语义的显式签名。这不仅是技术选择更是职责边界的清晰划分。可测性评审中最容易被忽略的隐形评分项很多代码评审只盯功能和性能却忘记问一句“这段代码怎么测试”这不是没事找事因为可测性直接决定未来改动的安全系数。没有测试保护的代码就像没有安全绳的高空作业——每一次重构都在赌命。而可测性差往往不是测试的问题是设计的问题。当你写了一个两百行的私有方法里面直接new了ServiceLocator、调了静态方法、访问了全局配置你在评审时就会看到自己亲手垒起的高墙。别人想给这个方法写个单元测试却发现必须先启动Spring容器、连接一个真实数据库、再模拟一个外部HTTP接口。于是测试只好变成集成测试甚至压根不写。代码评审中看到一个方法无法被快速构造出测试环境就应该立刻意识到这是依赖注入缺失、状态管理混乱、或职责过载的信号。我曾在评审中给过一个非常实用的标准“如果一个方法不能在一个测试用例中独立证明自己那它就不够工程化。”要让一个方法可测你需要通过构造函数参数传入依赖而不是在方法体内自己去findService你需要返回结果而不是修改全局状态你需要小而纯的核心逻辑和外层笨重的IO隔离。这些习惯不是凭空冒出来的每一次评审追问“你怎么测这个分支”都是一次对代码结构的重新审视。冗余与过度设计评审中的两种极端病工程化习惯的养成从来不是线性的“越来越复杂”。更多时候你是在“过度设计”和“复制粘贴病”之间走钢丝。评审中见过一个状态机框架为了处理三种状态用了八个类、四个接口、两个抽象工厂最后业务方自己都记不清流转规则也见过一个订单导出功能在Service层堆了六百行没有拆分没有模型全靠并列的if-else一路平推。过度设计是对简单问题的复杂补偿复制粘贴是对重复问题的懒惰妥协。代码评审的价值之一就是帮作者分辨目前的复杂度是否配得上问题的真实复杂度。一个只会在三个地方使用的公共类真的需要支持SPI扩展吗一个只有两种类型的枚举真的需要策略模式吗反过来你第三次写同样的逻辑时真的还打算再复制一次吗工程化习惯的核心是“度”的感知。这种感知只有靠大量的代码评审积累——你看到过过度设计导致的维护灾难看到过复制粘贴导致的多处不一致修复才会在每一次下笔时多问自己一句“现在这个设计是在解决问题还是在解决我自己的焦虑”在代码评审中一句“这个抽象解决的是未来十个版本的问题还是眼前这一个功能的问题”往往能直接戳破所有伪需求。代码评审作为习惯的熔炉很多人把代码评审当作质量关卡其实它是行为矫正器。每一次评审意见都是一次对习惯的微调。你一开始可能需要别人提醒“别忘了判空”后来变成自己写代码时主动考虑边界你一开始需要别人指出“这个方法太长了”后来变成自己写完就下意识地拆分你一开始需要别人质疑“这个异常被吞了”后来变成自己先抛出带上下文的新异常。真正的工程化习惯是把“让代码便于他人阅读”内化成肌肉记忆。而这种肌肉记忆的获得唯一的捷径就是在评审中被反复按摩擦。没有在评审中被人追问“为什么这里用HashMap而不是TreeMap”你永远是在瞎选集合没有在评审中被人指出“这个方法的返回类型应该用接口而不是具体类”你永远在依赖实现细节。每一次评审交流都是你原来自以为合理的做法被重新评估的过程也是你向工程共同语境靠拢的过程。最终你会发现代码评审其实是在训练一种“第三人称视角”。你开始在写代码的时候就模拟评审者会怎么挑毛病于是自动避开了一些显而易见的坑你开始把“别人能不能看懂”作为评价自己代码的标准于是写出来的东西天然带上了工程化的痕迹。这个世界的代码并没有因评审而完美但那些经得起评审的代码背后一定站着被评审打磨过无数次的工程师。他们拥有的不是什么高深技艺而是被一次次会议逼出来的——在每一次“我本可以写得更好”的遗憾中把更好的习惯刻进指尖。
返回列表