程序员修炼之道

程序员心底的小声音

如果要成为一个好程序员,其实所需要的道理也多不了多少,只不过,当水平不够的时候,永远不能认识到那些朴素道理的重要。

经验这个东西,往往并不能告诉我们什么一定对,但是可以告诉我们什么一定不对。

注重实效的程序员应该不断学习。能不能让正确的原则指导正确的行动本身,其实就是区分是否是高手的一个显著标志。

我们常常会“忘了”应该怎么正确地做一件事情(这个地方的“忘了”,指我们之前从书中或其他渠道读到看到了正确的原则或方法,但是在那一刻脑子里根本没考虑这个原则或方法,因为这个原则或方法根本没有亲自实践过,所以根本不是自己的一部分,不属于自己)。

想要内化这些小声音,还是要靠实践,如果不实践,即使你把这些小声音写在100块钱的高档笔记本上也没有用。

理想的阅读状态应该是先大致理解和记住里面的提示,然后每周争取实践2~3个提示。其实这样做完一圈也就是半年,在这一圈后就会记住所有的提示的内容,这时候,小声音就成了自己的一部分了。

事实上,每一个提示只是一句话而已,对这一句话的理解层次,则完全不是这一句话能够覆盖的。

编程是一种技艺,一种需要用心学习的技艺。编程是一项充满了各种细节的工作,追踪这些细节需要专注。

如何做的更好?答案是他们在做某件事情时,会把注意力投注在他们在做的事情上——然后他们会试着把它做得更好。

模式就是解决方案,而模式语言就是相互支援的若干解决方案的系统。

编程是一种技艺。用最简单的话表述,编程可归结为让计算机做你想要它做的事情。

注重实效的哲学

注重实效的程序员的特征是什么?我们觉得是他们处理问题、寻求解决方案时的态度、风格、哲学。他们能够越出直接的问题去思考,总是设法把问题放在更大的语境中,总是设法注意更大的图景。

注重实效的程序员不会坐视他们的项目土崩瓦解。

大多数人发现自己很难接受变化,有时是出于好的理由,有时只是因为固有的惰性。你需要拥有广泛的知识和经验基础才能赢得这一切。学习是一个持续不断的过程。

注重实效的编程源于注重实效的思考的哲学。

我的源码让猫给吃了

在所有弱点中,最大的弱点就是害怕暴露弱点。注重实效的程序员对他或她自己的职业生涯负责,并且不害怕承认无知或错误。

如果你确实同意要为某个结果负责,你就应切实负起责任。当你犯错误(就如同我们所有人都会犯错误一样)、或是判断失误时,诚实地承认它,并设法给出各种选择。不要责备别人或别的东西,或是拼凑借口。不要把所有问题都归咎于供应商、编程语言、管理部门、或是你的同事。

在你的头脑里把谈话预演一遍。其他人可能会说什么?他们是否会问:“你试了这个吗……”,或是“你没有考虑那个吗?”你将怎样回答?在你去告诉他们坏消息之前,是否还有其他你可以再试一试的办法?有时,你其实知道他们会说什么,所以还是不要给他们添麻烦吧。

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

不要害怕提出要求,也不要害怕承认你需要帮助。

在你大声说出它们之前,先设法把蹩脚的借口清除出去。如果你必须说,就先对你的猫说。

软件的熵

熵是一个来自物理学的概念,指的是某个系统中的“无序”的总量。遗憾的是,热力学定律保证了宇宙中的熵倾向于最大化。当软件中的无序增长时,程序员们称之为“软件腐烂”。

“破窗户理论”启发了纽约和其他大城市的警察部门,他们对一些轻微的案件严加处理,以防止大案的发生。这起了作用:管束破窗户、乱涂乱画和其他轻微违法事件减少了严重罪案的发生。不要容忍破窗户。

发现一个就修一个。如果没有足够的时间进行适当的修理,就用木板把它钉起来。或许你可以把出问题的代码放入注释,或是显示“未实现”消息,或是用虚设的数据加以替代。

如果你发现你所在团队和项目的代码十分漂亮——编写整洁、设计良好,并且很优雅——你就很可能会格外注意不去把它弄脏。

