完美主义是个陷阱。对于像我一样喜欢优雅设计并看到其实用性的人来说,当令人满意的设计没有在合理的时间内出现时,就会有一个滑坡等待。认识到这一点并接受、放手、发货并继续前进——或者在以后的周期中返回,如果重要的话,需要不断的自律。它并不总是重要的。对于我们系统的许多部分,一个足够好的设计就足够了。对于少数具有战略意义的部分,精辟的模型和清晰的设计实际上可能会影响项目的结果,出色的初始设计通常不会立即出现。我们需要迭代和实验。我们的任何目标都不是通过磨练和磨蹭来实现的,等待我们可以在第一版中引以为豪的设计。就我个人而言,我试图超越接受。当我为设计的某些部分苦苦挣扎时,我经常做出明确回应设计问题本身的设计选择。这有助于我放手继续前进,并且可以提高在以后的迭代中进行更改的机会。在这个简短的系列中,我将描述我使用的一些技术,这些技术可以帮助我采取措施交付我不满意的东西,同时也可能为未来的迭代改进留下良好的途径。我们将从非常细粒度的设计决策开始这个系列。一个诚实的名字并不总是一个揭示意图的名字。只有当我们通过设计元素成功实现我们的意图时,情况才会如此。但这并不总是发生。在本文中,我们正在考虑那些没有好的解决方案的不幸时期。我需要一个具体的例子来说明这种方法。挑出一些设计不佳的软件很容易,但检查通常设计良好的软件的缺陷更有趣。 JodaTime 是一个用于日期/时间的 Java 库,被广泛用作开源库,并最终以修改的形式采用作为 Java 的标准库。它设计精良——当然,并不完美。 (毕竟,它发货了!)JodaTime 库允许我们声明时间,例如日期和时间段: t = 2021-01-20 p = 3 days 对于许多应用程序,这些值的存储本身就是一个重要能力。当然,常见的时间相关的操作有很多,库中也实现了一些,比如:t.plus(p) 2021-01-20.plus(3 days) ⇒ 2021-01-23 不错!在 JodaTime 中,所有的值都被设计为值对象。没有突变或副作用。所以在上面的例子中,执行t.plus(p)后,t的值不变:2021-01-20,并且操作返回了一个新的值2021-01-23。 “加号”操作是通用的。它适用于不同类型的时期: 2021-01-20.plus(2 days) ⇒ 2021-01-22 2021-01-20.plus(2 Month) ⇒ 2021-03-20
代码看起来非常有表现力和清晰。然而......你认为以下会返回什么?请记住,二月是一个短暂的月份!我能想到至少三个似是而非的反应。为了了解它的实际作用,我运行了以下代码: 这似乎是一个合理的默认行为,但并不明显。我必须运行代码(或在某处查找文档)才能知道会发生什么,即使在使用该操作的一些经验之后,这一事实凸显了模型中的缺陷。但它有什么问题,可以做些什么呢?在本文中,我将重点介绍名称。 “加”这个词似乎符合我前几个例子中发生的情况,但它没有暗示我们如何处理不规则的情况,例如不同长度的月份。这给我们带来了“诚实的名字”。如果操作的行为很复杂,像“plus”这样的简单名称实际上可能会产生误导。它可以被称为什么?探索重要事物名称的许多选项通常是一种很好的做法。让我们尝试一些:这些中的任何一个至少会给我一个线索。他们也很尴尬!我们不喜欢笨拙的设计。但我们需要诚实的名字。让我们多看看 JodaTime 中的“plus”操作,以及为什么“plus”是一个令人困惑的名字。 (这里我将'plus' 写为'+' 以便于阅读。)
猜一下这两个表达式的值:2021-03-31 + 2 个月 ⇒ ? 2021-03-31 + 1 个月 + 1 个月 ⇒ ?以下是实际答案: 2021-03-31 + 2 个月 ⇒ 2021-05-31 2021-03-31 + 1 个月 + 1 个月 ⇒ 2021-05-30 期间也可以与“加”组合,所以 1 个月+ 1 个月 ⇒ 2 个月 因此, 2021-03-31 + 1 个月 + 1 个月 ⇒ 2021-05-30 2021-03-31 +(1 个月 + 1 个月)⇒ 2021-05-31 在这里我们来到关于称这个“加号”有什么问题的见解:该名称的含义在我们的上下文中不适用!在数学中,“加”运算具有诸如结合性之类的属性: (a + b) + c = a + (b + c) 当我们使用这个名称时,我们暗示了读者(使用库的程序员或阅读代码的程序员)使用它)该操作是关联的。但事实并非如此!许多定义明确的操作都不是关联的。但是我们应该称它们为“加号”吗?顺便说一句,我喜欢不断地将事物的可能替代名称添加到我的列表中。在这一点上,我还有一些其他想法:我们必须发货! JodaTime 的设计者当时可能已经注意到了这个问题。 (我对那个项目的内部一无所知。)如果他们注意到了,在我看来,他们仍然做出了正确的决定。他们发布了一个非常有用且通常非常干净的库——这并不完美。他们一定做过很多次类似的决定。有些问题他们注意到了,有些则没有。
但是,如果您决定运送一些您认识的笨拙的东西,请考虑给它一个诚实的、笨拙的名字。这可以与未来的用户进行交流,并且可以帮助设计的未来迭代。一个尴尬的名字会激发新的想法。 t.plusIshRoundCeiling(p) ⇒ t(拜托,拜托!我的代码太丑了!)它在我们的脑海中挥之不去,可能是通过软件的后期迭代。同时,它将向代码的用户传达一个现实的期望。接受我们设计中的缺陷并不意味着我们会忘记它!在第二部分中,我们将快速浏览一个替代概念,该概念可能会在以后的迭代中出现以缓解尴尬。