最近买了一本书《程序员修炼之道》,这书名起得跟葵花宝典一样😂,我一开始是拒绝的。就跟那些在畅销榜上的什么《阿弥陀佛么么哒》这种一听名字就反胃的书一样,畅销榜上的书都是好书吗?这年头花点钱就能上头条上热搜。写过代码的都知道,要想把某个东西排在前面再简单不过了,只要把数据库里这条记录的IsTop设为true就完事儿。这本书里的第18页说到:

      “永远不要低估商业主义的力量,网络搜索引擎仅仅把最热门的东西列在最前面而已,并不能说明这是你的最佳选择,而且内容提供商也可以花钱把他们的内容排到前面。书店有时候仅仅是把一本书摆在显著的位置而已,并不能说明这是一本好书,甚至不能说明这本书很流行,可能只是有人花钱把他摆在了那里”——《程序员修炼之道(第2版)》

        非常有道理,现在的网络,为了讨好、迎合和吸引用户,总是把你个人喜好的内容推送给你,慢慢的就会让你变成井底之蛙,某信、某博、某音、某手,某乎总有一款适合你,时间都会被这些快餐式的,没有什么内涵营养的内容给浪费掉,这些东西看的多了,人会感觉空虚,远没有读到一本好书有充实感。

       不过这本书我仔细看了一下,这个是20周年纪念版,表示这本书出来好多年了,而且译者看起来还很靠谱,就在某当上买了,目前看了前面几章,感觉不错,关于选书的原则我在一点读书笔记之二里说过一些。其实这类书以前也看过一些,比如《人月神话》《代码大全2》,《重构》之类的,说到《人月神话》,我想说一下,这本书大概是讲软件工程人与时间的关系,其中有一个地方说:

      “把项目的工作量定义成人月,并认为人和月可以互换,例如认为一个500人月的项目,如果100个人做5个月可以完成,而500个人做只需要一个月就可以完成,这只是一个神话(注:书名人月神话可能就是来自这里)。人类的认识需要时间周期、项目的运行也需要时间周期,这个周期相对固定,不会因为人多而变短;相反,向一个进度滞后的项目中添加人手,只会使项目更加滞后,因为需要额外的培训、交流,需要占用现有人员的时间。”——《人月神话》

      我以前在一家公司,需求很多而且变化快,时间很紧,天天加班,几个开发组的负责人跟老板说,能不能减少一些需求,调整一些优先级,把最重要的先做完,先发布一个可以使用,但是功能没有那么多的小而精的版本,后面再升级完善。老板却说,干不完招人啊,他不明白软件工程有时候不是简单的增加人手那么简单,听到只有吐血🙄,最后的结果可想而知,任何事情都要讲究科学,不能硬来,否则必然适得其反。

     这几本书,我其实都没看完,仅有一个大概的印象,以后还要拿出来翻翻。他们有个共同点,就是教方法论,简单来说就是教你写代码中的一些通用思想和方法,而不是针对某一具体的编程语言。

     看了这本书的前几章,跟之前看到的一些书里的思想其实很相似,比如什么DRY(Do not Repeat Yourself)、ETC( Easy to Change)、正交性(就是高内聚,低耦合,模块之间相关性低,往大了说就像手机app里面的沙盒,应用程序里的进程,软件开发里面的插件系统那样,模块之间依赖很少)。所以我时常在想,为什么看了这些,依然在实际编码中还是会犯错误,为什么没有成为高手。为什么那些反反复复说的道理,在实践中却一而再再而三的犯错,就跟某电影里的那句台词「听过很多道理,依然过不好这一生」一样,问题出现在哪儿。看了这本书我大概有了一些想法,可能各行各业也许都有类似的问题吧,想想大家在生活中是否也经常会犯一些常见的错误。