你能否说出某扇窗户是何时破的?你的反应是什么?如果它是他人的决策所致,或者是管理部门的指示,你能做些什么?

石头汤与煮青蛙

设计出你可以合理要求的东西,好好开发它。一旦完成,就拿给大家看,让他们大吃一惊。然后说:“要是我们增加……可能就会更好。”假装那并不重要。坐回椅子上,等着他们开始要你增加你本来就想要的功能。人们发现,参与正在发生的成功要更容易。让他们瞥见未来,你就能让他们聚集在你周围。

做变化的催化剂。常常是小事情的累积破坏了士气和团队。记住大图景。

不要像青蛙一样。留心大图景。要持续不断地观察周围发生的事情,而不只是你自己在做的事情。

足够好的软件

你可以训练你自己,编写出足够好的软件。对你的用户、对未来的维护者、对你自己内心的安宁来说足够好。

我们只是在宣扬,应该给用户以机会,让他们参与决定你所制作的东西何时已足够好。

许诺不可能兑现的时间标度,为赶上最后期限而削减基本的工程内容,这些同样不是有职业素养的做法。

你所制作的系统的范围和质量应该作为系统需求的一部分规定下来。

如果你给用户某样东西,让他们及早使用,他们的反馈常常会把你引向更好的最终解决方案。

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

你的知识资产

知识上的投资总能得到最好的回报。你的知识和经验是你最重要的职业财富。

管理知识资产与管理金融资产非常相似:

  • 严肃的投资者定期投资——作为习惯。

  • 多元化是长期成功的关键。

  • 聪明的投资者在保守的投资和高风险、高回报的投资之间平衡他们的资产。

  • 投资者设法低买高卖,以获取最大回报。

  • 应周期性地重新评估和平衡资产。

要在职业生涯中获得成功,你必须运用同样的指导方针管理你的知识资产。

计算技术的面貌变化很快——今天的热门技术明天就可能变得近乎无用。你掌握的技术越多,你就越能更好地进行调整,赶上变化。

定期为你的知识资产投资。每年至少学习一种新语言。也要阅读非技术书籍。记住计算机是由人,你在设法满足其需要的人使用的,这十分重要。不要忘了等式中人这一边。

不要就此止步,把找到答案视为对你个人的挑战。如果你自己找不到答案,就去找出能找到答案的人。不要把问题搁在那里。与他人交谈可以帮助你建立人际网络,而因为在这个过程中找到了其他不相关问题的解决方案,你也许还会让自己大吃一惊。

所有阅读和研究都需要时间,而时间已经很短缺。所以你需要预先规划。让自己在空闲的片刻时间里总有东西可读。

批判地思考你读到的和听到的。你需要确保你的资产中的知识是准确的,并且没有受到供应商或媒体炒作的影响。警惕声称他们的信条提供了唯一答案的狂热者——那或许适用、或许不适用于你和你的项目。

批判地分析你读到的和听到的

  • 确切地知道你想要问什么,并尽量明确具体。

  • 小心而得体地组织你的问题。记住你是在请求帮助;不要显得好像是在要求对方回答。

  • 组织好问题之后,停下来,再找找答案。选出一些关键字,搜索Web。查找适当的FAQ (常见问题的解答列表)。

  • 决定你是想公开提问还是私下提问。

如果你在进行非常详细的实现和编码,就阅读关于设计和架构的书。如果你在进行高级设计,就阅读关于编码技术的书。

交流

我相信,被打量比被忽略要好。

规划你想要说的东西。写出大纲。然后问你自己:“这是否讲清了我要说的所有内容?”提炼它,直到确实如此为止。

只有当你是在传达信息时,你才是在交流。为此,你需要了解你的听众的需要、兴趣、能力。

要在脑海里形成一幅明确的关于你的听众的画面。了解听众、选择时机。

为了了解你的听众需要听到什么,你需要弄清楚他们的“轻重缓急”是什么。

要记住,你也是交流事务的一方。如果有人说,他们需要你用一段话进行描述,而你觉得不用若干页纸就无法做到,如实告诉他们。记住,这样的反馈也是交流的一种形式。

