《程序员修炼之道》读书笔记

前段时间读了《程序员修炼之道》,读之前以为这本书估计基本是在重复《Unix编程艺术》,《编程珠玑》,《重构》等等里面的各种思想,结果我发现我错了,这本书完全不是那么一回事。其他的书说的只是代码或工程的哲学,而这本书除了讲述工程方面的哲学之外,还在讲述程序员应该如何规划自己的人生。看完之后确实是受益匪浅,越看到后面,越觉得这世间的万事万物其实是相通的。事物的表现或许不同,但是背后的规律却是如此的相似。

1. 修行啊,属于程序员的修行

不知道大家有没有这样的感觉,时间总是那么的不够用,想要学的东西太多,学习的速度太慢,有时候还不一定有激情。我们没有龙珠里面的时间与精神的小屋,也没有岛国的时间停止器,修行是一辈子的事情,而且有时候没有想象中的那么简单。

1.1. 重中之重:注重实效

这四个字是书中最关键的几个字,在书中频繁出现,仿佛作者写这本书就只是想将这四个字潜移默化给大家一样。方法和过程都因人而异,但是只有注重实效是永远不变的。

1.2. 投资并管理好你的知识

曾经有一个同事F对我说:“一个技术人员最不可或缺的是什么?技术。如果没有技术的,那其他的东西,如人际,都没有意义,因为那些都只是加分而已。”。这句话我觉得说的很对。所以,一个技术人员在修炼自己之前,首先需要有一个意识:你的知识就是你的资产,学会如何经营他。在这本书里面,作者给出了如下几个建议:

  • 定期评估已有资产,并进行投资
    定期的回顾你已经学习到的东西,并找出其中你遗忘的或者你想学的,以后会有用的内容,进行学习。说不定,以后这些知识就真的能够帮到你。

    书中推荐的几个目标是:

    • 每年学习一个新的语言,从新语言中学习新的解决问题的思想。
    • 每季度看完一本技术书籍,专业领域当然不能拉下。
    • 当然也要看看非技术书籍,和你打交道的他们都是人,不要什么时候都纯技术。
  • 多元化
    多元化投资是长期成功的关键,谁也不知道以后的市场会有怎样的突变,偶尔去看看别的方面,对自己是有好处的。也许你现在很熟悉C++了,那么尝试着去看看动态语言吧。如果你已经做了两三年Windows上的开发了,那么去看看Unix吧。分散的投资到最后总会有一处会收到回报。

    注意,这并不是让大家乱学知识,什么都不深,看着这段时间语言排行榜一变,就一股脑钻进去了。多元化的投资的前提是,你已经有一个擅长的专长或领域了。

  • 平衡风险和回报
    学习和投资一样,有风险有回报,管理好学习的风险,不要学了很久,也许带来不了任何回报,开阔眼界是好的,但是也要注意,你的时间是有限的。不要瞎忙活。

  • 主动联系大神们,向他们学习
    互联网带来的最大的好处就是将所有人和事物的关系都拉近了,主动的寻找你这个方向的大神,并向他们请教,也许他们不会马上回复你,组织好自己的问题,耐心一点,礼貌一点,总会有结果的。

1.3. 交流和沟通

虽然我们每天处理的都是代码,但是无可避免的和我们打交道的还是人,所以人和人之间的沟通其实是很重要的。在书中给了几点关于建议:

  • 知道你想要说什么,了解你的听众并让文档美观
    在和其他人交流之前,记得提前整理好自己的想要说明的问题,并且了解你的听众,不然就容易失去重点,有一茬没一茬,最后你和对方都不知道想聊的内容是什么。在整理谈话内容的时候,有一些简单的可供参考的标准,书中称为WISDOM离合诗:

    • 你想让他们学到什么?
    • 他们对你讲的什么感兴趣?
    • 他们有多富有经验?
    • 他们想要多少细节?
    • 你想要让谁拥有这些信息?
    • 你如何组是他们听你说话?
  • 一些沟通的技巧
    沟通是需要技巧的,书中说了如下几种建议,他们实在是太实在了,所以基本都不用展开赘述了,大家肯定也能明白其中的意思。

    • 选择一个好的时机开启话题
    • 让听众参与
    • 做倾听者
    • 回复他人

1.4. 警惕无处不在的马太效应

