读书分享:《程序员修炼之道:通向务实的最高境界》的思想经验

简介: 相较于全书众多的干货笔记,这篇文章是个别思想经验的总结,希望和大家交流。ETC;DRY不仅限于编码;维护一个项目概念列表;帮助业务方理解他想要什么;防御性编程;继承税;学会沟通;小实验

作者:爱因、方允

武侠影视剧中,江湖各路豪杰可以多年苦苦追寻一本武林秘籍,希望能够得到高人指点,从而功力突飞猛进。对于程序员来说,《程序员修炼之道》就是顶尖高手的智慧结晶,它的第一版风靡了二十年,更难能可贵的是,二十年后原作者又与时俱进重写了第二版。我们把这本书认真读了一下,相较于全书众多的干货,这篇文章只是个别思想经验的总结,希望和大家交流,如果能激发大家对原书的兴趣,自然更好。

ETC

能适应使用者的就是好的设计。对代码而言,就是要顺应变化。因此要信奉ETC原则(Easier To Change,更容易变更)——就该如此。
据我们所知,无论是什么设计原则,都是ETC的一个特例。
为什么解耦很好?因为通过隔离关注焦点,可让每一部分都容易变更——此谓ETC。
为什么单一职责原则很有用?因为一个需求变化仅体现为某个单一模块上的一个对应变化——此谓ETC。
为什么命名很重要?因为好的命名可以使代码更容易阅读,而你需要通过阅读来变更代码——此谓ETC!

我们常讲要对线上变更有敬畏之心,ETC原则是一个很重要的意识,因此我们在工作中要思考怎么样设计代码才能更方便、更高效、更不容易出错地变更。当我们针对一个任务有多个实现方案时,可以考虑把是否符合ETC原则加入到选择指标中。


比如说代码依赖某些值,这些值后面可能会变动(可能是因为业务逻辑变了,或政府出了个新政策或用户的需求变了等等),那可以把这些值放在外部,作为配置项。

DRY不仅限于编码

我们认为,想可靠地开发软件,或让开发项目更容易理解和维护,唯一的方法是遵循下面这条被称为 DRY 的原则:
在一个系统中,每一处知识都必须单一、明确、权威地表达。

DRY原则大家也很熟悉,但是如果认为DRY只是说不要复制粘贴源码,那还远远不够。DRY指的是你对知识和意图的复制,哪怕用两种不同的形式在不同的地方,它们表达的东西可能是一回事。


当我们要改变一个业务逻辑时,是否在不同的地方以不同的形式进行了变更?包括代码、文档、数据库Schema、数据结构、注释等等。如果我们的这个逻辑(或知识)在那么多地方重复表达,那么可以想到的是,用不了多久这些地方的信息就会不同步;如果你想确保它们同步,那每次变更就要花更多的时间和精力。

维护一个项目概念列表

每个项目都有自己的词汇表:对团队有特殊意义的术语。“Order”对于开发在线商店的团队来说是一回事,而对于记录宗教团体的世系的应用程序来说,意味着完全不同的另一件事。重要的是,团队中的每个人都知道这些词的意思,并始终如一地使用它们。
一种方法是鼓励大量的交流。如果每个人都参与结对编程,并且频繁地交换结对,那么术语就会渗透性地传播开来。 另一种方法是使用项目术语表,列出对团队有特殊意义的术语。这是一个非正式的文档,可以在 wiki 上创建并维护,也可以将索引卡片挂在墙上。
过一段时间,项目术语将会有自己的生命。随着每个人都熟悉了这些词汇,就能够把这些术语用作简称,准确而简洁地表达许多意思。(这正是模式语言所指。)