太多程序员在制作书面文档时只关心内容。我们认为这是一个错误。任何一个厨师都会告诉你,你可以在厨房里忙碌几个小时,最后却会因为饭菜糟糕的外观而毁掉你的努力。

如果你想要大家听你说话,你必须使用一种方法:听他们说话。

鼓励大家通过提问来交谈,或是让他们总结你告诉他们的东西。把会议变成对话,你将能更有效地阐明你的观点。

你应该总是对电子邮件和语音邮件做出回应,即使内容只是“我稍后回复你。”随时通知别人,会让他们更容易原谅你偶然的疏忽,并让他们觉得你没有忘记他们。

你说什么和你怎么说同样重要。知道你想要说什么。了解你的听众。选择时机。选择风格。让文档美观。让听众参与。做倾听者。回复他人。

注重实效的途径

我们都是在一个时间和资源有限的世界上工作。如果你善于估计出事情需要多长时间完成,你就能更好地在两者都很匮乏的情况下生存下去。

重复的危害

作为程序员,我们收集、组织、维护和利用知识。我们在规范中记载知识、在运行的代码中使其活跃起来并将其用于提供测试过程中所需的检查。

所有这些不稳定都意味着我们要把很大一部分时间花在维护上,重新组织和表达我们的系统中的知识。

不管原因是什么,维护都不是时有时无的活动,而是整个开发过程中的例行事务。

问题是,在我们开发的规范、过程和程序中很容易重复表述知识,而当我们这样做时,我们是在向维护的噩梦发出邀请。

我们称之为DRY的原则:系统中的每一项知识都必须具有单一、无歧义、权威的表示。

强加的重复。开发者觉得他们无可选择,环境似乎要求重复。

无意的重复。开发者没有意识到他们在重复信息。

无耐性的重复。开发者偷懒,他们重复,因为那样似乎更容易。

开发者之间的重复。同一团队的几个人重复了同样的信息。

DRY法则告诉我们,要把低级的知识放在代码中,它属于那里;把注释保留给其他的高级说明。

在可能的情况下,应该总是用访问器函数读写对象的属性。这将使未来增加功能变得更容易。

每个项目都有时间压力——这是能够驱使我们中间最优秀的人走捷径的力量。

无耐性的重复是一种容易检测和处理的重复形式,但那需要你接受训练,并愿意为避免以后的痛苦而预先花一些时间。

一定要阅读他人的源码与文档,不管是非正式的,还是进行代码复查。

正交性

这两条直线互不依赖。沿着某一条直线移动,你投影到另一条直线上的位置不变。

在计算技术中,该术语用于表示某种不相依赖性或是解耦性。如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。

非正交系统的改变与控制更复杂是其固有的性质。当任何系统的各组件互相高度依赖时,就不再有局部修正这样的事情。

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

正交的途径还能够促进复用。如果组件具有明确而具体的、良好定义的责任,就可以用其最初的实现者未曾想象过的方式,把它们与新组件组合在一起。

假定某个组件做M件事情,而另一个组件做N件事情。如果它们是正交的,而你把它们组合在一起,结果就能做M×N件事情。但是,如果这两个组件是非正交的,它们就会重叠,结果能做的事情就更少。通过组合正交的组件,你的每一份努力都能得到更多的功能。

你可以对项目团队的正交性进行非正式的衡量。只要看一看,在讨论每个所需改动时需要涉及多少人。人数越多,团队的正交性就越差。显然,正交的团队效率也更高。

系统应该由一组相互协作的模块组成,每个模块都实现不依赖于其他模块的功能。

对于正交设计,有一种简单的测试方法。一旦设计好组件,问问你自己:如果我显著地改变某个特定功能背后的需求,有多少模块会受影响?在正交系统中,答案应该是“一个”。

你在把电话号码当作顾客标识符吗?如果电话公司重新分配了区号,会怎么样?不要依赖你无法控制的事物属性。

在引入某个工具箱时,问问你自己,它是否会迫使你对代码进行不必要的改动。

