“屎山代码”这四个字,放在技术圈里已经不是简单的吐槽,而成了一种文化现象。每个团队几乎都有一片“祖传代码区”,每次改动都像在流沙上盖楼,越修越玄乎。我在这个行业混了十几年,亲眼见过代码从简洁走向混沌,也亲手收拾过几片快塌掉的“屎山”。这篇文章标题确实有点皮,叫“写出屎山代码的12个技巧”,但我的目的不是教你作恶,而是想让你清楚看到这些“技巧”到底长什么样——它们全是我在真实项目里见过、踩过、甚至自己写出来的反面教材。逐一拆完之后你自然会发现:每一条反面“技巧”,背后对应的都是一条正向的编码心法。
1. 先聊聊“屎山代码”是怎么形成的
1.1 屎山代码的定义与三大特征
屎山代码,英文里有个更文雅的说法叫 Big Ball of Mud,直译过来是“大泥球”。它不是指某一行代码写得烂,而是指整个模块、整个服务、甚至整条业务链路的代码结构已经混乱到没法正常维护的状态。我总结下来,屎山通常有三大特征。
第一个特征是“改不动”。想加一个字段,改完A处还要改B处,B处又牵出C处,最后发现全项目里散落着十多个地方的逻辑都要跟着动。改完以后心里没底,因为依赖关系根本没有边界。第二个特征是“看不懂”。一个函数几千行,变量名叫 data、temp、val,业务含义完全靠猜。第三个特征是“一碰就碎”。没有测试保护,没有分层抽象,任何小改动都有可能引爆一个完全不相干的模块。
这三个特征不是孤立存在的。它们往往互相强化:越看不懂就越不敢改,越不敢改就越堆新逻辑,越堆逻辑结构就越乱,最后形成恶性循环。所以说屎山不是一天建成的,它是一点一点“积累”出来的。
1.2 为什么大家一边骂一边写
有个很扎心的现实:大部分屎山代码,都不是故意的。没有人早上起来打开电脑,跟自己说“今天我要写一坨烂代码,让后人痛苦三年”。但事实就是,屎山源源不断地被生产出来。为什么?
最大的原因是业务压力。老板说这个功能下周必须上线,你算了算排期不够,只好砍掉重构、砍掉测试、砍掉注释,先把功能跑通再说。第二个原因是“以后再说”心态。写完一段看起来很“临时”的代码时,总会想“等需求稳定了我再来整理”,结果需求永远不稳定,这段临时代码就在核心链路里活了好几年。第三个原因是人员流动。写代码的人走了,文档没有,设计文档也没更新,接手的人只能靠猜,猜完再继续往上堆。
这几点叠加起来,屎山的形成几乎是必然的。所以这篇文章虽然名叫“技巧”,但核心精神是让你对照这些反面教材,搞清楚屎山到底是怎么被一块砖一块砖砌起来的,从而在源头就停手。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 12个反面技巧全景盘点:一张表看明白
先给你一张全貌图。这张表把12个“技巧”一个一个列出来,每一行都是一句扎心的总结。你可以先通读一遍,看看自己中了几条。后面我会分成两大部分,把每条“技巧”的都掰开揉碎讲清楚。
| 编号 | 反面“技巧” | 最终效果 | 对应的正向做法 |
|---|---|---|---|
| 1 | 变量名随心所欲 | 代码含义全靠脑补,维护成本爆炸 | 命名要能准确表达业务含义 |
| 2 | 一个函数包打天下 | 函数上千行,改一处崩三处 | 拆成小函数,每个函数只做一件事 |
| 3 | 复制粘贴是第一生产力 | 同款bug遍地开花,改都改不干净 | 抽公共模块,消除重复 |
| 4 | 魔法数字与魔法字符串 | 换个需求找半天,还容易改错 | 抽成常量或枚举,给数字起名字 |
| 5 | 错误处理全靠运气 | 生产环境静默失败,出问题查不到 | 显式捕获异常,留下可观测日志 |
| 6 | 注释和文档?不需要 | 只有“懂王”才能读的代码 | 写好必要注释,维护关键文档 |
| 7 | 全局变量满天飞 | 状态完全失控,排查问题如同大海捞针 | 缩小变量作用域,依赖显式传递 |
| 8 | 所有功能塞进一个文件 | 单文件几千行,多人协作等于互相踩脚 | 按模块拆分文件,让目录结构说话 |
| 9 | 无视代码规范,自由发挥 | 风格五花八门,diff永远不干净 | 统一规范,提交前自动格式化 |
| 10 | 滥用高级语法炫技 | 看起来高大上,实际没人读得懂 | 用团队最熟悉的写法,可读性第一 |
| 11 | 不写测试,编译过就算赢 | 上线像开盲盒,事故全靠用户发现 | 建立自动化测试,把回归风险兜住 |
| 12 | 提交信息乱成一锅粥 | 历史记录变成黑洞,bug无法追溯 | 写好提交信息,养成原子提交习惯 |
这张表我建议你截图或者抄下来贴在工位上。每一次写代码之前扫一眼,想想自己是不是正在往某个“技巧”靠拢。下面来详细展开。
3. 重点拆解:6个最致命的“技巧”
3.1 技巧一:变量名随心所欲
这个“技巧”的奥义是:让变量名完全失去信息量,让每一位接手代码的同事都体会到福尔摩斯破案的快感。
我见过最夸张的例子,是一个处理订单金额的函数里有三个变量,分别叫 a、b、c。你能猜到它们各自是什么意思吗?猜不到。后来我查了半天才发现,a 是商品原价,b 是折扣率,c 是最终结算价。这种命名等于给所有后来者设了一道智力题,而且答案文档已经丢失,只能靠推理。
为什么我们总是不自觉地用烂名字?因为起名字本身是一件费脑子的事。你在写代码那一刻,脑子里的上下文是完整的,你会觉得 data 这个变量名完全没问题,因为“我现在就是想存一组数据”。但问题是,三周以后,你自己回来看这段代码的时候,上下文早就不在了,data 到底是什么数据?那一瞬间你就会后悔。
正向的解法其实不难:命名时多花30秒,想一下这个变量的生命周期是什么、它代表什么业务概念、它会被谁使用。哪怕多写几个单词,也比一个含混不清的 x 强得多。函数名同理,handleData 这种名字等于没起,calculateOrderDiscount 这种名字才是有信息量的。名字就是代码的说明书,省事一时,后面还债无穷。
3.2 技巧二:一个函数包打天下
这个“技巧”的精髓是:把所有逻辑塞进一个函数,让函数的缩进层级多到像千层面,让看代码的人感受到一种窒息式的压迫感。
有个真实的例子。前几年我接手过一个支付回调接口,核心函数大概1200行,里面包含了参数校验、签名验签、订单状态判断、库存扣减、积分发放、消息推送、异常兜底,还有三个嵌套的 for 循环和五层 if 缩进。想改其中一个环节?你得先翻个三五分钟才能找到要改的位置,改完还得担心会不会影响同一个函数里其他毫不相关的逻辑。
这种代码的问题在于,函数把不同层次的抽象全部混在了一个平面里。就像把你的衣柜里所有东西——外套、袜子、领带、旧手机、发票——全部堆在一个抽屉里,你要找一支笔得翻半天。
函数式编程有一句老话:每个函数应该只做一件事。这句话听起来简单,做起来却需要克制。拆函数不是为了炫技,而是为了把“做什么”和“怎么做”分开。比如支付回调流程,你可以拆成 validateRequest、verifySignature、processOrder、updateInventory、sendNotification 这几个小函数,每个函数控制在二三十行以内。这样每个函数都能独立阅读、独立测试,出了问题也能快速定位。
3.3 技巧三:复制粘贴是第一生产力
“这个功能上一个模块写过类似的,直接复制过来改改就行”——这句话是屎山生长的核心引擎。
复制粘贴最恐怖的地方不在于代码重复,而在于重复背后的逻辑分叉。你今天复制了一段订单状态判断的代码,三个月后业务规则变了,你在A处改了,B处、C处的复制品没改,同一个业务就有三种不同的表现,用户就会遇到“有时能下单有时下不了单”的玄学问题。
我再举个具体场景。一个电商系统里,判断“用户是否可以申请售后”的逻辑,在订单详情页有一份、在售后申请页有一份、在管理后台有一份,三份代码各自经过不同的人员维护,最终对“已发货但未签收”这个状态的处理完全不一致。用户在前台看到可以申请,后台审核时却提示状态不合法,工单就是这么来的。
正确的做法是:重复出现第二遍的时候,就应该考虑抽取公共函数或公共模块。第三遍还不抽,那就是给自己埋雷。当然,抽取抽象本身也有成本,过早抽象反而会让代码更难懂。我的经验是“事不过三”原则:第一次正常写,第二次留意相似性,第三次一定要抽出来统一封装。如果你发现项目里某个逻辑的副本已经超过三个,那已经属于技术债的范畴,要记账并尽快处理。
3.4 技巧四:魔法数字与魔法字符串
所谓魔法数字,就是代码里直接出现的、没有任何解释的裸数值。比如 if (order.status === 3),这里的 3 到底是什么状态?是已支付、已发货、还是已取消?没人知道。再比如 price * 0.85,这个 0.85 是折扣吗?是平台抽成比例吗?还是活动优惠?只能靠猜。
魔法字符串同理,if (user.type === "vip"),这个 "vip" 是写死的,如果有人写成了 "Vip" 或者 "VIP",这个判断就悄无声息地失效了。这种bug最阴险的地方在于它不会报错,只是行为不符合预期,排查成本极高。
好的写法是给这些数值和字符串起名字。可以用常量:const ORDER_STATUS_PAID = 3;,也可以用枚举(enum)或者 TypeScript 的联合类型。核心思路是:让业务含义在代码里显式存在,而不是藏在一堆裸数字背后。你想想看,如果代码是 if (order.status === OrderStatus.PAID),是不是读起来就清爽多了?而且以后要查“哪些地方用到了已支付状态”,直接搜 OrderStatus.PAID 就能全部搜出来,魔法数字能做到吗?做不到。
3.5 技巧五:错误处理全靠运气
“这个接口理论上不会出错”——这是我听过最危险的一句话。任何外部依赖——数据库、网络、第三方接口——都有可能会挂。而屎山代码的特征之一,就是错误处理缺失到令人发指。
常见的反面姿势有三种。第一种:catch 块里什么都不写,或者只写一行 // ignore,异常被吞掉,程序继续跑,但数据已经不对了。第二种:完全不捕获,让异常一路向上抛,最终结果是用户看到一屏技术报错堆栈,或者直接白屏,而日志里什么关键信息都没记录。第三种:把所有异常打成同一种“系统繁忙”,具体原因不记录,排查问题的时候日志一片空白,只能靠猜。
这里我想强调一个认知:错误处理不是“防御性编程”的花架子,而是生产系统最后一条生命线。你吞掉一个异常,可能当时没事,但几周后数据对不上账的时候,你连从哪儿开始查都不知道。正确的姿势是“明确捕获、明确处理、明确记录”。能恢复的异常要恢复,不能恢复的异常要抛出并中断流程,同时把错误码、错误信息、堆栈、上下文参数全部记到日志里。只有这样,出问题时你才有据可查。
3.6 技巧六:注释和文档?不需要
这个“技巧”的拥趸通常有两大理由:第一,“代码即文档,好代码不用注释”;第二,“写注释浪费时间,需求变更太快注释容易过时”。
这两个理由都有道理,但它们是用来反对“无效注释”的,不是用来反对“注释”本身的。注释的真正价值,在于记录代码本身表达不了的信息。比如一个方法为什么用轮询而不走消息队列,比如某个字段为什么允许为空,比如这段逻辑是为了兼容哪个历史版本的垃圾数据。这些决策信息代码里看不出来,如果不写注释,后人就只能靠猜。
我见过最无语的一段代码,是在并发扣减库存的场景里,用了 synchronized 关键字,但没有任何注释解释为什么要在方法级别加锁。两个月后新来的同事看到这段代码,觉得锁粒度太大影响性能,大笔一挥改成了乐观锁,结果出现超卖,损失惨重。如果原作者留一行注释说“这里因为历史订单和库存表在同一个事务里,分布式锁会导致死锁,故退化为JVM本地锁”,后面的人根本不会碰这个雷。
文档也是一样。接口文档、架构图、数据流图,不需要面面俱到,但关键链路一定要有。很多时候我们骂“屎山代码”,其实骂的是“屎山工程”——代码乱、文档没有、上下游关系不清晰,全凭口头相传。这种项目,走一个人就少一段记忆,时间久了整个系统就像一个没有地图的城市,谁进去都会迷路。
4. 剩下6个反向操作,如何让团队“乐在其中”
4.1 技巧七:全局变量满天飞
全局变量的诱惑力在于“方便”。这一方法不想传参,直接在类里放一个静态变量,到处都能访问。但问题来了:当多个线程、多个请求同时操作这个全局变量时,状态根本不可控。线上出了问题,你看到这个全局变量的值不对,却不知道是哪一行代码改的,追查难度直线上升。
我一个好友维护过一个老系统,里面有个静态的 Map 当缓存用,没有任何并发控制,也没有过期策略。当并发量一上来,这个 Map 就出现各种灵异问题:用户A的订单信息跑到用户B的页面上去了。排查了三天,最后发现是全局 Map 被多个线程同时读写,数据串了。这种问题,光看一眼代码根本发现不了,必须靠压测和日志才能复现。正向的做法很简单:能用局部变量就用局部变量,能通过参数传递就通过参数传递,必须共享的状态要用显式的、线程安全的数据结构,并且把访问权限收拢到一个类里。
4.2 技巧八:所有功能塞进一个文件
一个文件几千行,一万行,甚至两万行——这种“巨石文件”在屎山项目里非常常见。尤其是 utils.js、helper.py、main.go 这种万能文件,什么东西都往里放,最后变成一个吞噬逻辑的黑洞。
巨石文件最大的问题在于,它把代码的“可发现性”降到了零。你想找一个函数,只能靠 IDE 的全局搜索,找到了还要判断是不是你要找的那个同名函数。更糟糕的是,所有代码都在同一个文件里,IDE 的自动补全和语法分析会变得非常吃力和卡顿,开发体验极差。
模块化拆分没有想象中那么难。先把同一业务域的功能归拢到一个目录,比如 user/、order/、payment/;再用“按层分包”的方式把通用能力沉淀到 common/ 或 shared/;最后辅以依赖规则,禁止跨层随意引用。这样代码的导航成本会大大降低,新同事上手也能快很多。
4.3 技巧九:无视代码规范,自由发挥
有人觉得代码规范是束缚,是繁文缛节。但代码规范本质上不是给机器看的规则,而是给团队所有人的“共同语言”。写代码跟写作一样,如果每个章节的格式都不统一,读者读起来就会很累。
规范问题最典型的表现就是命名风格不统一。同一个项目里,有写 user_name 的,有写 userName 的,有写 UserName 的,还有直接写 user 的。这种混乱会让代码检索变得非常低效,你搜 userName 只能搜到一半,另一半藏在 user_name 里。
现在工程化的解法已经很成熟了。JavaScript/TypeScript 项目用 ESLint + Prettier,Python 项目用 Black + Flake8,Go 项目有 gofmt,提交前自动格式化,配合 husky 之类的 git hook 在提交时自动检查。这些工具让规范执行变成自动化流水线,不需要靠人肉盯着。如果你还在靠“代码走查时人工指正命名”,那我劝你赶紧把自动检查搞起来,省下来的时间能多喝好几杯咖啡。
4.4 技巧十:滥用高级语法炫技
“一行代码解决战斗”看起来很酷,但代价可能是整条团队链的阅读成本。我甚至见过有人写嵌套三元表达式、连续 map + filter + reduce 的十层链式调用,还用了位运算来处理状态位,看起来非常炫技,实际上维护的人想骂娘。
这里不是说高级语法不能用,而是说,代码首先是写给“人”看的,其次才是给机器执行的。如果你的高级写法让团队里一半人看不懂,那不管效率提升多少,整体协作成本大概率是亏的。尤其是那种“一行流”代码,虽然执行效率可能更高,但在代码评审、bug 修复、需求变更时,别人根本没法改。
我的建议是:能用通俗写法表达清楚的逻辑,不用花哨写法;如果确实要用一些高级特性,一定要配注释解释设计意图,并在代码评审时主动给团队其他人讲明白。团队的技术成长是一点一点带出来的,不是靠写一堆没人懂的代码来证明的。
4.5 技巧十一:不写测试,编译过就算赢
“测试没有用,还会拖慢进度”——这个观念在屎山代码的养成过程中居功至伟。恰恰是那些没有测试的模块,最容易在需求变更时被改崩,因为没有人知道改动会牵连什么。
自动化测试的价值不是“证明代码能跑”(编译通过已经证明了这一点),而是“证明改动没有破坏既有功能”。没有测试,你每改一个地方都像在走钢丝。有了一份基本的单元测试和接口测试,你重构的时候才敢大胆下手,因为测试会帮你兜住回归风险。
当然我也理解,测试不是万能的,写测试也需要成本。对于屎山项目,我会建议:不要追求一步到位,先把最关键的业务链路用接口测试保护起来;每次修bug时,写一个能复现该bug的回归测试再修代码;新功能开发时,尽量顺带写几个核心场景的测试。坚持半年,你会明显感觉到代码的“安全感”上来了。
4.6 技巧十二:提交信息乱成一锅粥
提交信息这件事,很多人不重视。常见反面例子:提交信息写着“fix”、写着“update”、写着“”,连个标点都没有,更离谱的还有把临时调试代码和正式改动混在同一个提交里的。
为什么提交信息重要?因为它是代码历史的“路标”。当你在排查线上问题时,需要一条清晰的时间线索来定位“这个bug是哪次改动引入的”。如果提交信息全是 “update”、“fix”,你就只能一个一个提交地看diff,效率极低。如果提交信息写得清楚,比如 fix(order): 修复已支付订单重复退款的bug,一眼就能判断这次提交跟当前问题是不是相关。
更进一步的实践是“原子提交”:把一次改动切成多个逻辑上独立的提交,每个提交只做一件事,并且都有清晰的描述。这样回滚和 bisect 定位问题都会轻松很多。团队可以约定统一的 commit message 格式,最流行的是 Conventional Commits,格式很简单,比如 type(scope): description,type 包括 feat、fix、refactor、docs、test 等。这事不难,但收益极大。
5. 实操现场:从屎山到正道的还债流程
5.1 别急着重写,先加测试护网
很多人看到屎山代码的第一反应是“推倒重来”。这个冲动可以理解,但风险极大——屎山虽然丑,但它承载着大量没有文档化的业务规则。你贸然推倒,很容易把一些隐性的业务逻辑弄丢,损失比屎山本身还要大。
我的经验是:先测试,后重构。不管代码多烂,先把最关键的执行路径用黑盒测试覆盖住。你要知道,在重构之前,这段代码的“当前行为”就是“正确行为”,哪怕它看起来不符合软件工程的美学。测试的意义就是把这个“当前行为”捕捉下来,作为重构的基线。有了测试兜底,你才敢动手改内部结构。
具体步骤可以这样:第一步,用接口测试或端到端测试把核心业务流跑通;第二步,对关键函数补单元测试,不要纠结覆盖率,先把高频路径和容易出bug的边界条件覆盖到;第三步,开始重构,每改一步就立刻跑测试,有红了就停下来排查。
5.2 重构的最小步骤:从“看得懂”开始
重构不用一次做完,步子太大容易扯着蛋。我觉得最稳妥的方式是从增量式小步重构开始。
先挑一个最乱、但改动范围可控的模块,把它从大函数中拆出来。每次重构只做一个动作,比如:把一个魔法数字改成常量;把一个职责过多的函数拆成两个;把一段重复逻辑抽取成公共函数;把一个文件的某部分内容移动到新文件。改完立刻跑测试,确认通过后再进入下一轮。
这里有个经验技巧:重构中尽量保持“行为不变”,也就是不改变程序的输入输出。区别“重构”和“改需求”很重要,如果一边重构一边改需求,出了问题你分不清是重构引入的还是需求引起的。我建议重构和需求开发分开做,别混在一个提交里。
5.3 从团队制度上拦住屎山
个人层面的自律终究有限,要从根上拦住屎山,还得靠团队工程制度。不需要多复杂的体系,下面几件事做到了,效果就非常明显。
代码评审(Code Review)是性价比最高的拦截手段。要求每一个 MR 都必须有至少一个人review通过才能合入,评审人重点看不变量命名、函数拆分、是否复制粘贴、错误处理是否到位。这块不是走过场,而是真正提升团队整体代码质量的关键抓手。
持续集成(CI)是第二道防线。在 CI 里跑 lint、跑单测、跑构建。只要有任何一项不过,MR 就不能合入。这样就把“代码规范”和“有测试”这两件事从“靠自觉”变成了“靠机制”。
另外每隔一段时间安排一次“技术债清理周”,专门处理以往积累的问题。很多项目总觉得没时间处理技术债,但技术债跟信用卡欠款很像,你不还,利息会越滚越大,最后变成一笔根本还不起的数字。每周抽几个小时,或者每个迭代抽一天,专门做清理,长期来看收益很大。
6. 踩坑与避坑实录:真实案例里的教训
6.1 案例一:一段“运行了三年”的老代码,为什么没人敢碰
我刚入行的时候,接手过一段“运行了三年”的风控规则判断代码。这段代码有两个特点:一是缩进混乱,二是有大量的硬编码规则。历任开发都知道它有问题,但没人敢动,因为“能跑就行”。
后来业务出了个新需求,需要在现有判断逻辑里增加一条新规则。我在那段代码边上加了新的判断,基本没动原逻辑。上线后第一周就出了事故:一批本应该被拦截的订单全部通过了。
排查的时候我花了整整两天,最后发现原因其实特别狗血:那段老代码里,有一个变量被复用了三次,第一次存的是“用户历史下单次数”,第二次被改成了“用户当前请求的金额”,第三次又变成了“用户所在渠道编号”。我新加的规则读的是这个变量的最终值,恰好最终值是渠道编号,金额判断彻底失效。
这件事给我最大的教训是:变量复用是屎山的温床。你永远不知道一个变量在当前执行到哪一步的时候,被谁改成了什么东西。所以后来我再遇到类似代码,第一反应就是先把变量拆开,让每个变量的生命周期清晰可见。
6.2 案例二:复制粘贴的代价,比想象中更大
另一个印象深刻的案例,来自一个后台管理系统的权限判断逻辑。原系统判断用户是否有权限,有四处几乎一样的代码副本,分别散落在路由守卫、菜单渲染、接口拦截和页面按钮显示四个地方。
某次版本升级,产品要求“运营人员不能导出高敏感数据”。开发同事只改了菜单渲染那一处,路由守卫那处没改,结果运营人员依然可以绕过菜单,直接敲 URL 访问导出页面,数据泄露风险直接拉满。
这就是复制粘贴最典型的副作用:你以为你改了功能,其实只改了功能的一个入口,其他入口依然敞开着。如果当初这四处逻辑抽成一个 checkPermission(user, resource, action) 函数,所有入口都调用同一个函数,那改动只会在一个地方发生,出事的概率会小非常多。
6.3 避坑指南:面对屎山的三个态度
基于这些案例,我总结出面对屎山的三条态度,分享给你参考。
第一,尊重历史,但别被历史绑架。推倒重写要慎重,但也不是永远不能重写。如果一个模块已经缠满了无法解开的债务、团队里没人看得懂全部逻辑、测试覆盖为零,而且接下来还要继续大改,那可以考虑在写好“行为基线测试”的前提下,分批拆解重写。
第二,边写边清,不给后人留坑。你当前写下的每一条烂代码,都是未来的屎山砖块。下次再想“先跑通再说”的时候,多想想接手你代码的人会是什么表情。写的时候顺手抽个函数、起个像样的变量名,其实花不了几分钟,但省掉的可能是未来好几天。
第三,把代码质量当成团队资产来经营。代码不是写给自己看的,也不是写给机器看的,而是写给整个团队未来的每一个成员看的。代码质量差,团队效率就低,加班就多,人员流失就快,然后新人再接手,再变烂,这个负向飞轮会越转越快。你想停止它,唯一的办法就是在某个节点主动踩刹车。
7. 最后聊一点心里话
说了这么多,其实“写出屎山代码的12个技巧”,反过来就是“维护高质量代码的12条原则”。这些事情听起来都不复杂,难的是时刻保持警惕。我在这个行业待得越久,越觉得写代码是一个不断做取舍的过程。业务要快,质量要稳,两者冲突时,大多数人会本能地选择快。
但我想说的是,这个选择其实没有那么极端。你写一个函数时花30秒把变量名起好,在复制第三遍重复代码时停下来抽个公共函数,在提交之前跑一遍 lint 和测试,在注释里留下一句“为什么这样做”。这些动作一点都不贵,但积累下来,能让你一年后回头看自己的代码时,不至于倒吸一口凉气。
最后的最后,再分享一个我最近在用的习惯:每个月都挑一天,专门翻一翻自己一个月前写的代码,一边看一边问自己“这代码我现在还看得懂吗?如果看不懂,说明那时候欠了债”。这个习惯听起来有点自虐,但它帮我避开了很多“当时觉得没问题,后来全是坑”的陷阱。希望这个方法对你也有用。
