周一上午九点,林晨坐在工位上,盯着 GitHub 页面上那个刚刚创建的 Pull Request(代码合并请求),心跳有些加速。这是他在新公司的第一个 PR。
过去一周,他几乎每天加班到晚上十点,周末也泡在代码里。任务不算复杂:为一个 DeFi(去中心化金融)项目的前端添加一个质押收益计算器组件。他用了自己最熟悉的 React 方式完成了开发,自测了几遍,功能都正常。
鼠标在“Create pull request”按钮上悬停了十几秒,林晨深吸一口气,点了下去。页面跳转,PR 编号 #347 出现在屏幕上。他顺手在 Slack 的技术频道里 @ 了 Tech Lead 陈峰:“陈哥,质押计算器组件的 PR 已提,麻烦有空 review 一下”。
消息刚发出去,陈峰几乎秒回:“收到,上午处理”。
林晨松了口气,起身去接水。路过陈峰的工位时,看到对方已经点开了 PR 页面,眉头微皱,手指在键盘上快速敲击。回到座位,林晨强迫自己不去刷新页面,转而开始看项目里另一个模块的代码。但注意力总是不集中,每隔几分钟就忍不住瞥一眼屏幕右下角的 Slack 图标。
这种等待代码审查的感觉,比他预想的要焦虑。在上一家跨境电商公司,他的代码审查通常很顺利——十年老员工,对业务系统和代码库了如指掌,提交的 PR 往往只有些格式小调整。但在这里,一切都是新的:新技术栈、新编码规范、新的最佳实践,甚至新的思维方式。
上午十点半, Slack 图标终于闪动起来。
陈峰:“@林晨 看完你的 PR 了,问题比较多,我们快速过一下?现在方便的话来小会议室”。
林晨心里一沉,回复:“好的,马上来”。
拿起笔记本和笔,他走向走廊尽头的小玻璃会议室。推门进去时,陈峰已经坐在里面,面前的 MacBook 屏幕上正是那个 PR 的页面,右侧评论栏里密密麻麻的红色标记。
“坐”。陈峰指了指对面的椅子,语气平静但严肃,“我们先整体说,然后你回去逐条修改”。
林晨坐下,打开笔记本准备记录。
“首先,功能实现没问题,计算逻辑是对的”。陈峰开门见山,“但问题出在代码质量、安全性和可维护性上。我一条条说,你记一下”。
他滚动页面到文件开头:“第一,TypeScript 类型定义太松散。你看这里”,他指着屏幕,“userInput: any,这等于没定义类型。我们项目要求严格类型,所有变量、函数参数、返回值都必须明确定义。用 any 在审查中直接会被打回”。
林晨点头,快速记下:“明白,我改成具体类型”。
“第二,智能合约交互部分”。陈峰翻到另一段代码,“你直接调用了合约方法,但没有处理可能的失败情况和 Gas 费估算。这在 Web3 前端是必须的——每一次链上交互都可能失败,可能耗光用户 Gas 费。你需要加上 try-catch,加上 loading 状态,加上预估 Gas 并提示用户确认”。
“这个我确实没考虑到……”林晨如实说。在传统 Web 开发里, API 调用失败通常只是重试或报错,但涉及真金白银的 Gas 费,完全是另一个维度。
“第三,代码结构”。陈峰继续,“你把所有逻辑都写在一个组件里,计算函数、格式化函数、状态管理全混在一起。按照我们项目的规范,计算逻辑应该抽离成独立的纯函数,放在 utils 目录下;格式化函数也应该独立;状态管理考虑用 Zustand 而不是全用 useState,因为这部分状态可能在应用其他地方也需要访问”。
林晨看着自己那八百多行的组件文件,突然意识到问题所在——他用了最快速、最直白的方式实现功能,但没考虑后续维护和扩展。
“第四,安全问题”。陈峰的语气更严肃了些,“你这里用了 eval 吗”?
林晨一愣:“没有啊……”
陈峰指向一段动态计算公式的代码:“虽然不是 eval,但你用 new Function 动态执行用户输入的计算公式,这本质上和 eval 一样危险。如果用户输入恶意代码呢?即使在我们自己控制的前端,这种模式也绝对禁止。计算公式必须白名单化,只允许几种预设模式”。
林晨背后冒出冷汗。他确实为了方便,允许用户输入自定义计算公式,然后动态执行。这在传统 Web 也许还行,但在涉及加密资产的环境里,简直是漏洞。
“第五,样式问题”。陈峰翻到最后,“你用了内联样式和大量 !important 覆盖。我们项目用 Tailwind CSS,要求原子化样式类。另外,响应式设计考虑不足,在移动端布局会乱”。
>>>点击查看《AI时代:码农的涅盘重生》最新章节