维护一个概念列表,可以保证团队交流的准确性,避免你说的是A,我理解成B的情况。一个项目中有不同的角色,业务方、产品、前端、后端、算法、数据,对于一起开会时经常提起的概念,大家的理解并不一定一致。举个简单的例子,比如业务方有个二分类的需求,要从一些商户中找到其中不合规的商户,模型预测结果如下图所示,但是一个人以为的准确率是(a + d) / (a + b + c + d),另一个人以为的是d / (b + d)。如果没有在项目之初明确下来大家关注指标的具体含义,那可能出现各说各的的情形。技术按照一个计算逻辑承诺并达成了准确率指标,业务方按照另一个逻辑计算后发现准确率远远没达到,这会给团队合作带来障碍。

image.png

维护一个项目概念列表还有一个好处,就是在制定列表的同时会推敲这个概念的说法是否合适。举一个场景,政府规定购买某些药必须有48小时内阴性的核酸检测结果,要用模型识别订单是否需要拦截。有人把”识别通过“说成”识别成功“,把”识别拦截“说成是”识别失败“,这样就很容易把失败率和模型的识别错误率当作是一回事(因为”失败“和”错误“这两个词太相似了)。其实这是两个完全无关的指标,如果短时间内有10个订单全部拦截了,而且用户确实不符合防疫规定,真实的识别错误率是0,但是用失败称呼拦截很容易以为模型识别全错了。


概念是“思维的细胞”,维护一个概念列表不仅有利于项目成员内部的合作,也有利于给上级或其他人汇报时听众能更容易准确理解你的意思。因为项目成员有更多的背景知识,用词不准确不一定会引起歧义,大家都能理解,但是非项目成员不一定都能准确理解。

帮助业务方理解他想要什么

新手开发人员经常犯的错误是,把这种对需求的声明照单全收,然后实现对应方案。 根据我们的经验,最初对需求的声明,往往并非绝对化的要求。客户可能没有意识到这一点,但一定希望你能一起去探索。 下面给出一个简单的例子。你在一家出版纸质书和电子书的公司工作。你接到一个新的需求:所有 50 美元以上的订单都应该免运费。停一秒钟,把自己带入这个场景。首先想到的是什么?你有大把机会发现问题: 1、50 美元含税吗? 2、50 美元算没算上本应支付的运费? 3、50 美元必须全是用来买纸质书吗?还是允许在同一订单中有部分电子书? 4、包邮指的是怎样的服务?是加急还是平邮? 5、如果是国际订单如何处理? 6、未来会经常改变 50 美元这个限制吗? 这就是我们所做的。当某些事情看起来很简单的时候,我们却会去寻找那些边缘情况,并就其不胜其烦地问人。
很可能客户已经想到了其中的一些问题,并假定实现将以某种方式工作。问这类问题只是把信息明确下来。但有些问题可能客户之前并没有考虑到。这就是事情变得有趣之处,也能让好的开发人员从此处事老练。

上面的例子是通过帮助业务方理解他的需求,从而让问题变复杂了,那是因为问题本身就复杂,业务方最初没想清楚。你如果按照最简单的假定去做,可能会出现资损、客诉等各种问题。


有些场景下,帮助业务方理解他想要什么会让问题变得简单比如在某些合规审核场景下,业务方需要你从某种证照图片中提取法人姓名,你在OCR识别之后准备训练一个NER模型用来识别姓名,需要的注意点很多,比如这是全国的商户,少数民族的姓名通常的NER模型识别不出来或错误率高(针对性训练的话又需要标注数据了)。但仔细想一下,业务方想要的真的是这个姓名吗?询问之后发现,业务方想要的是图片中的姓名是否和已知的姓名一致。问题突然变简单了!你只需要判断真实姓名是否存在于OCR识别的字符串中即可。通过准确理解业务方的目的,你更快更好地完成了任务。

防御性编程

