读《程序员修炼之道——从小工到专家》(The Pragmatic Programmer: From Journeyman to Master)

来源:互联网 发布:12306网络购票暂停 编辑:程序博客网 时间:2024/06/16 03:26

花了几天时间略读完了《程序员修炼之道——从小工到专家》(The Pragmatic Programmer: From Journeyman to Master)。总体感觉就像是一位多年开发经验的软件工程师,在身旁谆谆教导。其中的大部分内容,要在工作中不断实践,才能有深刻的体会。也许是自身层次原因,其中一部分内容不是很能理解,也许在多年之后,第二次读这本书的时候,会有更加深刻的认识和理解吧。

下面是关于知识点的总结:

1、关心你的技艺(Care About Your Work)

如果你不在乎能否漂亮地开发出软件,你又为何要耗费生命去开发软件呢?

PS:态度很重要,如果并不喜欢软件开发,花时间去开发软件,无异于浪费生命。

 

2、思考!你的工作(Think! About Your Work)

关闭自动驾驶仪,接管操作。不断地批评和评估你的工作。

PS:自己每次所写出来的代码,自己是否能够理解,是否去记录那些当时没能理解的代码,现在再去看那些代码,能否理解。

 

3、提供各种选择,不要找蹩脚的借口(Provide Options,Don’t Make Lame Excuse)

要提供各种选择,而不是找借口。不要说事情做不到,说明能够做什么。

PS:写好的代码要记得备份,不要为自己做不到某件事情找借口,想想现如今自己能够为这件事做些什么。

 

4、不要容忍破窗户(Don’t Live with Broken Windows)

当你看到糟糕的设计、错误的决策和糟糕的代码时,修正它们。

PS:有什么问题必须立即解决,不要拖,拖到后面,小问题也会变成大问题的。

 

5、做变化的催化剂(Be a Catalyst for Change)

你不能强迫人们改变。相反,要向他们展示未来可能会怎样,并帮助他们参与对未来的创造。

PS:当某件事情悬而不定时,可以通过对事情的理解,做出相应的原始模型(原型),引诱团队里的其他成员,对你这个原型进行扩展。

 

6、记住大图景(Remember the Big Picture)

不要太过专注于细节,以致于忘了查看你周围正在发生什么。

PS:先整体在细节,先抽象再具体并且随时观察外界的变化。

 

7、使质量成为需求问题(Make Quality a Requirements Issue)

让你的用户参与确定项目真正的质量需求。

PS:有时候并不需要做到最完美,如果做到最完美要用户等几年,那用户宁愿用那些几个月就能做出,并在不断改进的毛边产品。

 

8、定期为你的只是资产投资(Invest Regularly in Your Knowledge Portfolio)

让学习成为习惯。

PS:时代进步,IT业也呈现爆发式发展,也许今年用的技术,三五年以后就会被淘汰,这时候就需要做到及时充电,更新知识库存。

 

9、批判地分析你读到的和听到的(Critically Analyze What You Read and Hear)

不要被供应商、媒体炒作、或教条左右。要依照你自己的看法和你的项目的情况去对信息今进行分析。

PS:不要完全相信别人的说法,即使是专家说的也不一定完全正确,通过结合自己的思想,参考别人的意见,做出当前情况下尽可能最好的判断。

 