每次你编写代码,都有降低应用正交性的风险。除非你不仅时刻监视你正在做的事情,也时刻监视应用的更大语境,否则,你就有可能无意中重复其他模块的功能,或是两次表示已有的知识。

避免使用全局数据。避免编写相似的函数。

养成不断地批判对待自己的代码的习惯。寻找任何重新进行组织、以改善其结构和正交性的机会。这个过程叫做重构。

我们建议让每个模块都拥有自己的、内建在代码中的单元测试,并让这些测试作为常规构建过程的一部分自动运行。

构建单元测试本身是对正交性的一项有趣测试。

你是否只改动了一个模块,或者改动分散在整个系统的各个地方?

运用DRY原则,你是在寻求使系统中的重复降至最小;运用正交性原则,你可降低系统的各组件间的相互依赖。

可撤消性

如果某个想法是你唯一的想法,再没有什么比这更危险的事情了。

要实现某种东西,总有不止一种方式,而且通常有不止一家供应商可以提供第三方产品。如果你参与的项目被短视的、认为只有一种实现方式的观念所牵绊,你也许就会遇到让人不悦的意外之事。许多项目团队会被迫在未来展现之时睁开眼睛。

问题在于,关键决策不容易撤消。

但如果你真的已经把数据库的概念抽象出来——抽象到数据库只是把持久作为服务提供出来的程度——你就会拥有“中流换马”的灵活性。

要把决策视为是写在沙滩上的,而不要把它们刻在石头上。大浪随时可能到来,把它们抹去。

如果在代码中有着糟糕的封装、高度耦合以及硬编码的逻辑或参数,事情也许就是不可能的。

预先考虑这个问题,你可以支持单机、客户-服务器、或n层模型——只需要改变配置文件。

没有人知道未来会怎样,尤其是我们!所以要让你的代码学会“摇滚”:可以“摇”就“摇”,必须“滚”就“滚”。

代码沿着与装满薛定谔的猫的盒子一样的路线演化:每一项决策都会导致不同版本的未来。你的代码能支持多少种可能的未来?哪一种未来更有可能发生?到时支持它们有多困难?

曳光弹

为了在代码中获得同样的效果,我们要找到某种东西,让我们能快速、直观和可重复地从需求出发,满足最终系统的某个方面要求。

曳光代码并非用过就扔的代码:你编写它,是为了保留它。它含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查。它只不过功能不全而已。

曳光弹告诉你击中的是什么。那不一定总是目标。于是你调整准星,直到完全击中目标为止。这正是要点所在。

一段代码的惯性也小——要改变它更容易、更迅速。

曳光代码方法处理的是不同的问题。你需要知道应用怎样结合成一个整体。你想要向用户演示,实际的交互是怎样工作的,同时你还想要给出一个架构骨架,开发者可以在其上增加代码

一旦你把应用中的所有组件都组合在一起,你就拥有了一个可以向你的用户和开发者演示的框架。

原型制作生成用过就扔的代码。曳光代码虽然简约,但却是完整的,并且构成了最终系统的骨架的一部分。

原型与便笺

原型的设计目的就是回答一些问题,所以与投入使用的产品应用相比,它们的开发要便宜得多、快捷得多。

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

原型应该遮盖细节,并聚焦于所考虑系统的某些具体方面,你可以用非常高级的语言实现原型。

领域语言

语言的界限就是一个人的世界的界限。

计算机语言会影响你思考问题的方式,以及你看待交流的方式。

在某些情况下,我们可以更进一层,采用领域的语汇、语法、语义、语言、实际进行编程。

考虑到大多数应用都会超过预期的使用期限,你可能最好咬紧牙关,先就采用更复杂、可读性更好的语言。

估算

通过学习估算,并将此技能发展到你对事物的数量级有直觉的程度,你就能展现出一种魔法般的能力,确定它们的可行性。

去问已经做过这件事情的人。在你一头钻进建模之前,仔细在周围找找也曾处在类似情况下的人。

任何估算练习的第一步都是建立对提问内容的理解。除了上面讨论的精确度问题以外,你还需要把握问题域的范围。

检查需求 分析风险 设计、实现、集成 向用户确认。

基本工具

