`

程序员修炼之道总结

 
阅读更多

第一章 我的代码让猫吃了
在所有弱点中,最大的弱点就是害怕暴露弱点。

Provide Options, Don’t Make Lame Excuses
提供各种选择,不要找蹩脚的借口

第二章 软件的熵
Don’t Live with Broken Windows
不要容忍破窗户

不要留着“破窗户”(低劣的设计、错误决策、或是糟糕的代码)不修。
发现一个就修一个。如果没有足够的时间进行适当的修理,就用木板把它钉起来。
或许你可以把出问题的代码放入注释(comment out),或是显示“未实现”消息,或是用虚设的数据(dummy data)加以替代。
采取某种行动防止进一步的损坏,并说明情势处在你的控制之下。

第三章 石头汤与煮青蛙
Be a Catalyst for Change
做变化的催化剂
要持续不断地观察周围发生的事情,而不只是你自己在做的事情。

第四章 足够好的软件
你所制作的系统的范围和质量应该作为系统需求的一部分规定下来。
Make Quality a Requirements Issue
使质量成为需求问题

你常常会处在须要进行权衡的情形中。让人惊奇的是,许多用户宁愿在今天用上有一些“毛边”的软件,
也不愿等待一年后的多媒体版本。许多预算吃紧的IT部门都会同意这样的说法。今天的了不起的软件常常比明天的完美软件更可取。
如果你给用户某样东西,让他们及早使用,他们的反馈常常会把你引向更好的最终解决方案。

不要因为过度修饰和过于求精而毁损完好的程序。继续前进,让你的代码凭着自己的质量站立一会儿。它也许不完美,但不用担心:它不可能完美。

第五章 你的知识产
每年至少学习一种新语言。不同语言以不同方式解决相同的问题。通过学习若干不同的方法,可以帮助你拓宽你的思维,并避免墨守成规。此外,现在学习许多语言已容易了许多,感谢可从网上自由获取的软件财富(参见267页)。

每季度阅读一本技术书籍。书店里摆满了许多书籍,讨论与你当前的项目有关的有趣话题。一旦你养成习惯,就一个月读一本书。在你掌握了你正在使用的技术之后,扩宽范围,阅读一些与你的项目无关的书籍。

也要阅读非技术书籍。记住计算机是由人——你在设法满足其需要的人——使用的,这十分重要。不要忘了等式中人这一边。

上课。在本地的学院或大学、或是将要来临的下一次会展上寻找有趣的课程。

参加本地用户组织。不要只是去听讲,而要主动参与。与世隔绝对你的职业生涯来说可能是致命的;打听一下你们公司以外的人都在做什么。

试验不同的环境。如果你只在Windows上工作,就在家玩一玩Unix(可自由获取的Linux就正好)。如果你只用过makefile和编辑器,就试一试IDE,反之亦然。

跟上潮流。订阅商务杂志和其他期刊(参见262页的推荐刊物)。选择所涵盖的技术与你当前的项目不同的刊物。

上网。想要了解某种新语言或其他技术的各种特性?要了解其他人的相关经验,了解他们使用的特定行话,等等,新闻组是一种很好的方式。上网冲浪,查找论文、商业站点,以及其他任何你可以找到的信息来源。

第六章 交流
It’s Both What You Say and the Way You Say It
你说什么和你怎么说同样重要
 知道你想要说什么。

了解你的听众。

选择时机。

选择风格。

让文档美观。

让听众参与。

做倾听者。

回复他人。

 

第七章 不要重复自己

DRY – Don’t Repeat Yourself
不要重复你自己

与此不同的做法是在两个或更多地方表达同一事物。
如果你改变其中一处,你必须记得改变其他各处。或者,就像那些异形计算机,你的程序将因为自相矛盾而被迫屈服。
这不是你是否能记住的问题,而是你何时忘记的问题。

Make It Easy to Reuse
让复用变得容易
 
你所要做的是营造一种环境,在其中要找到并复用已有的东西,比自己编写更容易。
如果不容易,大家就不会去复用。而如果不进行复用,你们就会有重复知识的风险。

 

第八章 正交性

如果你想要制作易于设计、构建、测试及扩展的系统,正交性是一个十分关键的概念,但是,正交性的概念很少被直接讲授,而常常是你学习的各种其他方法和技术的隐含特性。这是一个错误。一旦你学会了直接应用正交性原则,你将发现,你制作的系统的质量立刻就得到了提高。

什么是正交性

“正交性”是从几何学中借来的术语。如果两条直线相交成直角,它们就是正交的,比如图中的坐标轴。
用向量术语说,这两条直线互不依赖。沿着某一条直线移动,你投影到另一条直线上的位置不变。

在计算技术中,该术语用于表示某种不相依赖性或是解耦性。如果两个或更多事物中的一个发生变化,
不会影响其他事物,这些事物就是正交的。在设计良好的系统中,数据库代码与用户界面是正交的:
你可以改动界面,而不影响数据库;更换数据库,而不用改动界面。

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

我们想要设计自足(self-contained)的组件:独立,具有单一、良好定义的目的(Yourdon和Constantine称之为内聚(cohesion)[YC86])。
如果组件是相互隔离的,你就知道你能够改变其中之一,而不用担心其余组件。
只要你不改变组件的外部接口,你就可以放心:你不会造成波及整个系统的问题。

如果你编写正交的系统,你得到两个主要好处:提高生产率与降低风险。

 

第13章 估算

提示18
Estimate to Avoid Surprises
估算,以避免发生意外

  作为奖励,在这一节的末尾我们将透露一个总是正确的答案——无论什么时候有人要你进行估算,你都可以给出答案。
多准确才足够准确
  在某种程度上,所有的解答都是估算。只不过有一些要比其他的更准确。所以当有人要你进行估算时,你要问自己的第一个问题就是,你解答问题的语境是什么?他们是需要高度的准确性,还是在考虑棒球场的大小?
l       如果你的奶奶问你何时抵达,她也许只是想知道该给你准备午餐还是晚餐。而一个困在水下、空气就快用光的潜水员很可能对精确到秒的答案更感兴趣。

l       p的值是多少?如果你想知道的是要买多少饰边,才能把一个圆形花坛围起来,那么“3”很可能就足够好了。如果你在学校里,那么“22/7”也许就是一个好的近似值。如果你在NASA(美国国家航空航天管理局),那么也许要12个小数位。

  关于估算,一件有趣的事情是,你使用的单位会对结果的解读造成影响。如果你说,某事需要130个工作日,那么大家会期望它在相当接近的时间里完成。但 是,如果你说“哦,大概要六个月”,那么大家知道它会在从现在开始的五到七个月内完成。这两个数字表示相同的时长,但“130天”却可能暗含了比你的感觉 更高的精确程度。我们建议你这样度量时间估算:

时长
 报出估算的单位
 
1-15天
 天
 
3-8周
 周
 
8-30周
 月
 
30+周
 在给出估算前努力思考一下
于是,在完成了所有必要的工作之后,你确定项目将需要125个工作日(25周),你可以给出“大约六个月”的估算。
同样的概念适用于对任何数量的估算:要选择能反映你想要传达的精确度的单位。

 

估算来自哪里

  所有的估算都以问题的模型为基础。但在我们过深地卷入建模技术之前,我们必须先提及一个基本的估算诀窍,它总能给出好的答案:去问已经做过这件事情的人。在你一头钻进建模之前,仔细在周围找找也曾处在类似情况下的人。
  看看他们的问题是怎么解决的。你不大可能找到完全相符的案例,但你会惊奇有多少次,你能够成功地借鉴他人的经验。

 

理解提问内容

  任何估算练习的第一步都是建立对提问内容的理解。除了上面讨论的精确度问题以外,你还需要把握问题域的范围。这常常隐含在问题中,但你需要养成在开始 猜想之前先思考范围的习惯。常常,你选择的范围将形成你给出的解答的一部分:“假定没有交通意外,而且车里还有汽油,我会在20分钟内赶到那里。”


建立系统的模型

  这是估算有趣的部分。根据你对所提问题的理解,建立粗略、就绪的思维模型骨架。如果你是在估算响应时间,你的模型也许要涉及服务器和某种到达流量 (arriving traffic)。对于一个项目,模型可以是你的组织在开发过程中所用的步骤、以及系统的实现方式的非常粗略的图景。

  建模既可以是创造性的,又可以是长期有用的。在建模的过程中,你常常会发现一些在表面上不明显的底层模式与过程。你甚至可能会想要重新检查原来的问题:“你要求对做X所需的时间进行估算。但好像X的变种Y只需一半时间就能完成,而你只会损失一个特性。”

  建模把不精确性引入了估算过程中。这是不可避免的,而且也是有益的。你是在用模型的简单性与精确性做交易。使花在模型上的努力加倍也许只能带来精确性的轻微提高。你的经验将告诉你何时停止提炼。

 

把模型分解为组件

  一旦拥有了模型,你可以把它分解为组件。你须要找出描述这些组件怎样交互的数学规则。有时某个组件会提供一个值,加入到结果中。有些组件有着成倍的影响,而另一些可能会更为复杂(比如那些模拟某个节点上的到达流量的组件)。

  你将会发现,在典型情况下,每个组件都有一些参数,会对它给整个模型带来什么造成影响。在这一阶段,只要确定每个参数就行了。

 

给每个参数指定值

  一旦你分解出各个参数,你就可以逐一给每个参数赋值。在这个步骤中你可能会引入一些错误。诀窍是找出哪些参数对结果的影响最大,并致力于让它们大致正 确。在典型情况下,其值被直接加入结果的参数,没有被乘或除的那些参数重要。让线路速度加倍可以让1小时内接收的数据量加倍,而增加5毫秒的传输延迟不会 有显著的效果。

  你应该采用一种合理的方式计算这些关键参数。对于排队的例子,你可以测量现有系统的实际事务到达率,或是找一个类似的系统进行测量。与此类似,你可以 测量现在服务1个请求所花的时间,或是使用这一节描述的技术进行估算。事实上,你常常会发现自己以其他子估算为基础进行估算。这是最大的错误伺机溜进来的 地方。


计算答案

  只有在最简单的情况下估算才有单一的答案。你也许会高兴地说:“我能在15分钟内走完五个街区。”但是,当系统变得更为复杂时,你就会避免做出正面回 答。进行多次计算,改变关键参数的值,直到你找出真正主导模型的那些参数。电子表格可以有很大帮助。然后根据这些参数表述你的答案。“如果系统拥有 SCSI总线和64MB内存,响应时间约为四分之三秒;如果内存是48MB,则响应时间约为一秒。”(注意“四分之三秒”怎样给人以一种与750毫秒不同 的精确感。)

  在计算阶段,你可能会得到看起来很奇怪的答案。不要太快放弃它们。如果你的运算是正确的,那你对问题或模型的理解就很可能是错的。这是非常宝贵的信息。

 

追踪你的估算能力

  我们认为,记录你的估算,从而让你看到自己接近正确答案的程度,这是一个非常好的主意。如果总体估算涉及子估算的计算,那么也要追踪这些子估算。你常常会发现自己估算得非常好——事实上,一段时间之后,你就会开始期待这样的事情。

  如果结果证明估算错了,不要只是耸耸肩走开。找出事情为何与你的猜想不同的原因。也许你选择了与问题的实际情况不符的一些参数。也许你的模型是错的。不管原因是什么,花一点时间揭开所发生的事情。如果你这样做了,你的下一次估算就会更好。

 

 

估算项目进度

  在面对相当大的应用开发的各种复杂问题与反复无常的情况时,普通的估算规则可能会失效。我们发现,为项目确定进度表的惟一途径常常是在相同的项目上获取经验。如果你实行增量开发、重复下面的步骤,这不一定就是一个悖论:

l       检查需求

l       分析风险

l       设计、实现、集成

l       向用户确认

  一开始,你对需要多少次迭代、或是需要多少时间,也许只有模糊的概念。有些方法要求你把这个作为初始计划的一部分定下来,但除了最微不足道的项目,这是一个错误。除非你在开发与前一个应用类似的应用,拥有同样的团队和同样的技术,否则,你就只不过是在猜想。

  于是你完成了初始功能的编码与测试,并将此标记为第一轮增量开发的结束。基于这样的经验,你可以提炼你原来对迭代次数、以及在每次迭代中可以包含的内容的猜想。提炼会变得一次比一次好,对进度表的信心也将随之增长。

 

terate the Schedule with the Code
通过代码对进度表进行迭代
 

  这也许并不会受到管理部门的欢迎,在典型情况下,他们想要的是单一的、必须遵守的数字——甚至是在项目开始之前。你必须帮助他们了解团队、团队的生产 率、还有环境将决定进度。通过使其形式化,并把改进进度表作为每次迭代的一部分,你将给予他们你所能给予的最精确的进度估算。

在被要求进行估算时说什么

  你说:“我等会儿回答你。”

  如果你放慢估算的速度,并花一点时间仔细检查我们在这一节描述的步骤,你几乎总能得到更好的结果。在咖啡机旁给出的估算将(像咖啡一样)回来纠缠你。


第16章 强力编辑

Use a Single Editor Well
用好一种编辑器

  选一种编辑器,彻底了解它,并将其用于所有的编辑任务。如果你用一种编辑器(或一组键绑定)进行所有的文本编辑活动,你就不必停下来思考怎样完成文本操纵:必需的键击将成为本能反应。编辑器将成为你双手的延伸;键会在滑过文本和思想时歌唱起来。这就是我们的目标。
  确保你选择的编辑器能在你使用的所有平台上使用。Emacs、vi、CRiSP、Brief及其他一些编辑器可在多种平台上使用,并且常常既有GUI版本,也有非GUI(文本屏幕)版本。

编辑器特性

  除了你认为特别有用、使用时特别舒适的特性之外,还有一些基本能力,我们认为每个像样的编辑器都应该具备。如果你的编辑器缺少其中的任何能力,那么你或许就应该考虑换一种更高级的编辑器了。

l       可配置。编辑器的所有方面都应该能按你的偏好(preference)配置,包括字体、颜色、窗口尺寸以及键击绑定(什么键执行什么命令)。对于常见的编辑操作,与鼠标或菜单驱动的命令相比,只使用键击效率更高,因为你的手无须离开键盘。

l       可扩展。编辑器不应该只因为出现了新的编程语言就变得过时。它应该能集成你在使用的任何编译器环境。你应该能把任何新语言或文本格式(XML、HTML第9版,等等)的各种细微差别“教”给它。

l       可编程。你应该能对编辑器编程,让它执行复杂的、多步骤的任务。可以通过宏或内建的脚本编程语言(例如,Emacs使用了Lisp的一个变种)进行这样的编程。
此外,许多编辑器支持针对特定编程语言的特性,比如:

l       语法突显

l       自动完成

l       自动缩进

l       初始代码或文档样板

l       与帮助系统挂接

l       类IDE特性(编译、调试,等等)
  像语法突显这样的特性听起来也许像是无关紧要的附加物,但实际上却可能非常有用,而且还能提高你的生产率。一旦你习惯了看到关键字以不同的颜色或字体出现,远在你启动编译器之前,没有以那样的方式出现的、敲错的关键字就会在你面前跳出来。
  对于大型项目,能够在编辑器环境中进行编译、并直接转到出错处非常方便。

 

第17章 源码控制

进步远非由变化组成,而是取决于好记性。不能记住过去的人,被判重复过去。

  ——George Santayana, Life of Reason


  我们在用户界面中找寻的一个重要的东西是UNDO键——一个能原谅我们的错误的按钮。如果环境支持多级撤消(undo)与重做(redo),那就更好 了,这样你就可以回去,撤消几分钟前发生的事情。但如果错误发生在上周,而你那以后已经把计算机打开关闭了十次呢?噢,这是使用源码控制系统的诸多好处之 一:它是一个巨大的UNDO键——一个项目级的时间机器,能够让你返回上周的那些太平日子,那时的代码还能够编译并运行。

  源码控制系统(或范围更宽泛的配置管理系统)追踪你在源码和文档中做出的每一项变动。

    更好的系统还能追踪编译器及OS版本。有了适当配置的源码控制系统,你就总能够返回你的软件的前一版本。

  但源码控制系统(SCCS)能做的远比撤消错误要多。好的SCCS让你追踪变动,回答这样的问题:谁改动了这一行代码?在当前版本与上周的版本之间有 什么区别?在这次发布的版本中我们改动了多少行代码?哪个文件改动最频繁?对于bug追踪、审计、性能及质量等目的,这种信息非常宝贵。

 

第18章 调试

这是痛苦的事:
看着你自己的烦忧,并且知道
不是别人、而是你自己一人所致
  ——索福克勒斯:《埃阿斯》
 要接受事实:调试就是解决问题,要据此发起进攻。

发现了他人的bug之后,你可以花费时间和精力去指责让人厌恶的肇事者。
在有些工作环境中,这是文化的一部分,并且可能是“疏通剂”。
但是,在技术竞技场上,你应该专注于修正问题,而不是发出指责。

Fix the Problem, Not the Blame
要修正问题,而不是发出指责
 bug是你的过错还是别人的过错,并不是真的很有关系。它仍然是你的问题。

最容易欺骗的人是一个人自己。
  ——Edward Bulwer-Lytton, The Disowned
在你开始调试之前,选择恰当的思维方式十分重要。你须要关闭每天用于保护自我(ego)的许多防卫措施,
忘掉你可能面临的任何项目压力,并让自己放松下来。最重要的是,记住调试的第一准则:

提示25
Don’t Panic
不要恐慌

Don’t Assume it – Prove It
不要假定,要证明这是痛苦的事:
看着你自己的烦忧,并且知道
不是别人、而是你自己一人所致
  ——索福克勒斯:《埃阿斯》
 要接受事实:调试就是解决问题,要据此发起进攻。

发现了他人的bug之后,你可以花费时间和精力去指责让人厌恶的肇事者。
在有些工作环境中,这是文化的一部分,并且可能是“疏通剂”。
但是,在技术竞技场上,你应该专注于修正问题,而不是发出指责。

Fix the Problem, Not the Blame
要修正问题,而不是发出指责
 bug是你的过错还是别人的过错,并不是真的很有关系。它仍然是你的问题。

最容易欺骗的人是一个人自己。
  ——Edward Bulwer-Lytton, The Disowned
在你开始调试之前,选择恰当的思维方式十分重要。你须要关闭每天用于保护自我(ego)的许多防卫措施,
忘掉你可能面临的任何项目压力,并让自己放松下来。最重要的是,记住调试的第一准则:

提示25
Don’t Panic
不要恐慌

Don’t Assume it – Prove It
不要假定,要证明

 

第25章 分配资源

只要在编程,我们都要管理资源:内存、事务、线程、文件、定时器——所有数量有限的事物。大多数时候,
资源使用遵循一种可预测的模式:你分配资源、使用它,然后解除其分配。
但是,对于资源分配和解除分配的处理,许多开发者没有始终如一的计划。所以让我们提出一个简单的提示:
提示35
Finish What You Start
要有始有终

分享到:
评论

相关推荐

    程序员的思维修炼_中文版.pdf

    该书非常不错,对程序员的整个思维体系进行了一个总结。

    C 语言嵌入式系统编程修炼之道——宋宝华.pdf

    总结来说,C语言嵌入式系统编程修炼之道涉及了从基础的软件架构设计、内存操作,到具体的用户界面交互处理,以及性能优化的各个方面。一个成功的嵌入式系统开发者需要掌握这些核心技能,并且能够根据具体的硬件平台...

    安全编程修炼之道

    《安全编程修炼之道》这本书是指导开发者如何在C语言编程中实现安全性的权威指南。C语言因其高效和灵活性被广泛应用于系统级编程和嵌入式领域,但同时也因其内存管理和类型系统的特性,容易引发安全问题。本文将深入...

    c语言嵌入式系统编程修炼之道

    总结,《C语言嵌入式系统编程修炼之道》这本书可能会涵盖以上所有内容,旨在帮助读者从基础知识到高级技巧,全面掌握C语言在嵌入式领域的应用。通过学习,开发者可以具备设计、实现和维护复杂嵌入式系统的能力,为...

    一个程序员该读那些书

    2. 《程序员修炼之道》(Andrew Hunt 和David Thomas) 这本书适合已经学习过编程机制的程序员,旨在帮助他们在职业生涯中成长和发展。书中涵盖了个人责任、职业发展、代码架构技术等多方面的主题。 3. 《计算机...

    Practices of an Agile Developer 中文版 敏捷开发修炼之道

     本书简明实用、见解深刻,总结了高效程序员在开发过程中的45个个人习惯、思想观念和方法,有助于开发人员在开发进程、编码工作、开发者态度、项目和团队管理,以及持续学习等5个方面积极修炼。通过学习这些内容,...

    C语言嵌入式系统编程修炼之道-笔记2.pdf

    总结: 在C语言嵌入式系统编程中,对内存的精细控制、函数指针的使用、动态内存管理的严谨性以及const和volatile的正确应用,都是提高代码质量、防止错误和提高系统稳定性的关键。理解并熟练运用这些概念,能帮助...

    程序员成长路线图1-2章

    第二章:从新手到专家的进阶之道 2.1 项目经验:参与实际项目能提升实践能力,从简单的个人项目到复杂的团队合作,每一次经验都能带来新的收获。 2.2 代码质量:注重代码的可读性、可维护性和性能优化。编写易于...

    C语言嵌入式系统编程修炼之道(二)参考.pdf

    C语言允许程序员直接操作内存,通过指针变量指向特定的内存地址。例如,`unsigned char *p = (unsigned char *)0xF000FF00; *p=11;` 这行代码会将数值11写入地址0xF000FF00。在处理I/O芯片、双端口RAM通信或读取ROM...

    一个程序员五年学习观.doc

    一个程序员五年学习观 本文是对一个程序员五年学习观的总结...* 《卓有成效的管理者(典藏版)》、《管理的实践(珍藏版)》、《高效程序员的 45 个习惯:敏捷开发修炼之道》等书籍可以帮助程序员学习管理类的知识点。

    PHP-Interview:分享和记录常见的php面试题和面试技巧

    设计模式说说你对设计模式中的模板模式的理解吧系统架构软技能程序员修炼之路:你该知道的 7 个必经阶段为什么写这个常言道,好记性,不如烂笔头,在笔者几次面试的过程中,总会遇到一些常见的问题,特此记录下来,...

    软件工程开发项目管理类书目.pdf

    软件工程开发项目管理类书目.pdf 中包含了四本书的信息,分别是《软件调试实战》、《高效程序员的45个习惯:敏捷开发修炼之道》、《软件测试项目实战:技术、流程与管理》和《完美代码》。下面将对每本书的内容进行...

    阿里技术精选--不止代码(codelife)

    此外,文章中还提到了一些有助于技术成长的其他话题,比如如何在阿里技术面试中脱颖而出、如何正确使用开源项目、前端工程师的职业发展、架构师的修炼之道以及值得反复阅读的技术书籍推荐等。 从李运华的总结中我们...

    leetcode题库-LeetCode:该仓库为数据结构与算法专题,题目均来自leetcode,里面有每道题的解题过程,以及一些解题思路

    《深入探索LeetCode:数据...通过实际操练,不仅可以巩固理论知识,还能锻炼解决问题的思维能力和编程技巧,是程序员“内功”的重要修炼途径。不断挑战LeetCode的题目,可以让我们在面对复杂编程问题时更加游刃有余。

    嵌入式C精华.pdf

    #### 从两道经典试题谈C/C++中联合体(union)的使用 - **联合体概念**:`union`允许在同一个内存位置存储不同类型的数据,这对于内存管理和资源节约非常重要。 - **应用案例**:详细解析了如何使用`union`来实现...

Global site tag (gtag.js) - Google Analytics