科里定律:坚守一个目标
在“Outliving the Great Variable Shortage”(应对变量短缺)一文中,Tim Ottinger提到了“科里定律”(Curly’s Law):
一个变量应该代表一样东西,并且只能代表一样东西。它不应该在一种情况下代表这个意思,而在另一种情况下又代表不同的意思。它不能一次代表两样东西。它不能既是地板蜡,又是甜点上的打顶。它应该只有一个含义,并且自始至终只有一个含义。
在1991年上映的喜剧《城市乡巴佬》中,伟大的已故演员Jack Palance扮演了一位白发斑斑的牛仔Curly Washburn。科里定律便出自电影里的这一小段对话:
《城市乡巴佬》(City Slickers)是一部关于人生、牛仔和中年危机的喜剧片。三个面临中年危机的纽约都市人,面对破裂的婚姻、乏味的工作和一成不变的生活,决定暂时抛开烦恼,到大西部加入从墨西哥到科罗拉多的“赶牛队”,体验儿时当牛仔的梦想。结果,三人在“赶牛队”的生活并不如西部电影中那般浪漫刺激,最后他们体验出:“做一个真正成熟的成人,并不是一件容易的事。”——译者注
Curly:你知道人生的秘密是什么吗?
Curly(竖起了一根手指):就是这个。
Mitch:你的手指?
Curly:一个目标。就一个目标。你须坚持这个目标,心无旁骛。
Mitch:但是,这个目标是什么呢?
Curly(笑):这就是你要去寻找的。
科里定律:坚守一个目标。这个定律在现代软件开发的几个核心原则中都有体现:
· Don’t Repeat Yourself(DRY,即避免重复):如果你有多种方式来表达同一件事情,总有一天,这两种或者三种不同的表达方式会失去同步。即使没出现这种情况,当你需要做点什么改动时,你一定会因为要同时维护它们而感到头痛不已。改动总是会发生的。如果你想让软件保持灵活并易于维护,避免重复是非常重要的。
· Once And Only Once(OAOO,即唯一一次):每个行为的声明应当发生一次,并且只发生一次。当你重构代码的时候,如果这不是主要的目标,至少也应该是主要目标之一。设计的目标是为了消除重复的行为声明,方法是通过合并或者使用统一的抽象来替代多个相似的实现。
· Single Point Of Truth(SPOT,即单点真理):重复会造成不一致,并以一种微妙的方式破坏代码,因为在你需要修改所有的重复代码时,你可能只改了其中的一部分。这常常意味着,你没有好好地考虑代码的组织结构。每当你看到有重复代码的时候,你要知道那是一个危险信号。复杂是一种成本,不要加倍付出。
尽管科里定律完全适用于标准化和去除冗余,但“坚守一个目标”与上面的“每件事只做一次”的不同表述比起来,两者之间存在着细微的差别。科里定律更为深入,而Bob Martin将其称为“单一职责原则”(Single Responsibility Principle,简称SRP):
单一职责原则指的是,就一个类而言,应该仅有一个引起它变化的原因。举例来说,看下面的这个类:
Class Employee
{
Public Money calculatePay()
Public void save()
Public String reportHours()
}
这个类违反了单一职责原则,因为下面3个原因都会引起它的改变:
1. 薪酬的计算规则;
2. 数据库结构;
3. 报告时间的字符串格式。
我们不希望一个类受到3个完全不相干的因素影响。我们不希望每次报告的格式发生改变的时候,或者数据库管理员变更数据库结构的时候,再或者管理人员调整薪酬的计算方法的时候,这个Employee类总是要跟着改变。我们更希望把这些功能分拆到不同的类中,这样的话,他们就可以各自独立地变化。
科里定律告诉我们的是,要为每段代码选择单一而清晰的目标——坚持只做一件事。这一点已经很清楚了。但是,至于选择一个目标,你实际上要排除很多很多你可能做的其他事情。科里定律同时也告诉我们,要有意识地选择你的代码不做什么。这比选择做什么要难得多,因为它与软件开发者与生俱来的全能癖好格格不入。它可能意味着要把代码打散,违反传统的OOP规则,或者引入重复代码——我们的前进方式是“退一步,进两步”。
总之,每一个变量,每一行代码,每一个函数,每一个类,每一个项目都应该坚持一个目标。遗憾的是,我们通常要等到最后结束的时候才会发现那个目标。