程序员修炼之道–从小工到专家

第三章 基本工具

  • 工具放大你的才干。你的工具越好,你越是能更好地掌握他们的用法,你的生产力就越高。从一套基本的通用工具开始,随着经验的获得,随着你遇到的一些特殊需求,你将会在其中增添新的工具。要与工匠一样,想着定期增添工具。要总是寻找更好的做事方式。如果你遇到某种情况,你觉得现有的工具不能解决问题,记得去寻找可能会有帮助的其他工具后更强大的工具。
  • 为你自己的基本工具箱投资。

第四章注重实效的偏执

提示30 :你不可能写出完美的软件。

注重实效的程序员针对自己的错误进行防卫性的编码。

21、按合约设计 DBC

如果调用者满足了例程所有前条件,例程应该保证在其完成时、所有后条件和不变项目将为真。

对在开始之前接受的东西要严格,而允许返回的东西要尽可能少。

Liskov替换原则:子类必须要能通过基类的接口使用, 而使用者无须知道其区别。
提示37:要配置,不要集成。

要用元数据描述应用的配置:调谐参数、用户偏好、安装目录,等。

我们的目标是以声明方式思考(规定要做什么,而不是怎么做) ,并创建高度灵活和可适应的程序。我们通过采用一条一般准则来做到这一点:为一般情况编写程序,把具体情况放在别处——在编译的代码库之外。

提示38:将抽象放进代码,细节放进元数据。

提示39:分析工作流,并改善并发性。

提示40:用服务进行设计(Design Using Services)

提示41:总是为并发进行设计。

提示42:使视图与模型分离。

提示43:用黑板协调工作流。


第六章 当你编码时

不主动思考它们的代码的开发者是在靠巧合编程——代码也许能工作,但却没有特别的理由说明他们为何能工作。

31、靠巧合编程

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

  • 实现的偶然
  • 语境的偶然
  • 隐含的假定

怎样深思熟虑地编程?

  • 总是意识到你在做什么。
  • 不要盲目地编程。试图构建你不完全理解的应用,或是使用你不熟悉的技术,就是希望自己被巧合误导。
  • 按照计划行事,不管计划是在你的头脑中,在鸡尾酒餐巾的背面,还是在某个CASE工具生成的强墙那么大的输出结果上。
  • 依靠可靠的事物。不要依靠巧合或假定。如果你无法说出各种特定情形的区别,就假定是最坏的。
  • 为你的假定建立文档。”按合约设计”有助于澄清你头脑中的假定,并且有助于把它们传达给别人。
  • 不要只是测试你的代码,还要测试你的假定。不要猜测;要实际尝试它。编写断言测试你的假定。如果你的断言是对的,你就改善了代码中的文档。如果你发现你的假定是错的,那么就为自己庆幸吧。
  • 为你的工作划分优先级。把时间花在重要的方面;很有可能,它们是最难的部分。如果你的基本原则或基础设施不正确,在花哨的铃声和口哨也是没有用的。
  • 不要做历史的奴隶。不要让已有的代码支配将来的代码。如果不再使用,所有的代码都可被替换。即使是在一个程序中,也不要让你已经做完的事情约束你下一步要做的事情–准备好进行重构。这一决策可能会影响项目的进度。我们的假定是其影响将小于不进行改动造成的影响。

32 算法速率

注重实效的程序员几乎每天都要使用:估算算法使用的资源–时间、处理器、内存,等等。

常识估算:

  • 简单循环
  • 嵌套循环
  • 二分法
  • 分而治之
  • 组合。 启发式方法 heuristics

实践中的算法速率

提示45:估算你的算法的阶

注重实效的程序员会设法既考虑理论问题,又考虑实践问题。

提示46:测试你的估算

code profiler

最好的并非总是最好的


提示47:早重构,常重构(Refactor Early,Refactor Often)

提示48:为测试而设计(Design to Test)

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

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

提示51:不要收集需求——挖掘它们(Don’t Gather Requirements–Dig for Them)

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

提示53:抽象比细节活得更长久(Abstractiongs Live Longer than Details)

提示54:使用项目词汇表(Use a Project Glossary)

  • 要创建并维护项目词汇表(project glossary)——这是定义项目中使用的专业术语和词汇的地方。项目的所有参与者,从最终用户到支持人员,都应该使用这个词汇表,以确保一致性。

提示55:不要在盒子外面思考——要找到盒子(Don’t Think Outside the Box – Find the Box)

在处理问题的时候,问问自己以下的问题:

  • 有更容易的方法吗?
  • 你是在设法解决真正的问题,还是被外围的技术问题转移了注意力?
  • 这件事情为什么是一个问题?
  • 是什么使它如此难以解决?
  • 它必须以这种方式完成吗?
  • 它真的必须完成吗?

提示56:倾听反复出现的疑虑——等你准备好再开始(Listen to Nagging Doubts – Start When You’re Ready)

  • 你一直在试验各种东西,看哪些可行,哪些不可行。你一直在积累经验和智慧。当你面对一件任务时,如果你反复感觉到疑虑,或是体验到某种勉强,要注意它。你可能无法准确地指出问题所在,但给它时间,你的疑虑很可能就会结晶成某种更坚实的东西,某种你可以处理的东西。

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