在一个项目中,由于版本压力,时间不足等等的问题,有些较为复杂的问题又需要尽快的解决,于是山寨的方法就出现了,打破框架的限制,打破软件的分层,简单粗暴的解决掉这个问题。一扇破窗就形成了,慢慢的破窗越积越多,只到某天出现了这样一段对话:
—— 你觉得我们现在项目存在什么问题吗?
—— 我觉得我们现在项目有点XX问题,blah,blah……另外,还有一些这样的问题,blah,blah……
—— 那你觉得这个会对我们影响很大么?/ 那你觉得我们有必要现在停下来调整一下么?

这个时候迫于KPI等等的压力,不是每个团队都会停下来进行调整,要是完不成任务怎么办呢?于是答案就出来了:
—— 我觉得其实还好,后期重构就好,现在还是版本比较重要。 /  我觉得其实还好,敏捷开发嘛,先把功能出来,后面再慢慢的完善。

扪心自问一下,当你写出你自己都觉得恶心的,难以理解的代码,后期还会有谁想来接手这一摊子事情,来重构这块代码的基本只有你自己。而你自己肯定还会被KPI继续压着,做更多别的事情,直到整个架构崩坏。

“凡有的,还要加给他叫他多余;没有的,连他所有的也要夺过来。”

坏的代码必然越来越坏,不要抱有对其会突然变好的妄想,出现问题,一定要想一想是不是要停下来去重构一下。在《重构》一书中有一句话我觉得很好:一而再,再而三,三而重构。

相对的,好的代码将更容易保持其好的状态,就如同你去上流的地方吃饭一样,悠扬的音乐一响起来,你吃饭的速度自然就慢下来了。而如果是在食堂吃饭……

也许你会奇怪,这难道不是应该放在之后的如何完成项目中么?问题就在于这还仅仅是马太效应的冰山一角,可怕的事情即将来临。

  • 出了问题,之后重构吧。再出了问题,再之后重构吧。最后永不重构。
  • 今天版本忙,不去运动了吧。第二周又重复第一周。最后永不运动。
  • 写博客,今天好累啊,明天写吧。明天好累啊,后天写吧。最后永不写博。
  • 今年的推广指标/投入资金用不完,明年就会变少。今年的用完了,还吵着说不够,明年就会更多。面对这种情况,有一种粗暴的解决方案
  • 还有一个好玩的:今天任务做不完,加班吧。明天任务做不完,加班吧。最后天天加班。(总是有新的任务来,美名:能者多劳)

到现在为止,你中了几枪?所以不要像温水煮青蛙一样,习惯一个环境,就不去改变,直到最后被你熟悉的环境所毁灭。

2. 如何完成项目

当然,除了对人生规划的建议以外,这本书里面也有不少对项目和编码的建议。有一些在其他的书中也有提及,比如真理的唯一性,测试的重要性,等等等等,但是有几个部分,作者可谓是不厌其烦,一再提及。

2.1. 正交性,DRY原则和解耦合

正交性是一个相当重要的概念,它在《Unix编程艺术》这本书中被特意提了出来,当作是重构的本质。但是其实这个概念本身非常简单,就是修改一个模块,不会对其他模块产生影响。说的直白一点就是一个模块只做一件事情,不要让模块承担过多的工作。不然修改了一个功能,就会很容易对另外一个功能产生影响。随着项目越来越大,到后期如果碰到问题,则很难找到合适的解决方法,而且大家会越来越不敢修改代码,因为谁也不知道修改了这块代码会导致哪些地方出问题。相反的,遵守正交性可以为项目带来的很多的好处:

  • 促进模块的复用
    一个模块越简单,那么他就越容易被理解和复用,正交的代码就是这样。这个思想被广泛的用于Unix的环境中,导致了现在Unix的工具链+管道的开发习惯。项目中也是一样,小巧锐利的工具,大家都喜欢。想想,平时在工作之中,是不是有同事常问你:“哥们,我们的代码里面有用来干XX事情的模块么?”。

  • 使模块变得更好修改
    这个结论似乎是那么的好理解,你是愿意在一滩逻辑泥沼中摸索它对各个模块的影响呢,还是愿意修改影响显而易见的代码呢?

  • 使模块易于测试
    相比无所不能的模块,一个只干一件事情的模块肯定更容易理解,并且具有更少的依赖,所以不会担心当需要为这个模块编写白盒测试时,要写一大堆的测试用例才能达到一定的效果,或者是要调整半天工程依赖才能进行正常的编译。