为什么会犯一些经常会犯的错误

      这一问题可能普遍存在,“知行合一”中,行为什么困难,一个原因是懒惰。不管是肉体的还是思想上的,可能“过好这一生”太难了,然而随随便的过,浑浑噩噩的过太容易,就像有句心灵毒鸡汤说的「努力,不一定成功;但不努力一定很舒服」,举个例子🌰,我之前给自己定了每天锻炼身体的目标,比如每天跑步至少五公里,刚开始一段时间很累,好不容易坚持了几个月好多了,但又碰上疫情,又几个月没锻炼,于是就改在室内,但是效果感觉远没有室外的好,一个原因是练着练着就开始玩手机了,因为玩手机舒服啊。拿到编程里来说,想写好代码太难了,但是随随便便弄个能交差的软件相对来说就比较容易,“又不是不能用”,“能运行就行了”,“妈的这代码写的一坨屎,我也懒得去改了,就这样吧”,“天天加班,怎么东西还有这么多,也懒得想了,怎么快怎么来,复制粘贴一下,能跑起来就行。至于代码效率,可扩展什么的以后再说吧”,“反正有测试给我兜底呢,代码看起来差不多,应该没问题,先提交吧,等测试报bug我再来改 ” 这些想法是不是经常会像幽灵一样,在你不想干的时候,在你脑海中浮现🤣。生活中是不是也是这样,总能给自己找一些活的不那么痛苦的借口。思想上或者肉体上的懒惰,虽然一时舒服,但是将来是要承担后果的,比如疫情期间没好好锻炼的我那又胖了几斤的肉😂。在编程领域,有个术语叫“技术债”,在这本书里说道:

    “虽然软件开发不受绝大多数物理法则的约束,但我们无法避免来自熵的增加的重击,熵是一个物理学术语,它定义了一个系统的“无序”的总量,不幸的是热力学法则决定了宇宙中熵会趋向最大化。当软件中的无序化增加时,程序员会说“软件在腐烂”,有些人可能会用更乐观的术语来称呼它,即“技术债”,潜台词是是他们总有一天会偿还的——恐怕不会还了(注:99%不会还😂),不过不管叫什么名字,债务和腐烂都可能失控地蔓延开

    “有很多原因会导致软件腐烂,最重要的一个似乎是项目工作中的心理状态,或者说是文化。即使是一个单人团队,你的项目的心理状态也是个非常脆弱的东西”

      我最近看ASP.NET Core MVC顺便看了一下单元测试,觉得挺好的,一个是方便调试,就是我不需要每次把整个项目编译,然后把程序启动起来,只需要就单个功能语句,单个代码逻辑进行测试就可以,如果每个小的模块,小的语句没问题,那么组合起来大概率没问题,这或许有点像系统工程,测试每一个小部分,提高每个小部分的稳定性,那么封装起来之后,大概率也没问题。二是方便以后对代码进行重构,因为没有单元测试对代码进行重构是很危险的,单元测试是一种testcase,他能保证代码的修改后所有的用例都能通过。单元测试这么好,但是写单元测试太累了,而且还需要有一定的能力,因为之前写的代码可能没那么容易进行测试,需要学习mock一些对象来隔离依赖,或者回过头来需要去修改代码让它的结构变得更合理,更容易测试。这些都需要时间成本,都需要精力,也需要学习。有一些事情,在平常没压力的情况下可能还好,但是在时间,效率受限的条件下可就不一样了,懒惰随时会想,我以后再加吧,以后再处理吧,殊不知这跟请客吃饭一样,如果某人跟你说改天请你吃饭啊,一定不要听他的鬼话🤣。

     还有一个原因是自我麻痹,这种其实是一种思想上的懒惰,但是他让自己觉得自己看起来甚至还很勤快,以前看过一本书,里面有说道:

    “工作狂往往不得要领。他们花大把大把的时间去解决问题,他们以为能靠蛮力来弥补思维上的惰性,其结果就是折腾出一堆粗糙无用的解决方案。”——《重来:更为简单有效的商业思维》

     “靠蛮力来弥补思维上的惰性” 说的太好了,我们是不是经常会遇到,一些需要自己重复去做的事情,有些完全能写个代码或者工具让计算机来处理,准确高效又不犯错误。但是“ 写代码需要消耗脑细胞啊。我留着脑细胞看看电影听听音乐它不香么,每天动动手做一些这些重复的工作也挺好的,说明我还是个勤快的人”,这种就是思想上的懒惰。大家是不是都有这种经历🤣。“每次一到放假,是不是都会带很多书回去,想着我要爱学习,带回去就会看,但是实际上大多数时候都是束之高阁,因为学习要思考,躺在家里睡觉、看电视,或者出去玩太舒服,有时候还会安慰甚至说服自己:我起码把书带回来了”,“要劳逸结合,放假了就该好好放松休息”,在《代码大全2》里说过:

     “人们容易混淆行动与进展,混淆忙碌与多产。有效编程中最重要的工作是思考,而人思考时通常不会看上去很忙。”——《代码大全2》

       有些时候把自己弄得很忙,这样可以麻痹自己很勤奋努力,看看我天天加班,认真吧,其实有可能是思维上的懒惰,不想找能够提高效率的方法。比如每次代码提交后,代码审查被指出的问题,我都会认认真真的记到OneNote里,思想上就会认为,我记下来了肯定以后就不会犯错误,就会吸取教训,我必须首先说服我自己重视问题,至于是否能修正以后不再犯,以后再说;再比如在写代码的过程中,有时候觉得别扭,那这肯定是有一些问题没想清楚,为什么要这样写或者要这样做,但是有时候就那样提交了,被问起来为什么这样又答不上来,有些问题在某一刻也问过自己,但是抱着侥幸的心里忽略了;再比如有时候拿到需求,没深刻理解就急忙写代码,思想上先给自己一个假象,我开始工作了,这样进度应该会很快就能做好交差,实际上有时候在错误的道路上走得很远,最后浪费很多时间,有时甚至需要重新开发和测试,这些都是很危险的想法。正如阿迪王(注:EdiWang,程序员,本博客系统作者)说过:

   “程序员这个职业,还是讲点道德,不要自欺欺人。偷工减料,欺上瞒下,实际就是豆腐渣工程,跟黑心棉,地沟油,涂蜡橙子一样可恶”,千万不能有“又不是不能用”,“看起来能运行就行”的危险想法,这就像你去餐馆吃饭,厨师做饭的时候心里想“看起来能吃就行” 一样。

     如果全社会各行各业都是这种“又不是不能用”,“看起来能运行就行”,“看起来能吃就行”的想法,对每个人都是危险的。

     最后一个原因是技术或者经验上的问题,比如对一些情况的准备不足、认识不充分、考虑不周全,缺乏对问题的深入理解,有些错误一而再再而三的出现,问题出现第一次的时候,很想认真去解决,但是由于认知的原因,很悲剧的只抓住了表面情况,就像八爪鱼一样,只看到了一个触角,以为这就是全部而没有深入了解原理,内部出现的问题,可能会表现出很多个外部错误。

