大约在1951年,一种名为“全员生产维护”(Total Productive Maintenance,TPM)的质量保证手段在日本出现。它关注维护甚于关注生产。TPM的主要支柱之一是所谓的5S原则体系。
5S哲学包括以下概念。
整理(Seiri),或谓组织(想想英语中的 sort 一词)。
整顿(Seiton),或谓整齐(想想英文中的systematize 一词)。
清楚(Seiso),或谓清洁(想想英文中的 shine一词)。
清洁(Seiketsu),或谓标准化。
身美(Shitsuke),或谓纪律(自律)。勒布朗(LeBlanc)法则:稍后等于永不(Later equals never.)。
窃以为单字母名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应。
我们想要让代码拥有自顶向下的阅读顺序。我们想要让每个函数后面都跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能循抽象层级向下阅读了。我把这叫作向下规则。
关于实体变量应该放在哪里,争论不断。在C++中,通常会采用所谓剪刀原则(scissors rule),即所有实体变量都放在底部。而在Java中,惯例是放在类的顶部。
我们再次看到这两种定义的本质:它们是截然对立的。这说明了对象与数据结构之间的二分原理:
过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数;面向对象代码便于在不改动既有函数的前提下添加新类。
反过来讲也说得通:
过程式代码难以添加新数据结构,因为必须修改所有函数;面向对象代码难以添加新函数,因为必须修改所有类。
所以,对于面向对象较难完成的事,对于过程式代码却较容易,反之亦然!
在任何一个复杂系统中,都会有需要添加新数据类型而不是新函数的时候。这时,对象和面向对象就比较适合。另一方面,也会有想要添加新函数而不是数据类型的时候。在这种情况下,过程式代码和数据结构就更适合。著名的得墨忒耳律(The Law of Demeter)认为,模块不应了解它所操作对象的内部情形。如上节所见,对象隐藏数据,曝露操作。这意味着对象不应通过存取器曝露其内部结构,因为这样更像是曝露而非隐藏其内部结构。
更准确地说,得墨忒耳律认,类C的方法f只应该调用以下对象的方法:
• C;
• 由f创建的对象;
• 作力参数传递给f的对象;
• 由C的实体变量持有的对象。
方法不应调用由任何函数返回的对象的方法。换言之,只跟朋友谈话,不与陌生人谈话。最为精练的数据结构,是一个只有公共变量、没有函数的类。这种数据结构有时被称为数据传送对象(Data Transfer Objects,DTO)。DTO 是非常有用的结构,尤其是在与数据库通信或解析套接字传递的消息之类的场景中,在应用程序代码里一系列将原始数据转换为数据库的翻译过程中,它们往往是排头兵。
学习第三方代码很难,整合第三方代码也很难,同时做这两件事难上加难。如果我们采用不同的做法呢?不要在生产代码中试验新东西,而是编写测试来遍览和理解第三方代码。Jim Newkirk把这叫作学习性测试(leaming test)。
谁都知道 TDD 要求我们在编写生产代码前先编写单元测试。但这条规则只是冰山看看下列3条定律。
第一定律 在编写不能通过的单元测试前,不可编写生产代码。
第二定律 只可编写刚好无法通过的单元测试,不能编译也算不通过。
第三定律 只可编写刚好足以通过当前失败测试的生产代码。F.I.R.S.T.
快速(Fast)。测试应该够快。测试应该能快速运行。
独立(Independent)。测试应该相互独立。
可重复(Repeatable)。测试应当可以在任何环境中重复通过。
自足验证(Self-Validating)。测试应该有布尔值输出。
及时(Timely)。测试应及时编写。首先,构造与使用是非常不一样的过程。
软件系统应将起始过程和起始过程之后的运行时逻辑分离开,在起始过程中构建应用对象,也会存在互相缠结的依赖关系。并发是一种解耦策略。它帮助我们把做什么(目的)和何时做(时机)分解开。
Dave Thomas 和 Andy Hunt 称之 DRY 原则(Don't Repeat Yourself,别重复自己)。Kent Beck 将它列为极限编程核心原则之一,并称之“一次,也只一次”。Ron Jeffries 将这条规则列在第二位,地位仅次于通过所有测试。
所有较低层级概念放在派生类中,所有较高层级概念放在基类中。
我使用所谓“单个 switch”规则:对于给定的选择类型,不应有多于一个的switch语句。在那个switch语句中的多个case,必须创建多态对象,取代系統中其他类似的switch语句。