本书将告诉你怎样以一种你可以遵循的方式去编程。程序员
Pragmatic:注重实效的程序员不只仅要完成工做,并且要干得漂亮。他们应有的特征:早期的采纳者和快速的改编者、好奇、批判的思考者、有现实感、多才多艺。算法
关心你的技艺。shell
思考!你的工做数据库
软件的构造是工程学科,可是不排斥我的的技艺。编程
注重失效的程序员的特征是什么,是他们处理问题、寻求解决方案的态度、风格、哲学。他们可以越出直接的问题进行思考,老是设法把问题放到更大的语境下,老是设法注意更大的图景。他们成功的另外一关键是他们对本身所作的每件事都负责。他们不会坐视本身的项目瓦解,努力使它保持整洁。架构
在全部弱点中,最大的弱点就是惧怕暴露弱点。你要负责,不能惧怕认可无知和错误。你要作的,就是提供各类选择,而不是找蹩脚的借口。并发
开发软件时的内心也多是很是微妙的事情。不能容忍破窗户,发现一个,修补一个,若是你没有足够的时间进行适当的修理,那么就用木板把它钉起来。或许你能够把出问题的代码放入注释,活着显示“未实现”消息,或是用虚设的数据加以代替。采起某种行动防止进一步的损坏,说明形势在你的控制之下。编程语言
不要惧怕破坏代码,勇于进行适当的修改。编辑器
设计出你能够合理要求的东西,好好开发它,一旦完成,就拿给你们看,让他们大吃一惊,而后说“要是加入。。。。可能更好。”要作变化的催化剂。模块化
记住大图景!要持续不断地观察周围发生的变化,而不仅是你在作的事情。
什么才是足够好,对你的用户、将来的维护者、对你的心里来讲足够好。让你的用户参与权衡。
使质量成为需求问题。
不要过分修饰和过于求精而损毁往好的程序,不可能完美。
知识资产须要按期投资,多元化投资,投资者要设法低买高卖,以获取最大回报。程序员要学会经营本身的资产。建议性的目标:每一年至少学习一种新语言、每季度阅读一本技术书籍、也要阅读非技术书籍、上课、参加本地用户组织、试验不一样的环境、跟上潮流、上网。学习的机会千千万,读书、请教他人。最最重要的,要学会批判性的思考。
知道你要说什么、了解你的听众(他们要什么,他们经验丰富么,如何让他们参与进来)、选择合适的时机、合适的风格、试图让你的文档更加美观、让听众参与进来、作一个好的倾听者、善意的回复他人。
不要重复你本身。系统中的每一项知识都必须是具备单1、无歧义、权威的表示。
l 强加的重复:无可选择,环境彷佛要求重复。把低级的知识放在代码中,把注释保留给高级说明。
l 无心的重复:开发者没有意识到本身在重复,使影响局部化。
l 无耐性的重复:偷懒,欲速则不达。
l 开发者之间的重复:多交流,让复用变得容易。
正交性表示某种不相依赖性活着解耦性。不要把任何一项知识分散在多个系统组件之中,消除无关事物之间的影响。
咱们想要设计自足的组件:独立,具备单一的、良好定义的目的和Constantine称之为内聚。正交的两个好处:提升生产率与下降风险。
项目团队要划分为责任获得良好定义的小组,使重叠性降至最低。
设计的正交:模块化、基于组件或是分层,模块之间的依赖性降至最低。
为了保持系统的正交性,要明智地选择工具箱和类库。在引入一个工具前,要想想它带来了哪些改变。
若干编码技术用于维持正交性:让你的代码保持解耦,避免使用全局数据、避免编写相似的函数。
测试:正交的系统更易于测试的执行。
文档:对于真正正交的文档,应该能显著地改变其外观,而不用改变其内容。
不存在最终的决策,要选用灵活的架构,适应未来的变化。
经典的作法是将系统做死,制做大量文档,逐一列出没想需求,肯定全部的未知元素,限定环境。根据死的计算射击,预先进行一次大量计算,而后设计并企望击中目标。
或者,你可使用曳光弹,它可使得枪手获得即时的反馈。曳光代码并不是用过就扔,你编写它,是为了保留它。曳光开发与项目永不结束的理念是一致的:总有改动要完成,这是一个渐进的过程。
另外一种传统作法是划分模块,编写模块代码,模块组成子配件,子配件组成系统。。。
曳光代码可让用户早些看到能工做的东西,你有了一个集成平台,能够演示的东西,可以感受到本身的进展。
曳光代码 VS 原型制做:原型要扔到,从新编码。曳光代码是一个架构骨骼。能够把原型制做视为第一发曳光弹发射以前进行的侦查和情报搜集工做。
为了学习,而制做原型。
应制做原型的事物: 构架 已有系统的新功能外部数据的结构或内容 第三方工具或组建 性能问题 用户界面设计。
制做架构原型:用便笺或索引卡片、或在白板上制做原型,推迟考虑细节。在架构原型时需求解答的问题有:主要组件的责任、组件间的协做、耦合最小化、重复的潜在来源、接口定义和约束、模块可否访问所需的数据?
计算机语言会影响你的思考方式。要靠近问题领域进行编程。用你的用户的语言进行设计和编码。
估算的精确程度视项目而定,估算的主要依据是:理解提问内容,创建系统的模型,将模型分解为组件,给每一个参数指定值,计算答案,追踪你的估算能力。
经过代码对进度表进行迭代。
工具是手的延伸,工具能放大你的才干。
纯文本是由可打印字符组成的,人能够直接阅读和理解的形式。它并不意味着文本是无结构的。用纯文本保存知识。纯文本的缺点在于:相比于二进制,它所需空间更多,要解释和处理纯文本的代价更昂贵。
纯文本的好处是保证不过期,杠杆做用,更易于测试。
不要采用GUI,使用shell命令行。
用好一种编辑器,完全了解它,扩展它,将它用于全部的编辑任务。
编辑器的重要特性:可配置,可扩展,可编程(语法突显,自动完成,自动缩进,初始代码或文档样板,与帮助系统链接,类IDE特性-编译调试)
源码控制系统会追踪你在源码和文档中作出的每一项变更,使得你总能返回你的软件的前一版本。它让你能够进行自动的和可重复的产品构建。
调试就是修正问题,而不是发出指责。最最容易欺骗的人是你本身。
不要恐慌!
测试策略:使你的数据可视化、跟踪(查看栈踪影)、向别人解释你的程序。
不要假定,要证实。
当你遇到使人吃惊的bug时,除了只是修正它之外,
l 你还要肯定先前为什么没有找到它,考虑引入单元测试或其它测试,
l 尽早隔离数据,
l 在对bug进行处理时,考虑受它影响的范围,
l 若是修正bug须要很长时间,问问为何,是否能够减小点时间。
l 若是bug是某人错误假定的结果,与整个团队一块儿讨论。
调试检查列表
l 正在报告的问题是底层bug的直接结果仍是症状?
l Bug在编译器里,在os里,或者在你的代码里?
l 向你的同事解释该问题,你会说什么
l 若是可疑代码经过了单元测试,这个测试是否完整
l 产生这个bug的条件是否存在于系统的其余地方?
学会一种文本操纵语言:Python, Perl, Shell, Tcl 。
文本操纵语言的应用实例:数据库Schema维护、Java属性访问、测试数据生成、写书、C与Object Pascal的接口、生成Web文档。
编写能编写代码的代码。
被动代码生成器:只运行一次来产生结果,而后结果就变成独立的了。它们本质上是参数化模版,根据一组输入生成给定的输出形式。
主动代码生成器:每次须要其结果时被使用。取某项知识的一种表示形式,将其转换为你的应用须要的全部形式。
你不可能写出完美的软件。
注重实效的程序员会针对本身的错误进行防卫性编码:按照合约设计,客户与供应者必须就权利和责任达成共识。
软件系统中的每个函数和方法都会作某件事情,在作某事开始以前,例程会对世界的状态有某种指望:前条件、后条件、类不变项。若是调用者知足了例程全部的前条件、那么例程应该保证完成时,全部后条件和不变项将为真。
要早崩溃,但不要破坏。死程序带来的危害比有疾患的程序要小得多。
若是它不可能发生, 那就用断言确保它不会发生。绝对不要把必须执行的代码放入断言之中。
不要用断言代替真正的错误处理,断言检查的是毫不应该发生的事情。
乐观的说法:断言在软件发布以后,再也不须要。
异常不多做为程序的正常流程的一部分使用,应保留给意外事件。
若是你试图打开一个文件进行读取,而该文件不存在,这是异常吗?“取决于实际状况”,若是文件本该在那儿,那就是异常,若是你不清楚该文件是否存在,那就不是异常,要错误返回。
异常表示的是即时的、非局部的控制转移,这是一种级联的goto 。异常若是做为正常处理的一部分,就破坏了封装。
错误处理器是检测到错误时调用的例程。
管理资源遵循一种可预测的模式:分配、使用、解除其分配。要善始善终!
对象间的直接横贯关系可能很快带来依赖关系的组合爆炸。
函数的得墨忒耳法则:某个对象的任何方法都应该只调用属于如下情形的方法
l 它自身
l 传入该方法的任何参数
l 它建立的任何对象
l 任何直接持有的组件对象
为了遵循得墨忒耳法则,可能会编写大量包装方法,把请求转发给被委托者。
把细节赶出代码。把抽象放入代码,细节放进元数据。
要配置,不要集成。
元数据就是关于数据的数据,典型状况下,元数据在运行时、而不是编译时被访问和使用。元数据什么时候进行配置?启动时?运行时?视状况而定。
分析工做流,以改善并发性。
用服务进行设计。
老是为并发进行设计。
把程序分而治之,每一个模块有本身的单一的、定义良好的责任。
发布/订阅:对象应该进行登记,只接收它们须要的事件。
MVC:视图与模型分离。
组织你的黑板,学会利用黑板协调工做流
编码不是机械工做。
不要靠巧合编码,你要深思熟虑为何你的程序能够工做:
l 老是意识到你在作什么
l 不要盲目编程
l 按计划行事
l 依靠可靠的事物
l 为你的假定创建文档
l 不要只是测试你的代码,还要测试你的假定
l 为你的工做划分优先级,把时间花在重要的方面
l 不要作历史的奴隶
算法速率:大O表示法,估算你的算法的阶。
可是最好的并不是老是最好的。
不管代码出现下面哪些特征,都应该考虑重构代码:重复、非正交的设计、过期的知识、性能。
早重构,常重构。
重构时,不要同时增长功能;在开始重构以前,确保你拥有良好的测试,重构过程尽可能采用短小的、深思熟虑的步骤。
单元测试:在隔离状态下,对每一个模块进行测试。
针对合约进行测试,检测先后条件。要为测试而设计。
不要使用你不理解的向导代码。
需求不是搜集来的,而是要去挖掘。要与用户一同工做,以像用户同样思考。
创建需求文档,可是不要规定获取。
要看的远一些,抽象比细节更长久。
维护词汇表,定义项目中使用的专业术语和词汇的地方。
不要在盒子外面思考----要找到盒子
倾听反复出现的疑虑---等你准备好,再开始。
当你没法判断本身是在拖延仍是等待全部工做就绪的时候:构建原型。这是会有两种状况,一种是,开始画不久,你以为本身在浪费时间,好吧,放弃原型,回答真正的开发之中。第二种,随着原型取得进展,你获得启示,意识到有些基本的前提错了,你就会放弃原型,投入正常的项目。
编写程序规范就是把需求归约到程序员可以接管的程度的过程,规范也是与用户的约定。
可是规范不能捕捉需求的每一处细节,语言自身的表达能力也有限,也没有给编码这留下任何解释余地的设计剥夺了他们发挥技巧的权利。
对于有些事情,“作”胜于“描述”。
做为注重实效的程序员,你应该倾向于把需求搜集、设计、以及实现视为同一个过程---教父高质量的系统----的不一样方面。不要信任这样的环境:搜集需求、编写规范、而后编码。这些步骤都是孤立的。
不要作形式化方法的奴隶:形式化结合图和文字来捕捉需求,彷佛鼓励专门化,静态。
昂贵的工具不必定能制做出更好的设计。
不要破坏窗户
温水煮青蛙
交流
不要重复你本身
正交性----围绕功能,而不是工做职务进行组织
自动化
知道什么时候中止:足够好
不要使用手工流程。
早测试,常测试,自动测试
要经过所有测试,编码才算完成:单元测试、集成测试、验证和校验、性能测试、可用性测试。资源耗尽、错误及恢复
测试状态覆盖,而不是代码覆盖。
一个bug只抓一次。
全都是写
把英语做为又一种编程语言
把文档建在里面,不要栓在外面:代码中的注释,包含函数列表,修改历史,文件名。
傲慢与偏见:对你的代码负责。