正交性有一个好朋友,那就是常被提及的DRY原则——Don’t Repeat Yourself,在《Unix编程艺术》中又被称为SPOT原则——真理的单点性。说的直白一点就是:只有一个模块做这一件事情。遵守DRY原则带来的好处就是可以避免散弹式修改(Shotgun Surgery),而最常见的场景就是魔数,在《重构》一书中还专门探讨了如何来解决这种代码的坏味道,其实本质上就是DRY原则。

但是在想要实现正交性,却不是那么的容易。如何来判断一段代码是不是正交的呢?如果发现其不是正交的,如何将其修改为正交的实现呢?

这个问题在书中给了一个简单易用的答案——解耦合。这个方法说起来似乎还是有点飘渺,因为什么样的代码才算是耦合严重呢?书中给出了一个方便快捷的判断标准:得莫忒尔法则。

函数的得莫忒耳法则规定,某个对象的任何方法都应该只调用属于以下情形的方法。

  • 它自身
  • 传入该方法的任何参数
  • 他创建的任何对象
  • 任何直接持有的组件对象

通过这个法则编写的代码,一般都会更好的实践上面提到的两个原则,从而实现错误更少的代码。因为如果n个对象都互相了解,那么一个对象的改动就可能导致其他n - 1个对象都需要改动。当然,如果一直遵循这个法则,可能会出现大量的包装方法,从而导致效率的损耗。所以,如果出现了效率问题,那么就应该要逆着这个法则来做优化。法则并不是死的,还是要根据实际情况来做决定,优化也不要太早,盲目的优化必然带来更加复杂的实现和难以维护的代码。

2.2. 自动化

懒惰是人类的天性,谁也不想自己一年工作时间,一年半的工作经验,面对经常重复的工作,自动化就是对付它们的一件大杀器。
automation

面对自动化,你肯定不会陌生。自动化的好处是不言而喻的,在项目中,我们利用它来帮助我们跟进开发进度并尽早发现问题,如:每天都进行的dailybuild,每天都跑的白盒测试和黑盒测试,每天根据新的代码生成新的接口文档。这些事情大家肯定接触的不少,所以这里我想提的是自动化的反面。

书中使用了无所不在来描述自动化这件事情,甚至提出了一切都要自动化的概念,当然我相信这个的针对可重复的事情而言的,如流程等等。但是不要忘记了,上面这条曲线还是有手动来的更快捷的部分。也不要想着将一件事情自动化了就是上流的表现,因为有可能这件事情你将永远都不会重复它,这样你付出的将比你得到的要多的多,所以要谨记第一原则还是注重实效。还是那句话,一而再,再而三,三而重构。同样一件重复的事情,不要让自己做三遍,如果做了三遍,那么就把他自动化吧,因为它极有可能是你要经常重复的工作。

2.3. 弄清楚自己在做什么,原型还是初号机

很多项目开始的时候,或者很多特性在规划的时候,第一步就是需求分析。但是有的时候,就连开发团队自己都弄不清楚这个特性到底是要干什么。他们当然弄不清楚,因为他们不是用户,真正的需求只有用户才知道。不过可惜的是,你不一定有机会能和用户大量的沟通,用户也不一定能把他的想法表述的那么真真切切,没有歧义。这样在开发的时候就会碰到一个问题:我现在写的代码,后面到底还有没有用呢?
programmers-06-need

这个问题相信不少人都遇见过,而我遇到的最通常的解决方法是,写一个非常复杂的模块,可以适应各种环境,产生各种变化,用户要是不是要的现在这种,稍稍配置一下,它就变成另外一种。这种程序开发和维护成本都很高,而且更加杯具的事情是:计划赶不上变化。也许收到的用户反馈或者产品建议是:完全用另外一种方法来实现吧。笔者就遇到过这样的问题,那感觉,悲催的。而笔者的一位同事则更加的惨,整整半年都泡在来回折腾的需求里面,需求不是你想改,想改就能改,现在又要拍脑袋让我改回来。碰到这种情况,是个人都想早日的解脱出来,可惜程序员们都有着不同程度的代码洁癖,这点着实要命。说了这么多废话,其实就是想说,一定要想清楚现在你做的东西到底是什么,只是一个原型给大家尝尝鲜,过过瘾呢?还是一个真正的产品,最终要发布出去。这完全是两码事情。