每个人都觉得,地球上只有自己一个好司机。全世界都在闯红灯、实线变道、不打灯就转弯、开车发短信,总之都不符合我们的标准。所以我们需要防御性驾驶。在麻烦发生之前就做好准备,预料到意料之外的事情,永远不要把自己置于无法自拔的境地。
与编程类比,上述理论也明显成立。我们不断地与他人的代码交互,代码可能不符合我们的高标准,或需要处理可能有效也可能无效的输入。所以我们被教导要防御式编程——有任何疑问,都要去验证我们得到的一切信息;使用断言来检测错误数据,不信任任何可能来自潜在攻击者或有恶意者的数据;做一致性检查,对数据库的列设置约束——做完这些,我们通常就会自我感觉良好。
务实的程序员则更进一步,他们连自己也不相信。既然没人能写出完美的代码,那么也包括自己在内。务实的程序员会为自己的错误建立防御机制。我们将在契约式设计中描述第一个防御措施:客户和供应商必须就权利和责任达成共识。

当我们和他人的代码交互,比如调用他人的接口时,最好要考虑到正常情况之外的一些corner case,它们可能非常罕见,但是最好不要在出现时导致故障的发生。

继承税

我刚开始工作时,看到团队的一大堆代码,真的是头皮发麻,遇到过代码上一次变更是10年前(非阿里),结果团队待得最久的成员才待了7年,也没啥文档,没人知道咋弄。只能硬看。这就是文档的重要性。


记得有一次,我发现某个地方有问题,理解上应该是如果errorMsg非空,那就打印errorMsg,结果代码是如果errorMsg为空,那就打印errorMsg。但是问了团队同事,他说,也不一定,都不知道写代码的人想干嘛,建议别动。我本来想改掉,听他这么说,心想还是算了,和我这个需求无关,到时候改出问题了咋办。做一些我认为正确但是有风险,做好了也收益不大的事情,还是需要勇气的。而当时在试用期的我,并没有这份勇气,这真是个非常现实的问题。屎山也许就是这么来的。


本书提了一些方案,比如少用继承,多用interface,使用配置等等。同时也提到说,不要因为懒,就放弃做决策,把分歧都做成配置。也不要做的太过,把所有东西都做成配置,会导致修改和维护起来非常难和低效。

学会沟通

有些程序员喜欢一整天都待在电脑前,不说一句话。但线上或线下的开会、沟通、分享等也是不可或缺的。这本书强调了沟通的重要性。一个是做的事情本身,一个是传达和表达出来,两个都很重要。如果心里有抗拒,那就把中文/英文当作另一门编程语言,去掌握和用好它。

小实验

读这本书的时候,我们组一位同学做了一个很有意思的实验,组会时大家也一起进行了讨论,这里分享给大家。请看下面这段话:

“不要把问题归咎于别人或其他什么事情上,也不要寻找借口。不要把所有问题都归咎于供应商、编程语言、管理或是同事。这些因素都可能是问题的一部分。它们的确会对解决方案造成影响,但不是给你的借口。”

假设是你的主管对你说如上这番话,你觉得这是在pua你吗,还是确实讲的很有道理不是pua你?大家心里也许有一个答案了。

把这个问题发到脉脉上,让大家投票,近500人参与投票,统计下来有60%的人认为这是PUA。

image.png

我们可以把这个问题再扩展一下, 如果你老板和你在平时轻松的状态下和你讲这番话,和打绩效的时候讲这番话,同样的话你的感受是否会不一样?如果是不在同公司的好友讲的呢?如果是你敬重的前辈呢?

而如果,这番话来自本书《The Pragmatic Programmer 程序员修炼之道》呢?

说明 :

1. 本身不是话术的问题,而是谁说出来的问题,场景问题;

2. 你对他是否“信任”很重要, 如果信任就不觉得是PUA,不信任就觉得是PUA;

3. 是否有利益关系,比如外部大佬跟你没有利益关系。

如果要总结的话,就是我们心里知道说话人的动机到底是不是真的为我好,在这个前提下,对同一番话的解读也会不同。

其实这些思考和讨论都不局限于这本书本身了,感觉包含了对于生活和人生的思考。这也许是组队读书的好处之一。