工具放大你的才干。你的工具越好,你越是能更好地掌握它们的用法,你的生产力就越高。

花时间学习使用这些工具,有一天你将会惊奇地发现,你的手指在键盘上移动,操纵文本,却不用进行有意识的思考。工具将变成你的双手的延伸。

提供“锋利”的小工具、其中每一样都意在把一件事情做好——Unix因围绕这样的哲学进行设计而著称。

GUI的好处是所见即所得。缺点是所见即全部所得。

我们认为你最好是精通一种编辑器,并将其用于所有编辑任务:代码、文档、备忘录、系统管理,等等。

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

调试

这是痛苦的事:看着你自己的烦忧,并且知道不是别人、而是你自己一人所致。

要接受事实:调试就是解决问题,要据此发起进攻。

在技术竞技场上,你应该专注于修正问题,而不是发出指责。

最容易欺骗的人是一个人自己。

如果你目睹bug或见到bug报告时的第一反应是“那不可能”,你就完全错了。一个脑细胞都不要浪费在以“但那不可能发生”起头的思路上,因为很明显,那不仅可能,而且已经发生了。

在调试时小心“近视”。要抵制只修正你看到的症状的急迫愿望:更有可能的情况是,实际的故障离你正在观察的地方可能还有几步远,并且可能涉及许多其他的相关事物。要总是设法找出问题的根源,而不只是问题的特定表现。

在开始查看bug之前,要确保你是在能够成功编译的代码上工作——没有警告。

你也许需要与报告bug的用户面谈,以搜集比最初给你的数据更多的数据。

一旦你认为你知道了在发生什么,就到了找出程序认为在发生什么的时候了。

开始修正bug的最佳途径是让其可再现。毕竟,如果你不能再现它,你又怎么知道它已经被修正了呢?

找到问题的原因的一种非常简单、却又特别有用的技术是向别人解释它。你只是一步步解释代码要做什么,常常就能让问题从屏幕上跳出来,宣布自己的存在。

bug有可能存在于OS、编译器、或是第三方产品中。但这不应该是你的第一想法。有大得多的可能性的是,bug存在于正在开发的应用代码中。

你总是可以依靠好用的老式二分查找。不要假定,要证明。

在你对其进行处理的同时,代码中是否有任何其他地方容易受这同一个bug的影响?现在就是找出并修正它们的时机。确保无论发生什么,你都知道它是否会再次发生。

如果修正这个bug需要很长时间,问问你自己为什么。你是否可以做点什么,让下一次修正这个bug变得更容易?也许你可以内建更好的测试挂钩,或是编写日志文件分析器。

代码生成器

工具带走了复杂性,降低了出错的机会,从而让工匠能够自由地专注于质量问题。程序员可以构建代码生成器。一旦构建好,在整个项目生命期内都可以使用它,实际上没有任何代价。

无论何时你发现自己在设法让两种完全不同的环境一起工作,你都应该考虑使用主动代码生成器。

注重实效的偏执

你不可能写出完美的软件。

注重实效的程序员知道没有人能编写完美的代码,包括自己,所以注重实效的程序员针对自己的错误进行防卫性的编码。

“断言式编程”描述了一种沿途进行检查的轻松方法——编写主动校验你的假定的代码。

合约既规定你的权利与责任,也规定对方的权利与责任。

什么是正确的程序?不多不少,做它声明要做的事情的程序。用文档记载这样的声明,并进行校验,是按合约设计的核心所在。

死程序不说谎

我们很容易掉进“它不可能发生”这样一种心理状态。我们中的大多数人编写的代码都不检查文件是否能成功关闭,或者某个跟踪语句是否已按照我们的预期写出。

注重实效的程序员告诉自己,如果有一个错误,就说明非常、非常糟糕的事情已经发生了。

早崩溃 要崩溃,不要破坏。Java语言和库已经采用了这一哲学。当意料之外的某件事情在运行系统中发生时,它会抛出运行异常。如果没有被捕捉,这个异常就会渗透到程序的顶部,致使其中止,并显示栈踪迹。

死程序带来的危害通常比有疾患的程序要小得多。

断言式编程