提示58:不要做形式方法的奴隶(Don’t Be a Slave to Fomal Methods)

  • 注重实效的程序员批判地看待方法学,并从各种方法学中提取精华,融合成每个月都在变得更好的一套工作习惯。这至关重要。你应该不断努力提炼和改善你的开发过程。觉不要把方法学的呆板限制当做你的世界的边界。

提示59:昂贵的工具不一定能制作出更好的设计(Expensive Tools Do Not Produce Better Designs)

提示60:围绕功能,而不是工作职务进行组织(Organize Around Functionality,Not Job Functions)

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

提示62:早测试、常测试、自动测试(Test Early. Test Often. Test Automatically):与呆在书架上的测试计划相比,每次构建时运行的测试要有效得多。

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

提示64:通过“蓄意破坏”测试你的测试(Use Saboteurs to Test Your Testing):在单独的软件副本上故意引入bug,以检验测试能够抓住它们)。

提示65:测试状态覆盖,而不是代码覆盖(Test State Coverage,Not Code Coverage):确定并测试重要的程序状态。只是测试代码行是不够的。

提示66:一个bug只抓一次(Find Bugs Once):一旦测试人员找到一个bug,这应该是测试员最后一次找到它。此后自动测试应该对其进行检查。

提示67:英语就是一种编程语言(English is Just a Programming Language):像你编写代码一样编写文档:遵守DRY原则、使用元数据、MVC、自动生成,等等。

提示68:把文档建在里面,不要拴在外面(Build Documentation In,Don’t Bolt It On):与代码分离的文档不太可能被修正和更新。

提示69:温和地超出用户的期望(Gently Exceed Your Users’Expectations):要理解你的用户的期望,然后给他们的东西要多那么一点。

提示70:在你的作品上签名(Sign Your Work)过去时代的手艺人为能在他们的作品上签名而自豪。你也应该如此。


第八章 注重实效的项目

41、注重实效的团队

  • 不要留破窗户
    • 团队作为一个整体,不应该容忍破窗户——那些小小的、无人修正的不完美。团队必须为产品的质量负责,支持那些了解我们在“软加的熵”中描述的“不要留破窗户”哲学的开发者,并鼓励那些还不了解这种哲学的人。
  • 煮青蛙
    • 确保每个人都主动监视环境的变化。可以指定一个“首席水情监测员”(chief water tester)。让这个人持续的检查范围的扩大、时间标度的缩减、新增特性、新环境——任何不在最初的约定中的东西。对新需求进行持续的度量。团队无需拒绝无法控制的变化——你只需注意它们正在发生。否则,你就会置身于热水中。
  • 交流
    • 团队的开发者必须相互交流。团队作为实体需要同外界明晰地交流。
    • 有一个简单的营销诀窍,能帮助团队作为整体与外界交流:创立品牌。当你启动项目时,给它取一个名字,最好是不寻常的某种东西。
  • 不要重复你自己
    • 有些团队指定某个成员担任项目资料管理员,负责协调文档和代码仓库。
    • 当项目对一个资料管理员来说太大时,可以指定多人负责工作的各个方面。
    • 群件系统?本地Usenet新闻组?
  • 正交性
    • 我们喜欢按照功能划分团队。把你的人划分成小团队,分别负责最终系统的特定方面的功能。让各团队按照个人的能力,在内部自行进行组织。每个团队都按照他们约定的承诺,对项目中的其他团队负有责任。承诺的确切内容随项目而变化,团队间的人员分配也是如此。
  • 自动化
  • 知道何时停止绘画

42、无处不在的自动化

  • 一切都要自动化
  • 项目编译
    • 我们想要用一条命令就完成签出、构建、测试和发布。
    • 生成代码
    • 回归测试
    • 构建自动化
    • 最终构建
  • 自动化管理
  • 生成网站
    • 用内部网站来进行项目交流
    • 误导人的信息比完全没有信息还要糟糕
  • 工具使用
    • cron
    • make
    • Perl脚本语言:可用于快速开发自制的工具、网页生成器,代码生成器、测试装备,等等。

检查清单

71、要学习的语言

厌倦了C、C++和JAVA?试试CLOS、Dylan、Eiffel、Objective C、Prolog、Smalltalk或TOM。它们每一种都有不同的能力和不同的“风格”。用其中一种或多种语言在家里开发一个小项目。

72、WISDOM离合诗

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? 你如何促使他们听你说话?

73、怎样维持正交性

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

74、应制作原型的事物

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

75、架构问题

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

76、调试检查清单

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

77、函数的得墨忒耳法则

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

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

78、怎样深思熟虑地编程

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

79、何时进行重构

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

80、劈开戈尔迪斯结

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

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

81、测试的各个方面

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

发布者

虚妄的存在感

我尊重你的存在感,但我鄙视你虚妄的存在感。