有没有解决方法呢?

     前面说了那么多,那有没有解决方法或者突破口呢,我总结了一些解决方法,也是我自己在进行的。

     对于懒惰和自我麻痹,这两个其实是最大的问题,它不是技术上或者能力上的问题,或者说技术或者能力问题不是主导因素。 

     首先要“自我洗脑”,需要偶尔或者经常读一些“进步书籍”,比如这本书,虽然看完不一定功力能立马提升几个级别,但是起码能在自己松懈的时候提一个醒,给自己灌输一些正确的思想,提醒自己不要懒惰。回想当年考研报政治辅导班的情景,那些政治课老师讲课非常有煽动性,如其说是政治辅导,不如说是传销打鸡血,每当倦怠的时候,听一堂课就会让人觉得热血沸腾,内心小宇宙马上要爆发😂。同样这本书也有“洗脑“功效,比如:

     “如果代码都不写好,那你做这件工作的意义是什么呢?”

     “人生是你自己的,是你在拥有、经营和创造”

     “我们和很多沮丧的开发者交谈过,他们的担忧多种多样,一些人感觉自己的工作停滞不前,还有一些人认为自己的技术已经过时了,有人觉得自己没有得到应有的重视,有人觉得薪水过低,有人觉得团队已经一团糟”

      “对此,我们总是给出相同的答案。”

      “为什么你不考虑改变一下呢?” 

      “软件开发在任何职业列表中,绝对是你自己最能掌控的职业之一。我们的技能供不应求,我们的知识不限于地域,我们可以远程工作。我们收入颇丰,我们真的能做我们想做的任何事情”

      “但是,总有一些原因导致开发者拒绝改变,他们缩在那里,期盼着事情会自己变好。他们眼睁睁地看着自己的技能过时,却抱怨公司没有给予培训”

      “你有选择权!你的工作环境很糟糕?你的工作很无聊?尝试纠正它,不过不要一直试下去。正如Martin Fowler说的'你可以去改变组织,或者让自己换一个组织'”

      “如果你的技术过时了,安排时间(你自己的时间)学习一些看起来有趣的新东西。这是一种自我投资,只有为此而加班才是合适的”

     另一个是要加强“辩证法”,比如我很早就觉得世界上的喜怒哀乐都是平衡的,大喜容易大悲,现在过的多舒服,以后就可能多杯具。那为什么现在不辛苦一点,让以后能过的爽一点呢,当然这个比较玄学了(杠精会说“条条大路通罗马,但有的人就出生在罗马”,这不在讨论范围内🤣),这只是我自己的认知。现在舒服一下,急急忙忙不好好检查,代码提交了,到时候代码审查问题,会挨批评,万一没审查出来或者测试没测出来,东西给别人用了,出了大问题,造成了损失,可能就杯具了,搞不好可能要删库跑路😂。所以不能怕麻烦,立即,马上,认认真真,不放过一个细节,再检查验证一下,如果时间允许,先让自己冷静一下,明天再过来看看是否有问题,很奇怪,有时候代码当天写完,在晚上回家的路上,或者洗澡的时候,可能会觉得有一个小问题没考虑进去,亦或者有一种更好的方法。总之,如果有时间,不要着急,确保交出去的东西完善,各种case都要想清楚。在每次commit代码前,再问一下自己(在这本书里作者说一些IDE能自动修改保存时的提示语,比如可以在每次保存时,提示“当前的修改是否让代码变得更好”)。即使出了问题,起码前面是自己仔仔细细检查过各种case都想过了,而不是拍大腿感叹“妈的要是当时再认真多检查一遍就好了”。

     第三就是要提高责任意识,并不断强化 “不要写烂代码,把烂代码跟豆腐渣、地沟油、黑心棉联系起来,写烂代码就是不道德!” 的思想😂。有个“破窗理论”,这本书里也提到过:

     “在最初启发‘破窗理论’的实验中,一辆废弃的汽车完好无损地停了一个星期,但是一旦有一块玻璃被打破,这辆车在几个小时内就会被扒光并被翻个底朝天”

     “一扇破损的窗户,只要一段时间不去修理,建筑中的居民就会潜移默化地产生一种被遗弃的感觉——当权者不关心这幢建筑的感觉,然后其它的窗户也开始损坏,居民开始乱丢废物,墙上开始出现涂鸦,建筑开始出现严重的结构性损坏。在一段看上去很短的时间内,建筑的损坏程度就足以打消业主们想修好它的期望,被遗弃的感觉最终变成了现实”

     “不要搁置‘破窗’(糟糕的设计、错误的决定、低劣的代码)不去修理。每发现一个就赶紧修一个。如果没有足够的时间完全修好,那就把它钉起来,也许你可以注释掉那些糟糕的代码,显示一行‘尚未实现’的信息,或用假数据先替换一下。采取行动,预防进一步的损害发生,表明一切都在你的掌控中”

     “处于同样的原因,如果身处一个健康的团队,你们的项目代码如此完美——编写清晰、设计优良、简洁优雅,你就会倾向于格外地小心,不把他弄糟,就像那些消防员那样,即使屋内火势熊熊(截止时限、发行日期、销售演示等等),你也不想成为第一个弄乱它,造成附带损害的人。一定要告诉自己‘不要打破窗户。”

     “现在我们了解了一旦窗户开始破裂,运转良好的干净系统会迅速恶化。还有一些其他因素会导致软件腐烂,我们将在别处探讨,但与其他任何因素相比,漠视会加速腐烂的过程”。

      对于第三个问题,经验不足可能可以从以下三方面能够改善:

     首先是要靠自己多实践,多动手,多思考,见多识广,所谓的经验只不过是在各种挖坑填坑的过程中丰富起来的。

     其次可以借助一些外部的工具辅助自己,比如就在最近,我就在代码里犯了一个拼写错误,把一个label的text中的某个字写错了,直到提交后,准备截图写说明文档时才看出来。虽然领导没审查出来,虽然这完全不影响使用,但是认真的人看到了就会觉得你不认真,很马虎。拼写错误的原因是我用的某歌输入法,它干净清爽,但纠错能力或者说联想能力不强,那个字我用拼音打字出来它就是错的,没有正确联想到我要的那个字。然而我又不想用某狗输入法,虽然准确率更高,但是实在是不喜欢各种广告以及弹窗。像这种情况下,为了避免错误,我可能就要把某歌卸载了用某狗,虽然要忍受偶尔的广告弹窗,但是能减轻拼写错误的机率。另外,在写代码中,除了IDE能提供一些提示之外,还有一些插件,比如ReSharper能给你一些有益提示,这样能避免一些错误。

     最后就是锻炼心里承受能力,有些时候在平常可能没问题,但在一些条件受限的情况下,比如时间紧急、压力大、领导站在你旁边😁,再比如线上出现问题,要马上解决,不然会损失好几个亿,在这种压力情况下,要能不紧张不犯错很难。但要克服这种情况,有一点可以做的是,平时做好各种预案,要有Plan B(这些预案包括限流、熔断、备份...),这样在实战中看到一些情况,心里有底,知道这个问题产生的最坏的可能后果,然后安静平和的做好准备并及时通知上级,保护好现场后开始操作,操作之前做好备份,操作完之后做完校验,万一失败能回滚,在很大情况下能改善这种状况。

总结

     本文主要对「听过很多道理,却依然写不好代码」这一世纪难题进行了一些粗浅的分析和思考,并给出了一些不成熟的想法,以期能提高自身思想、技能水平,从而避免996,虽然稍微有点遗憾的是不能积福报。

     许多年之后,摸着自己的头发,中年程序员yy可能会回想起,他在灯下思考如何避免996进ICU,进而写出《为什么听过很多道理,却依然写不好代码?》一文的那个遥远的晚上。