在自责中有一种满足感。当我们责备自己时,会觉得再没人有权责备我们。

如果它不可能发生,用断言确保它不会发生。不要用断言代替真正的错误处理。断言检查的是决不应该发生的事情。

如果你需要释放资源,就让断言失败生成异常、跳到某个退出点、或是调用错误处理器。要确保你在终止前的几毫秒内执行的代码不依赖最初触发断言失败的信息。

你的第一条防线是检查任何可能的错误,第二条防线是使用断言设法检测你疏漏的错误。

问问你自己:“如果我移走所有的异常处理器,这些代码是否仍然能运行?”如果答案是“否”,那么异常也许就正在被用在非异常的情形中。

  • 以与资源分配的次序相反的次序解除资源的分配。这样,如果一个资源含有对另一个资源的引用,你就不会造成资源被遗弃。

  • 在代码的不同地方分配同一组资源时,总是以相同的次序分配它们。这将降低发生死锁的可能性。

弯曲,或折断

保持灵活的一种好办法是少写代码。改动代码会使你引入新bug的可能性增大。“元程序设计”将解释怎样把各种细节完全移出代码,那样就可以更安全、更容易地改动它们。

把你的代码组织成最小组织单位,并限制它们之间的交互。如果随后出于折中必须替换某个模块,其他模块仍能够继续工作。

假定你在改建你的房子,或是从头修建一所房子。典型的安排涉及到找一位“总承包人”。你雇用承包人来完成工作,但承包人可能会、也可能不会亲自进行建造;他可能会把工作分包给好几个子承包人。但作为客户,你不用直接与这些子承包人打交道——总承包人会替你承担那些让人头疼的事情。

对象间直接的横贯关系有可能很快带来依赖关系的组合爆炸。

将抽象放进代码,细节放进元数据。

考虑一下你的应用的使用方式:如果它是长期运行的服务器进程,你可以提供某种途径,在程序运行的过程中重新读取并应用元数据。

时间有两个方面对我们很重要:并发和次序。

分析工作流,以改善并发性,总是为并发进行设计。

很早以前我们就被教导说,不要把程序写成一个大块,而应该“分而治之”,把程序划分成模块。每个模块都有其自身的责任;事实上,模块的一个好定义就是,它具有单一的、定义良好的责任。

用事件把某个对象的状态变化通知给可能感兴趣的其他对象。发布/订阅协议。

靠巧合编程

我们应该避免靠巧合编程——依靠运气和偶然的成功——而要深思熟虑地编程。

没有记入文档的行为可能会随着库的下一次发布而变化。

在所有层面上,人们都在头脑里带着许多假定工作——但这些假定很少被记入文档,而且在不同的开发者之间常常是冲突的。并非以明确的事实为基础的假定是所有项目的祸害。

总是意识到你在做什么。不要盲目地编程。试图构建你不完全理解的应用,或是使用你不熟悉的技术,就是希望自己被巧合误导。

为你的假定建立文档。“按合约设计”有助于澄清你头脑中的假定,并且有助于把它们传达给别人。

不要猜测;要实际尝试它。编写断言测试你的假定。

为你的工作划分优先级。

所以下次有什么东西看起来能工作,而你却不知道为什么,要确定它不是巧合。

重构

随着程序的演化,我们有必要重新思考早先的决策,并重写部分代码。这一过程非常自然。代码需要演化;它不是静态的事物。

重写、重做和重新架构代码合起来,称为重构。

不要对改动犹豫不决。应该现在就做。

时间压力常常被用作不进行重构的借口。但这个借口并不成立:现在没能进行重构,沿途修正问题将需要投入多得多的时间。早重构,常重构。

不要试图在重构的同时增加功能。在开始重构之前,确保你拥有良好的测试。尽可能经常运行这些测试。这样,如果你的改动 破坏了任何东西,你就能很快知道。

易于测试的代码

我们想要编写测试用例,确保给定的单元遵守其合约。这将告诉我们两件事情:代码是否符合合约,以及合约的含义是否与我们所认为的一样。

  • 一些例子,说明怎样使用你的模块的所有功能。

  • 用以构建回归测试、以验证未来对代码的任何改动是否正确的一种手段。

