代码大全(Code Complete)
https://book.douban.com/subject/1477390/
P20/P35 组合各个隐喻(Combining Metaphors)
因为隐喻是一种启发式方法而不是算法,因此他们彼此并不排斥。你可以同时使用生长(accretion)和建筑(construction)这两个隐喻。你如果想用"写作"隐喻也行,你还可以把"写作"同“驾驶”,“狩猎狼人”,“与恐龙一起在焦油坑中淹死”等隐喻组合到一起。你可以选用任何一种隐喻,或者是一些隐喻的组合,只要他能激发你的思维灵感,并让你和团队其他成员更好的沟通。
使用隐喻又是一件说不清楚的事情(fuzzy business)。你需要适当的引申它的含义,才能从其蕴含的深刻启发中受益,但若你过分地或在错误的方向上延伸了它的含义,它也会误导你。正如人们会误用任何强大的工具一样,你也可能误用隐喻,但它的强大功效,还会成为你智慧工具箱中的一个宝贵部分。
P31/P46 辨明你所从事的软件类型
- 商业系统
- 使命攸关的系统
- 性命攸关的嵌入式系统
P67/P82 你在技术浪潮中的位置
这些评论看起来似乎在建议:应该避免在浪潮的早期搞编程,但这并不是我的意思。一些最具创造力的应用程序,就是从浪潮早期的程序中涌现出来的,例如turbo pascal, lotus 123, Microsoft word, mosaic浏览器。关键在于,“你如何面对自己的编程工作”,取决于你在技术浪潮中所处的位置。如果处在浪潮的后期,你就可以计划用大部分时间稳定持续地编写新功能。如果你处在浪潮的前期,可以预期你要花费很大一部分时间,用来找出文档中未加说明的编程语言特性,调试程序库代码缺陷带来的错误,修订代码以适应厂商提供的新版本函数库等。
P69/P84 深入一种语言去编程
如果你正在一个很初级简陋的环境下工作,你会发现与成熟的环境相比,本书介绍的编程实践将更有帮助。正如David Gries所言,编程工具不应该决定你的编程思路。Gries对“在一种编程语言上编程”(programming in a language)和“深入一种语言去编程”(programming into a language)做了区分。在一种语言上编程的程序员将他们的思想限制于语言直接支持的那些构件,如果语言工具是初级的,那么程序员的思想也是初级的。深入一门语言编程的程序员首先决定他要表达的思想,然后决定如何使用特定语言提供的工具来表达这些思想。
理解“在一种语言上编程”和“深入一种语言去编程”的区别,对于理解本书是至关重要的。大多数重要的编程原则并不依赖特定的语言,而依赖于你使用语言的方式。如果你使用的语言缺乏你希望用的构件,或倾向于出现其他种类的问题,那就应该试着去弥补它。发明你自己的编码约定,标准,类库以及其他改进措施。
P75/P90 设计是一个险恶的问题(Wicked Problem)
你在学校中所开发的程序和你在职业生涯中所开发的程序的主要差异就在于,学校里的程序所解决的设计问题很少(如果有的话)是险恶的。学校里给你的编程作业,都是为了让你能够从头到尾直线前进和设计的。如果有位老师给你一份编程作业,你刚完成设计时他就把作业的要求改了,然后就在你将要提交完整的程序时,他又对作业的要求再次改动,这事你肯定会十分生气。然而这一过程正是在专业编程中每日可见的真实情形。
P270/P285 为什么要有命名规则
命名规则可以带来以下的好处:
- 要求你更多的按规矩行事,通过做一项全局决策,而不是做许多局部决策,你可以集中精力关注代码更重要的特征。
- 有助于在项目之间传递知识,名字的相似性能让你更容易更自信的理解那些不熟悉的变量,原本应该是做什么的。
- 有助于你在新项目中更快的学习代码。所有项目中相似对象的名字都是类似的。
- 有助于减少名字增生(name proliferation)。没有命名规则的情况下,会很容易的给同一个对象起两个不同的名字。在写代码的时候,就可能并不会让你感到迷惑,但是它却会让一位日后阅读这段代码的新程序员感到极其困惑。
- 弥补编程语言的不足,你可以用规则来仿效具名常量和类型,规则可以根据局部数据,类数据以及全局数据的不同有所差别,并且可以包含编译器不直接提供的类型信息。
P470/P485 各种质量保证技术的缺陷检测率
P482/P497 协同构建有利于传授公司文化以及编程专业知识
软件标准可以写下来并发布出去,但是如果无人去讨论它们,也不鼓励使用这些标准,那么就不会有人去按照这些标准做事情。复查是一个很重要的机制,它可以让程序员得到他们自己的代码反馈。代码,标准以及让代码符合标准的理由等,都是复查讨论中的主题。程序员除了需要得到他们是否很好的遵循了标准的反馈之外,还需要得到程序设计主观方面的回馈,比如格式,注释变量名,局部变量和全局变量的使用,设计方法以及“我们这里采用的解决方法"(the-way-we-do-things-around-here)等。刚出道的编程人员需要那些有丰富知识的前辈给予指导,而资深程序员们往往太忙而没有直接同他人分享他们的知识。复查为这两种人提供了一个技术交流的平台,所以无论在未来还是现在,复查都是培养新人以及提高代码质量的好机会。
P490/P505 审查中的自尊心
进行详查的目的是发现设计或代码中的缺陷,而不是探索代替方案,或者争论谁对谁错,其目的绝不应该是批评作者的设计或者代码。对于作者来说详查的过程应该是正面的,在这一过程中的团队参与使程序得到了明显改善,对所有参与者都是一个学习的过程。这一过程不应该让作者认为团队里面某些人是白痴,或者认为自己应该另谋高就。
因为设计或代码受到了批评,作者可能感到自己难辞其咎,所以很自然的或者会觉得代码让他脸上无光。作者应该预料到他会听到对某些缺陷的批评,而那些其实并不是缺陷,还有许多是有争议的。尽管如此,作者应该承认每一个所谓的缺陷,然后继续详查。承认一个批评并不意味着作者认同批评的内容。在复查过程中,作者不应该试图为正在被检查的工作辩护。在复查之后,作者可以独自对每一个问题进行思考,判断它是否真的是一个缺陷。
评论员必须记住,最终是由作者来负责决定如何处理缺陷,我们应该享受寻找缺陷的乐趣,并且可以在复查后,享受为解决方案提供建议的乐趣。但是每一个评论员必须尊重作者决定如何解决某个错误的最终权利。
P595/P610 从全局观点做程序优化
一句话,不成熟优化的主要缺陷,在于它缺乏前瞻性。受到损害的,包括最终代码的运行速度,比代码速度更为重要的性能特性,程序质量,直至最终软件用户。如果能将开发最简单程序所节省下来的时间,放到优化可运行程序上,结果得到的程序必然比那些未经斟酌便具优化的程序更快。
偶然有这样的情况,后期优化还无法完全满足性的目标,你不得不对已经完工的代码进行大规模改动。这时小型的局部优化无论如何也无法提供所需的性能,造成这种局面的原因并不是代码质量不高,而是软件架构的先天不足。
如果需要在程序完成前做优化,那就应该在优化过程中建立一种全局观点,这样才能降低风险。方法之一就是为某项功能确定一些资源占用和速度的目标,在优化过程中使程序满足这些目标。这样一来,程序员在思考眼前这棵大树到底有多高的时候,还能留意一下整个森林。
P644/P659 恪守优化的原则
代码调整无可避免地为性能改善的良好愿望而付出复杂性,可读性,简单性,可维护性方面的代价。由于每一次调整后需要对性能进行重新评估,代码调整还引入了额外的管理维护开销。
我已经体会到,恪守“对每一次的改进进行量化”的准则,是抵御思考成熟前匆忙优化之诱惑的法宝。这一准则也帮助我坚守编写清晰简单代码的一贯作风。如果某向优化非常重要,值得为它付出剖析和对优化效果进行量化测量的代价,那么只要优化有效,我们还是可以去做的。但是如果某项优化的重要性不够,不值得为他做性能剖析,那么就不值得为它付出和可读性,可维护性和其他代码特性恶化等方面的代价。未经测量的代码优化对性能上的改善,充其量是一次投机,然而对可读性产生的负面影响则确凿无疑。
P654/P669 项目规模范围和构建时间比重
对于小型项目,构建是最主要的活动,它占了整个开发时间的差不多65%。对于中型项目,构建仍是处于主导地位的活动,但是它所占的比例已经下降到了大约50%。对于非常大型的项目,架构,集成和系统测试占据了更多的时间,而构建活动则变得不再那么占主导地位了。简而言之,随着项目规模的增大,构建活动在整个工作量中所占的比重将逐渐减少。
P681/P696 程序员们怎样花费时间
P723/P738 工具幻境
出现这一对抗性态势的原因在于,就其本质而言,编程从根本上说就是困难的。即便有好的工具资源,无论能用到哪些工具,程序员都必须与凌乱的真实世界角力:我们必须严密思考前后次序,依赖关系,异常情况;而且我们还要与无法说清楚自己想法的最终用户交往。我们始终要应对连接到其他软件或硬件的定义不清的接口,还要解决规章制度业务规则以及其它复杂性制约,这些复杂性来自计算机编程之外的世界。
始终需要人来填补真实世界里需要解决的问题和准备用来解决问题的计算机之间的鸿沟,这些人将会被称为程序员。无论他是以汇编语言操控机器计算器,还是用Microsoft visual basic操控对话框,只要有计算机,就需要能告诉计算机该去做什么的人,这一活动都将会被称作编程。
P833/P848 好的习惯
我们要学习源于亚里士多德的“精神品德”的“编程品德”。他指出人们并非天生好或坏,而是设定的道路使人成为优或劣的程序员。你做的好坏主要靠你的所作所为。建筑师要通过建筑,程序员则要通过编程。行为养成习惯,年复日久这些好坏习惯,就决定了你作为程序员的优劣。
比尔盖茨说,任何日后出色的程序员前几年就做的很好。从那以后,程序员好坏就定型了。在你搞编程颇有些年头后很难会突然说,“怎样才能使这个循环再快些呢?”或者“如何让这段代码更好看懂呢?”优秀的程序员早就养成了这些习惯。初涉某事时,就应端正态度来学。开始做事情时你还会继续思考,轻松决定做的好坏。干了一段时间后就会习以为常,习惯的力量开始起作用。请确保这些习惯是你所希望的东西。
P851/P866 分离软件与信仰
宗教信仰在软件开发中有多种表现形式。非要坚持某种设计方法,笃信特定的布局或注释风格,极力避免全局变量。不管是哪种情况,都是不合适的。
糟糕的是,一些优秀人员往往更容易偏执。革新方法需要公开才能让别人尝试,尝试这些方法后才能充分证实或反驳之。研究结果向实践者的传播称为“技术转移”,对于推动软件开发的实践水平有重要作用。然而传播新方法和兜售狗皮膏药不是同样的概念,对于后者,兜售者只是不懈地让你确信他们的方法如何灵验,如何放之四海而皆准。他们要你忘掉所学的一切,因为新方法如此伟大,能在任何方面将你的效率提高100%。不要盲目跟风,而应使用一种混合的方法。可用激动人心的最新方法做做试验,但仍扎根于传统的可靠的方法。
要对编程问题找到最有效的解决方法时,盲目迷信某种方法只会缩小你的选择余地。要是软件开发是确定的精确过程,就能按固定的套路解决问题。但软件开发并非确定过程,是需要逐步细化的。因而生硬的过程是不合适的,很难指望会成功。例如设计中有时字顶向下分解法行得通,有时候面向对象的方法,自底向上综合法或数据结构法会更好一些。你应该有意识的尝试几种途径,明知这些方法中有的可能成功有可能失败,但只有通过实践才能知道哪些好使。你必须采取折中的态度。