书中针对这种需求不明的开发,提出了两种解决方案:原型和曳光弹。

  • 原型
    原型开发有一个非常重要的前提:你写的这段代码,将一定会被遗弃!如果不满足这个条件,请不要使用这种方法,否则会出现很悲惨的事情。既然是一个原型,那么我们可以考虑使用更加简单的方法来实现他。比如C#或者java?或者使用一些项目不建议使用的库来简化开发?甚至直接用黑板,将你的想法画出来?这样你不但能很快让大家看到一个基本的效果,还能减少不少的开发量。在原型中也不要担心效率问题,实现的优不优雅等等因素,因为请谨记:你的这段代码将被丢弃。所以请放心大胆的在上面实验你的各种想法吧。

  • 曳光弹
    一旦使用原型找到合适的方向了之后,我们就可以将原型抛弃而转入曳光弹的开发了,这也是这两种开发模式本质的区别。在曳光弹开发时,你可以为产品或特性想一个较为合适的实现了,搭建一个足已支撑项目的框架,然后开始慢慢进入正常的产品开发迭代:完成一定的功能,交付使用,根据反馈再继续修改这部分功能……直到最终成型并交付。

2.4. 让别人有兴趣加入你

程序员的工作很多时候是属于劳动力密集型的,我这么说也许你会不开心,但是姑且先听我解释。每个开发人员的开发能力是基本恒定的,比如:平均每天提交代码的数量。一般来说这个数值会维持在400左右,当然这个数据每个人会不同,而且还和项目阶段相关,我们这里不详细讨论。而一个项目,有时候会多达几十万行代码,也就是说,一个项目需要几个人年。现在世界变化这么快,几年过去,这个世界已然换了一个模样了。所以你的工作一定会需要同伴来帮忙,而一定程度上同伴越多,开发速度就会越快。所以这也就是为什么一个开发团队总是想招人的原因了,想快,那就得招人,没办法。

(这里需要注明一下:平均每日提交代码数,这只是反应一个人开发能力的很小的一方面,有可能有个人平均每天都提交2k行,但是却各种重复,所以请不要把这个看成衡量程序员能力的标准。)

所以,让别人有兴趣加入你的工作很重要。

这里其实是书中介绍的一个小的Trick了,听上去很腹黑,但是它却十分管用。那就是:在项目中,需要不断的给大家新鲜的东西,去刺激大家来支持你。也许这个功能能加一个这样的特性,效果会好很多,但是我需要更多的人/我需要时间/我需要更多来自后台的支持,等等。但是说实话这招能有多大的用,就只能看个人的忽悠能力了。你可以将它吹的天花乱坠,但是事情的关键,也是难点是:你要不停的给其他人新鲜感,不要一下把大招全放完了。

2.5. 文本化的魅力

文本化已经有太多太多的书提到过了,看过《Unix编程艺术》的朋友肯定影响非常深刻。文本化,DDD(Data Driven Development),blah…blah…blah…,耳朵都起茧了。但是和《Unix编程艺术》一样,这本书花费了整整一个大章——基本工具,来阐述纯文本带来的好处,因为他实在太有好处了。

纯文本带来的好处有三个:易懂,易修改和版本控制。前两个特性导致了DDD的产生。而最后一个特性就霸气了,所有需要长时间来维护的,会多次改动的工作,都可以使用到版本控制。版本控制可以使得整个文档的修改易于追踪,而相比起来二进制文件就是无限的悲催了,根据这个你想想你的身上有没有可以利用版本控制来管理的东西呢?

 

 

……………… 让我们为思考留出一点时间 ………………

 

 

现在让我们来简单的列举几样吧:

3. 结语

看完这本书之后,我感觉,现在的我,感受的东西实在肤浅,如果再过个两年回头看这本书,肯定又会感悟到不同的东西。总的来说这本书确实相当不错,如果各位看到这,能被我激起一些兴趣去读这本书,就太好了。

现在回头再看这本书才发现,这还真是一本现实的书啊。