因为我们通常都会编写大量测试代码,并进行大量测试,我们要让自己的生活容易一点,为项目开发标准的测试装备。

含有跟踪消息的日志文件就是这样一种机制。日志消息的格式应该正规、一致。

测试你的软件,否则你的用户就得测试。

需求之坑

完美,不是在没有什么需要增加、而是在没有什么需要去掉时达到的。

需求是对需要完成的某件事情的陈述。如果陈述是“只有得到授权的用户可以访问员工档案”,开发者就可能会设计并实现某种访问控制系统。找出用户为何要做特定事情的原因、而不只是他们目前做这件事情的方式,这很重要。

与用户一同工作,以像用户一样思考。

管理需求增长的关键是向项目出资人指出每项新特性对项目进度的影响。

你必须挑战任何先入之见,并评估它们是否是真实的、必须遵守的约束。

不要在盒子外面思考——要找到盒子。

倾听反复出现的疑虑——等你准备好再开始。

我们采用的一种行之有效的技术是开始构建原型。选择一个你觉得会有困难的地方,开始进行某种“概念验证“。

编写规范是一项重要职责。

注重实效的团队

使项目级活动保持一致和可靠的一个最重要的因素是使你的各种工作流程自动化。我们鼓励你在作品上签名,并为你所做的事情而自豪。

团队必须为产品的质量负责,支持那些了解我们在“软件的熵”中描述的“不要留破窗户”哲学的开发者,并鼓励那些还不了解这种哲学的人。

项目至少需要两个“头”——一个主管技术,另一个主管行政。技术主管设定开发哲学和风格,给各团队指派责任,并仲裁成员之间不可避免的“讨论”。技术主管还要不断关注大图景,设法找出团队之间任何不必要的、可能降低总体正交性的交叉。行政主管调度各团队所需的各种资源,监视并报告进展情况,并根据商业需要帮助确定各种优先级。在与外界交流时,行政主管还要充当团队的大使。

为了确保事情得以自动化,指定一个或多个团队成员担任工具构建员,构造和部署使项目中的苦差事自动化的工具。让它们制作makefile、shell脚本、编辑器模板、实用程序,等等。

我们想要确保项目的一致性和可重复性。人工流程不能保证一致性,也无法保证可重复性,特别是在不同的人对流程的各个方面有不同解释时。

无情的测试

早测试,常测试,自动测试。

bug被发现得越早,进行修补的成本就越低。“编一点,测一点”是Smalltalk世界里流行的一句话。

要到通过全部测试,编码才算完成。我们须要查看项目范围测试的三个主要方面:测试什么、怎样测试,以及何时测试。

问问你自己,软件是否能满足现实世界的条件下的性能需求——预期的用户数、连接数、或每秒事务数。它可以伸缩吗?

数据只有两种:现实世界的数据和合成的数据。

在你编写了一个测试、用以检测特定的bug时,要故意引发bug,并确定测试会发出提示。这可以确保测试在bug真的出现时抓住它。

许多项目往往会把测试留到最后一分钟——最后期限马上就要来临时。我们需要比这早得多地开始测试。任何产品代码一旦存在,就需要进行测试。

全都是写

把英语当作又一种编程语言。

注释应该讨论为何要做某事、它的目的和目标。代码已经说明了它是怎样完成的,所以再为此加上注释是多余的——而且违反了DRY原则。

匈牙利表示法(即把变量的类型信息放在变量名自身里)在面向对象系统中绝对不合适。

记住,你会好几百次地阅读代码,但却只编写几次。花时间拼写出connectionPool,而不要只用cp。

有时要为源码的设计建立文档并不让人舒服,因为设计在你的头脑中还不清晰;它仍然在演变。你觉得在它实际完成之前,你不应该浪费精力去描述它。这听起来像是靠巧合编程。
原文链接:程序员修炼之道

写的不好,就当是整理下思绪吧。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

读完了,不要靠巧合编程、石头汤与煮青蛙、交流,都很有感触。毕业前看类似文章 读不进去。现在可以了

1个月前 评论
一句话儿 (楼主) 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!