最后,这本书只读一遍是不够的,需要反复阅读并在实践中增进理解。

相关文章
|
22天前
|
程序员
代码与生活:技术感悟中的哲理
【10月更文挑战第20天】 在编程的世界里,我们不仅仅是在编写代码,更是在塑造一种生活方式。本文将探讨如何将编程思维应用到日常生活中,以及这种思维方式如何帮助我们更好地理解世界和自己。通过具体的例子和深入的分析,我们将看到,编程不仅仅是一种技能,更是一种生活哲学。
30 0
|
2月前
|
JavaScript 前端开发 Java
技术探索之旅:从迷茫到顿悟
本文记录了作者在技术领域的探索历程,从初入行的迷茫、尝试新领域的勇气,到不断学习和提升后的顿悟。通过个人经历,展现了技术成长的曲折与收获。
|
2月前
|
机器学习/深度学习 人工智能 开发者
技术之道:从迷茫到明晰的自我探索
在技术的海洋里,每位开发者都是在不断试错和成长的旅程中。本文通过个人经历,探讨了如何从初入职场的迷茫中找到自己的技术方向,并分享了持续学习和实践的重要性。
40 4
|
2月前
|
机器学习/深度学习 人工智能 算法
编程之路上的启示与反思
【9月更文挑战第16天】在编程的海洋中,我们每个人都是一艘航行的船。有时顺风顺水,有时逆流而上。本文将分享一段个人的技术成长之旅,从初心到迷茫,再到自我发现,最终找到属于自己的航道。通过这段旅程的反思,我们将探讨如何在技术的洪流中保持初心,不断进步,并对未来做出明智的选择。
|
3月前
|
算法
编程之旅:从代码到思维的蜕变
【8月更文挑战第20天】在数字化浪潮中,编程不仅是技术的实践,更是思维的锻炼。本文探讨了编程如何影响我们的思考方式,并分享了作者个人的技术感悟和成长经历。通过深入分析编程带来的逻辑思维、问题解决能力和持续学习的重要性,文章揭示了编程与日常生活之间的紧密联系,鼓励读者以更加开放和创新的心态面对挑战。
|
3月前
掌握这 3 个诀窍,你也能成为一个技术大牛
掌握这 3 个诀窍,你也能成为一个技术大牛
|
程序员
程序员成长第四篇:程序员的职业天花板
程序员成长第四篇:程序员的职业天花板
141 0
|
监控 移动中间件 安全
关于程序员的职业操守,从《匠艺整洁之道》谈起
《匠艺整洁之道》是鲍勃大叔的整洁系列新书。这本书主要从纪律、标准、操守三个方面阐述了软件从业者应该如何要求自己,提升研发质量、效率、道德水准,本文主要围绕《匠艺整洁之道》的第三部分 -- 操守,聊一聊我们程序员该如何自我约束、自我提升。
515 1
关于程序员的职业操守,从《匠艺整洁之道》谈起
|
测试技术 程序员
风雨20年:我所积累的20条编程经验【转】
风雨20年:我所积累的20条编程经验Posted by zhaoxingyun on 十一月 13th, 2010 | Comments off原文作者乔纳森·丹尼可(Jonathan Danylko)是一位自由职业的web架构师和程序员,编程经验已超过20年,涉足领域有电子商务、生物技术、房地产、医疗、保险和公用事业。
828 1
|
程序员
【抛砖引玉】“技术顾问” —— 老程序员的一个出路。
     以前总可以看到一些讨论,程序员30岁以后怎么办?35岁以后怎么办?当然有一些人,不管大多的年龄,都可以继续编程。但是对于大多数人年龄大了,各方面的压力也就更大了。年龄大了就面临上有老下有小的处境,简单地说父母、爷爷奶奶病了要去照顾;孩子病了也要照顾;老婆病了也要照顾;自己病了还得自己照顾自己。
1326 0