10、你说什么和你怎么说同样重要(It's Both What You Say and the Way You Say It)

如果你不能有效地向他人传达你的了不起的想法,这些想法就毫无用处。

PS:不仅要成为技术上的专家,还要成为社交上的能手。


11、不要重复你自己(DRY - Don’t Repeat Yourself)

系统中的每一项知识都必须具有单一、无歧义、权威的表示。

PS:大量的重复不仅会浪费空间,也会造成效率低下问题。

 

12、让复用变得容易(Make It Easy to Reuse)

如果复用很容易,人们就会去复用。创造一个支持复用的环境。

PS:代码的复用,无疑会让我们效率更高,但是为了复用,花大量的时间在琢磨怎么去复用上面就得不偿失了。所以,尽量在初次开发时,就考虑代码的复用问题。

 

13、消除无关事物之间的影响(Eliminate Effects Between Unrelated Things)

设计自足、独立。并具有单一、良好定义的目的的组件。

PS:如果有n个文件,在最坏的情况下,修改一个文件的源代码,同时也要修改其余n-1个文件的源代码。

 

14、不存在最终决策(There Are No Final Decisions)

没有决策是浇灌在石头上的。相反,要把每项决策都视为是写在沙滩上的,并为变化做好计划。

PS:考虑到随时变化的环境,要在写代码之前就考虑清楚,这些代码能不能在决策发生变化后还能使用。或者是花费很小的代价就能适应于变化。

 

15、用曳光弹找到目标(Use Tracer Bullets to Find the Target)

曳光弹能通过试验各种事物并检查它们离目标有多远来让你追踪目标。

PS:曳光弹法表示的是建立一个可用但是功能不全的版本来判别所做设计是否符合客户需要,和原型这种用完即扔的方法不同,曳光弹法的代码都是后期扩展所必需的。


16、为了学习而制作原型(Prototype to Learn)

原型制作是一种学习经验。其价值并不在于所产生的代码,而在于所学到的经验教训。

PS:原型也是探索新事物的一种方法,通过建立原型,可以快速的了解当前事物的各种特性,虽然原型的代码用完即扔,但是所用的思想是需要保存的。

 

17、靠近问题领域编程(Program Close to the Problem domain)

用你的用户的语言进行设计和编码。

PS:设计不同领域的软件时,可能有其领域的规范和业务逻辑,通过熟悉该领域,能写出更符合业务逻辑的代码。

 

18、估算,以避免发生意外(Estimate to Avoid Surprises)

在着手之前先进行估算。你将提前发现潜在的问题。

PS:估算不仅仅是对预算的估量,也包括了做软件各个方面的考虑,比如:时间,质量,范围,干系人之类的等等。

 

19、通过代码对进度表进行迭代(Iterate the Schedule with the Code)

用你在进行实现时获得的经验提炼项目的时间标度。

PS:进度往往是由代码的完成度来进行决定的,代码完成度高,则进度离完成不远了,相反,如果某一时段内,代码的平均完成率低于预计水平,那么,实际进度可能就会慢于计划进度了。

 

20、用纯文本保存知识(Keep Knowledge in Plain Text)

纯文本不会过时。它能够帮助你有效利用你的工作,并简化调试和测试。

PS:纯文本是有一定意义的文字,当我们将知识保存至纯文本文件中时,并通过一定的形式进行组织,这样它就永远有意义的保存下来了,如果以后需要,就能直接派上用场。


21、利用命令shell的力量(Use the Power of Command Shells)

当图形用户界面无能为力时使用shell

PSshell,dos这种命令行的威力是巨大的,也许图形界面需要很多步骤才能实现的功能,通过命令行短短一两行代码就能实现。

 

22、用好一种编辑器(Use a Single Editor Well)

编辑器应该是你的手的延伸;确保你的编辑器是可配置、可扩展和可编程的。

PS:基本上所有的计算机语言都是能够用文本编辑器来进行编写代码的。虽然现在开发都是用IDE,但是IDE会自动给你做很多细节的事,这很好,但是请不要忘记了,如果你初学一门语言就用IDE的话,会丢失很多该语言的细节信息。同时,要学会一种编辑器的各种使用方法,常用的编辑器有EditPlusSublime Text等等。

 

23、总是使用源码控制(Always Use Source Code Control)

源码控制是你的工作的时间机器——你能够回到过去。

PS:学会使用版本控制软件(过段时间了解下)

 

24、要修正问题,而不是发出指责(Fix the Problem, Not the Blame)

bug是你的过错还是别人的过错,并不是真的很有关系——它仍然是你的问题,它仍然需要修正。

PS:当有bug需要修复时,不要总想着去指责别人,或者是怎么去逃避指责,这都不重要,重要的是什么时候能将这个bug修复。

 

25、不要恐慌(Don’t Panic When Debuging)

做一次深呼吸,思考什么可能是bug的原因。

PS:寻找bug一直是一件很头疼的事,也许我们因为时间问题,急于修复bug,但是不要恐慌,不要陷入混乱,这样只会使你的效率更低,如果陷入混乱,请站起来去外面走一圈,放松下再来,也许就能寻觅见迟迟不出现的bug

 

26、“Select”没有问题(“Select” Isn’t Broken)

OS或编译器、甚或是第三方产品或库中很少发现bugbug很可能在应用中。

PS:不要想当然的以为自己的代码没有问题,不可能出现问题。问题往往就出现在你的代码中,要永远对自己的代码持怀疑态度。

 

27、不要假定,要证明(Don’t Assume It - Prove it)

在实际环境中——使用真正的数据和边界条件——证明你的假设。

PS:不要理所当然的认为自己所有的假设都是正确的,如果想要证明自己的假设,可以去测试它。

 

28、学习一种文本操纵语言(Learn a Text Manipulation Language)

你用每天的很大一部分时间处理文本,为什么不让计算机替你完成部分工作呢?

PS:不是很能理解文本操纵语言的定义。

 

29、编写能编写代码的代码(Write Code That Writes Code)

代码生成器能提高你的生产率,并有助于避免重复。

PS:那些范式的代码就可以通过代码生成器来生成。

 

30、你不可能写出完美的软件(You Can’t Write Perfect Software)

软件不可能完美。保护你的代码和用户,使它(他)们免于能够预见的错误。

PS:软件不可能完美,真是因为不可能完美,才需要在编程时,多加小心,预防出错。正如书中讲到的,注重实效的的程序员连自己的代码都不相信。


31、通过合约进行设计(Design with Contracts)

使用合约建立文档,并检查代码所做的事情正好是它声明要做的。

PS:在java中,合约规定类,接口及其所实现的功能。(并不是很能理解)

 

32、早崩溃(Crash Early)

死程序造成的危害通常比有问题的程序要小得多。

PS:通过让程序尽早的崩溃(找出bug),所付出的代价会少很多。

 

33、用断言避免不可能发生的事情(Use Assertions to Prevent the Impossible)

断言验证你的各种假定。在一个不确定的世界里,用断言保护你的代码。

PS:现在并没有用过断言,等以后用了再说(据说现在Java用的比较多的是JUnit)。

 

34、将异常用于异常的问题(Use Exceptions for Exceptional Problems)

异常可能会遭受经典的意大利面式代码的所有可读性和可维护性问题的折磨。将异常保留给异常是事物。

PS:通过异常处理,可以省略大块的if -else if - else 的判断,当出现异常事件时,就可以用异常处理来进行捕获并处理。java中,不要以为在异常处理catch块中简简单单的写个e.printStackTrace();就行了,用户并不会看到,也不见得看得懂这个消息,我们能做的就是尽量处理这个异常,使之回到正常流程中。

 

35、要有始有终(Finish What You Start)

只要可能,分配某资源的例程或对象也应该负责解除其分配。

PS:学会配平资源,也就是说获取资源的时候想到怎么去释放它。很多时候可以在代码内部结尾处加上释放资源的代码,但是这样的一个坏处就是,如果调用者想保持该资源的占用是做不到的。由此出现了一种是谁调用,谁就负责关闭的机制。当然,还有其他机制,比如说Java中的垃圾回收机制,就是通过在堆栈中的资源块加上一个使用者个数的属性,当使用者个数为0时,就自动释放资源。

 

36、使模块之间的耦合减至最少(Minimize Coupling Between Modules)

通过编写“羞涩的”代码并应用德墨忒耳法则来避免耦合。

PS:德墨忒耳法则是一种软件设计的方法,限制某个对象的方法的调用来避免耦合。具体为:使用自身,使用传入参数,使用所创建对象,使用组件对象。

class Demeter{public:   void example(B &b);private:    A *a;    int func(){}}void Demeter::example(B &b){    C c;    int f = func(); <------------------1. 它自身    b.invert(); <----------------------2. 传入该方法的任何参数    a = new A();    a->setActive(); <------------------3. 它创建的任何对象    c.print(); <-----------------------4. 任何直接持有的组件对象}

得墨忒耳法则缩小了调用类中的响应集的规模,结果以这种方式设计的类的错误也往往更少。


37、要配置,不要集成(Configure,Don’t Integrate)

要将应用的各种技术选择实现为配置选项,而不是通过集成或工程方法实现。

PS:使用配置往往比集成的扩展性更好(并不是很能理解)。

 

38、将抽象放进代码,细节放进元数据(Put Abstractions in Code, Details in Metadate)

为一般情况编程,将细节放在被编译的代码库之外。

PS元数据被定义为:描述数据的数据,对数据及信息资源的描述性信息。

 

39、分析工作流,以改善并发性(Analyze Workflow to Improve Concurrency)

利用你的用户的工作流中的并发性。

PS:在同一时刻,某些事情是可以同时发生的,譬如流水线技术。可以去调查用户的工作的步骤(工作流),来设计同步并行的处理方法,以此来提高效率。

 

40、用服务进行设计(Design Using Services)

  根据服务——独立的、在良好定义、一致的接口之后的并发对象——进行设计。

PS:并不能理解。


41、总是为并发进行设计(Always Design for Concurrency)

容许并发,你将会设计出更整洁、具有更少假定的接口。

PS:控制并发是一件很头疼的事,如果写代码之前就考虑好了并发这一特性,那么就会迫使你去考虑很多你本来不会考虑的问题,这样写出的代码bug会少很多。

 

42、使视图与模型分离(Separate Views from Models)

要根据模型和视图设计你的应用,从而以低廉的代码获取灵活性。

PSMVC的设计模式就是一种很好的设计模式,通过将视图、业务逻辑和数据库访问进行分层隔离,这样无论是改变哪一层的代码都不会影响其它层的代码。

 

43、用黑板协调工作流(Use Blackboards to Coordinate Workflow)

用黑板协调完全不同的事实和因素,同时又使各参与方保持独立和隔离。

PS:黑板只是一个比喻,黑板象征着那种能够自由发表言论的地方。通过黑板这一介质,能将很多零散的东西组合成我们所需要的东西。

 

44、不要靠巧合编程(Don’t Program by Coincidence)

只依靠可靠的事物。注意偶发的复杂性,不要把幸运的巧合与有目的的计划混为一谈。

PS:正如前面所说的,不要相信你的代码,既然如此,为什么仅凭自己巧合通过的测试,就能证明,代码没问题了呢?

 

45、估算你的算法的阶(Estimate the Order of Your Algorithms)

在你编写代码之前,先大致估算事情需要多长时间。

PS:算法的阶大致分为:

c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n! 

一般来说会用大O(O(n)),来表示该算法的数量级,再通过分析,得出相应的时间复杂度T(n)和空间复杂度S(n)

 

46、测试你的估算(Test Your Estimates)

对算法的数学分析并不会告诉你每一件事情。在你的代码的目标环境中测试它的速度。

PS:根据硬件环境,软件环境的不同,相同的算法,其速度也有差异。

 

47、早重构,常重构(Refactor Early, Refactor Often)

就和你会在花园里除草、并重新布置一样,在需要时对代码进行重写、重做和重写架构。要铲除问题的根源。

PS:重构虽然可能耽误一点时间,但是比起与不重构的花费来比,完全可以忽略不计。

 

48、为测试而设计(Design to Test)

在你还没有编写代码时就开始思考测试的问题。

PS:就像硬件开始设计时,就考虑到了测试的问题一样,软件也应该考虑测试问题。

 

49、测试你的软件,否则你的用户就得测试(Test Your Software, or Your Users Will)

无情地测试。不要让你的用户为你查找bug

PS:如果软件做到要实际用户去测试bug,这样的软件任何一个用户都不想在使用第二次。如果想要节省花费,可以通过测试版本推送给同意参加测试的用户。

 

50、不要使用你不理解的向导代码(Don’t Use Wizard Code You Don’t Understand)

向导可以生成大量代码。在你把他们合并进你的项目之前,确保你理解全部这些代码。

PS:通过IDE能够生成一大堆向导代码,但是这些代码会加入你的项目,成为你项目的组成部分。不想要后期修改的时候头疼,尽早弄懂这些代码。


51、不要搜集需求——挖掘它们(Don’t Gather Requirement - Dig for Them)

需求很少存于表面上。它们深深地埋藏在层层假定、误解被政治手段的下面。

PS:这也是为什么需求分析那么难的原因了。

 

52、与用户一同工作,以像用户一样思考(Work with a User to Think Like a User)

要了解系统实际上将如何被使用,这是最好的办法。

PS:了解业务逻辑了,写起代码来才会得心应手。

 

53、抽象比细节活得更长久(Abstractions Live Longer than Details)

“投资”于抽象,而不是实现。抽象能在来自不同的实现和新技术的变化的“攻击”之下存活下去。

PS:抽象的事物,其所涵盖的范围相对于具体的事物更广,所能够表达的信息也就越多。

 

54、使用项目词汇表(Use a Project Glossary)

创建并维护项目中使用的专用术语和词汇的单一信息源。

PS:不同的人在对同一件事物的表达上可能不同,这样的话,通过统一的规范会取得更好的效果。

 

55、不要在盒子外面思考——要找到盒子(Don’t Think Outside the Box - Find the Box)

在遇到不可能解决的问题时,要确定真正的约束。问问你自己:“它必须以这种方式完成吗?它真的必须完成吗?”

PS:找到问题的关键所在。(不是很能理解)

 

56、等你准备好再开始(Start When You’re Ready)

你的一生都在积累经验。不要忽视反复出现的疑虑。

PS:无法理解。

 

57、对有些事情“做”胜于“描述”(Some Things Are Better Done than Described)

不要掉进规范的螺旋——在某个时刻,你需要开始编码。

PS:一大堆规范文档看得头疼欲裂,为什么不自己收集需求,理解业务逻辑,然后开始编码呢?在编码后,再仔细审阅文档(不是很能理解)

 

58、不要做形式方法的奴隶(Don’t Be a Slave to Formal Methods)

如果你没有把某项技术放进你的开发实践和能力的语境中,不要盲目地采用它。

PS:掌握一种描述方法比了解十门描述方法更好。

 

59、昂贵的工具不一定能制作出更好的设计(Costly Tools Don’t Produce Better Designs)

小心供应商的炒作,行业教条、以及价格标签的诱惑。要根据工具的价值判断它们。

PS:就像Oracle在低性能的服务器表现力不一定有MySQL好一样,找到最适合的更重要。

 

60、围绕功能组织团队(Organize Teams Around Functionality)

不要把设计师与编码员分开,也不要把测试员与数据建模员分开。按照你构建代码的方式构建团队。

PS:无法理解。

 

61、不要使用手工流程(Don’t Use Manual Procedures)

shell脚本或批文件会一次次地以同一顺序执行同样的指令。

PS:正如数据库的备份一样,如果设置好时间进行自动备份的话,就不需要人来手工备份了,而且这样出错的机率也低很多。

 

62、早测试,常测试,自动测试(Test Early. Test Often. Test Automatically)

与呆在书架上的测试计划相比,每次构建时运行的测试要有效的多。

PS:就像你很难发现三个月前写得代码的bug一样,尽早、常常测试将帮助你更早发现它,尽可能的写一些自动测试的脚本,来节省你花在测试上的时间。

 

63、要到通过全部测试,编码才算完成(Coding Ain’t Done ‘Til All the Tests Run)

就是这样。

PS:没通过全部测试,怎么可能是复合要求的代码。

 

64、通过“蓄意破坏”测试你的代码(Use Saboteurs to Test Your Testing)

在单独的软件副本上故意引入bug,以检验测试能够抓住它们。

PS:就像前面所说的一样,没有完美的代码,那么测试代码也有可能出错,这时候就可以引入一些既定的bug来测试,测试代码。

 

65、测试状态覆盖,而不是代码覆盖(Test State Coverage, Not Code Coverage)

确定并测试重要的程序状态。只是测试代码行是不够的。

PS:单元测试的方法有很多种,条件覆盖,路径覆盖,基本路径覆盖等等,但是很明确的一点就是,这些测试都是通过关键代码的状态来进行组合的。

 

66、一个bug只抓一次(Find Bugs Once)

一旦测试员找到一个bug,这应该是测试员最后一次找到它。此后自动测试应该对齐进行检查。

PS:找到bug就要想方设法修复,并且实现该bug的自动检查(不是很能理解)。

 

67、英语就是一种编程语言(English is Just a Programming Language)

像你编写代码一样编写文档:遵守DRY原则、使用元数据、MVC、自动生成,等等。

PS:无法理解。

 

68、把文档建在里面,不要拴在外面(Build Documentation In, Don’t Bolt It On)

与代码分离的文档不太可能被修正和更新。

PS:写注释就是为了在读源代码的时候方面,如果将注释和源代码分开,可能读取来就很麻烦了。不过注释的原则是要有意义,要注释类,方法的功能,成员变量的用途,方法参数列表的意义等等。

 

69、温和地超出用户的期望(Gently Exceed Your Users’ Expectations)

要理解你的用户的期望,然后给他们的东西要多那么一点。

PS:如果能在完成用户所预想的东西的基础上加上一些便捷性的功能,无疑是锦上添花,这就能打下良好的声誉。

 

70、在你的作品上签名(Sign Your Work)

过去时代的手艺人为能在他们的作品上签名而自豪。你也应该如此。

PS:署名是一种良好的习惯,证明你愿意为你写的代码负责,由此你就会更细心的写出更好的代码。通过你的不断努力,代码写得非常好,那么别人看到你的署名就知道这代码质量很好。而不愿意花心思在这上面的程序员恰恰相反,不愿意署名,也不敢署名。





补充:

1、要学习的语言

厌倦了CC++JAVA?试试CLOSDylanEiffelObject-CPrologSmalltalkTOM。它们每一种都有不同的能力和不同的“风味”。用其中的一种或多种语言在家里开发一个小项目。

 

2WISDOM离合诗

                            What do you want them to learn?       你想让他们学到什么?

    What is their interest in what you’ve got to say?       他们对你讲的什么感兴趣?

                                   How sophisticated are they?       他们有多富有的经验?

                               How much detail do they want?       他们想要多少细节?

           Whom do you want to own the information?       你想要让谁拥有这些信息?

          How can you motivate them to listen to you?      你如何促使他们听你说话?

 

3、怎样维持正交性

  • 设计独立、良好定义的组件。
  • 使你的代码保持解耦。
  • 避免使用全局数据。
  • 重构相似的函数。

 

4、应制作原型的事物

  • 架构
  • 已有系统的新功能
  • 外部数据的结构或内容
  • 第三方工具或组件
  • 性能问题
  • 用户界面设计

 

5、架构问题

  • 责任是否得到了良好定义?
  • 协作是否得到了良好定义?
  • 耦合是否得以最小化?
  • 你能否确定潜在的重复?
  • 接口定义和各项约束是否可接受?
  • 模块能否在需要时访问所需数据?

 

6、调试检查清单

  • 正在报告的问题是底层bug的直接结果,还是只是症状?
  • bug真的在编译器里?在OS里?或者是在你的代码里?
  • 如果你向同事详细解释这个问题,你会说什么?
  • 如果可疑代码通过了单元测试,测试是够足够完整,如果你用该数据运行单元测试,会发生什么?
  • 造成这个bug的条件是否存在于系统中的其他任何地方?

 

7、函数的德墨忒耳法则

某个对象的方法应该只调用属于以下情形的方法:

  • 它自身
  • 传入的任何参数
  • 它创建的对象
  • 组件对象

 

8、怎样深思熟虑地编程

  • 总要意识到你在做什么。
  • 不要盲目地编程。
  • 按照计划行事
  • 依靠可靠的事物。
  • 为你的假设建立文档
  • 不要只是测试你的代码,还要测试你的假定。
  • 为你的工作划分优先级。
  • 不要做历史的奴隶。

 

9、何时进行重构

  • 你发现了对DRY原则的违反。
  • 你发现事物可以更为正交。
  • 你的知识扩展了。
  • 需求演变了。
  • 你需要改善性能。

 

10、劈开戈尔迪斯结

在解决不可能解决的问题时,问问你自己:

  • 有更容易的方法吗?
  • 我是在解决正确的问题吗?
  • 这件事情为什么是一个问题?
  • 是什么使它如此难以解决?
  • 它必须以这种方式完成吗?
  • 它真的必须完成吗?

 

11、测试各个方面

  • 单元测试
  • 集成测试
  • 验证和校验
  • 耗尽资源、错误及恢复
  • 性能测试
  • 可用性测试
  • 对测试自身进行测试


----------参考《程序员修炼之道——从小工到专家》


0 0
原创粉丝点击