跳转到主要内容

保存的文章

合同设计:第一部分

Dave Nicolette |领导敏捷
Dave Nicolette 高级顾问
阅读: 合同设计:第一部分

尽管契约式设计(DbC)很有用,但几乎所有主流编程语言都极度缺乏对它的支持。Ruby和JavaScript似乎是仅有的两种主流语言,可以提供可靠且易于使用的DbC库。

但是,滚动自己的代码先决条件后置条件在任何语言中都是直截了当的。支持不变量这是另一个故事,但您的应用程序可能没有它也能正常运行。通常指某人的意图不变的可以强制执行前提后置条件检查。

这是DBC主题的一系列三个帖子。第1部分包含:

  • 合同设计的解释
  • 澄清DbC的目的——具体来说,它不是一个测试工具
  • 随机自以为是的评论

第2部分:

  • 一些主流编程语言(Java、c#、Ruby、JavaScript、Python、Go)可用的DbC库的快速调查
  • 一个小的演示合同为Ruby gem
  • 一个小的演示合同包JavaScript
  • 随机自以为是的评论

第3部分:

  • 逐步演练Java中对DbC的测试驱动手卷支持
  • 随机自以为是的评论

什么是契约式设计?

契约式设计(DbC)由Bertrand Meyer在20世纪80年代创建,是一种专注于指定的软件设计方法合同它定义了组件之间的交互。DbC是我们工具包中的另一个工具,用于获得对我们的代码正确的信心,另外还有其他工具,如类型系统、可执行测试用例、静态代码分析和变异测试。

一个基本的假设是组件在客户机-服务器模型中彼此交互。服务器确定承诺(也称为义务) 提供好处对客户端,客户组件可能会假定这些承诺将被保存。合同还规定了后置条件不变量,参与的部件必须遵守。

DBC基于先前存在的逻辑构建块。一个关键的潜在概念是霍尔三元组.1969年,英国计算机科学家Tony Hoare提出,我们可以通过考虑一段代码的执行如何改变计算状态来推断软件的正确性。基本公式为:

C P {} {Q}

在哪里P代表一个前提C表示计算,和代表一个后置条件.前置条件和后置条件表示为断言,在某种意义上谓词逻辑(也称为一阶逻辑)。那些是DBC的基本逻辑构建块。

在DbC,义务先决条件, 表示为断言;的好处后置条件, 表示为断言;和不变量是保证不受计算影响的系统状态的方面。

埃菲尔铁塔的语言

如果能定义一种将契约指定为文档的方法,程序员可以将其用作基于DbC构建软件的指南,那将是非常有趣和有用的,但Meyer并没有就此止步。他还开发了一种内置DbC构造并在编译时强制执行的编程语言。Eiffel语言直接实现DbC。

为了了解DbC如何帮助我们,让我们先看看Eiffel,因为它是最初的实现。这是来自的一个示例Eiffel类DbC的介绍在埃菲尔铁塔上:

class DICTIONARY [ELEMENT] feature put (x: ELEMENT;key: STRING)是——通过key插入x使其可检索。要求count <= capacity not key。空确保有(x)项(键)= x计数=旧计数+ 1结束…接口规格的其他功能…不变0 <= count count <=容量结束

需要关键字指定先决条件为了例程在字典。一个或多个断言可以遵循需要.在本例中,先决条件是字典条目的数量(count)不超过字典的容量,并且客户端不试图添加没有键的条目。

确保关键字指定后置条件为了例行公事。它承诺之后操作,字典将包含元素x,基于的查找关键将检索元素x,并且新计数将比前一个计数大1。

不变的关键字指定必须保持不变的系统状态的某些方面。的范围不变的比的大吗需要确保,因为不管执行什么操作,不变量都必须为真。在本例中,不变式是字典中的项数(count)必须为正,并且count不能超过字典的容量。

不是测试技术

在为Eiffel以外的语言寻找DbC实现的过程中,我注意到一个常见的误解:许多人认为DbC是一种测试技术。之间的区别测试和检查通常是明确的,但是每种情况可能发生的情况可以有不同的解释。

DBC是一种形式检查,它是以断言为基础的。正如迈克尔·博尔顿和詹姆斯·巴赫所说:“一个断言,在计算机科学的意义上,是一种检查。但并不是所有的检查都是断言,甚至在断言的情况下,断言之前可能有代码是检查的一部分,但不是断言的一部分。”DbC与这个观察结果是一致的。

还有关于语境的混淆;有些人认为任何类型的检查,特别是那些通过软件工具执行的检查,都必须在产品开发或交付的“测试阶段”进行。我在DbC库的实现中看到的问题可能源于这种误解。许多DbC解决方案被设计为在开发和测试期间使用。它们涉及“额外的”和“可选的”库,这些库可以在构建时或运行时启用或禁用。至少我研究过的一种方法要求在编译代码时打开调试选项,以便插装目标代码,并且DbC工具可以使用调试信息。在为生产部署准备代码时,不会这样做。

但其目的是在应用程序实时运行时在生产环境中断言前置条件、后置条件和不变量。这才是重点。它可以防止无效参数或不正确的数据结构被传递到应用程序组件中;防止组件无意中产生不可用或有害的输出;防止应用程序更改系统状态作为其操作的意外副作用。规范引用实现Eiffel没有将DbC检查与代码的其余部分分开。这不是我们的意图。

为什么不只是写一个“如果”声明?

当您查看各种DbC库时,您会发现它们往往是相对基本条件代码的复杂包装器。DbC没有大范围流行的一个原因可能是人们被这些工具表面上的复杂性吓到了。当研究DbC的值时,开发人员经常会问,为什么不为它写一个“if”语句呢?

他们是对的。问题不在于你不能写一个“如果”语句。问题是,大多数人都懒得去写“如果”语句。把它作为一个独特的“事物”来称呼,可能会潜移默化地影响开发人员更多地关注它。

上面提到的同一个迈克尔·博尔顿讲述了开发商挑战他违反他所写的网络申请的时间的故事。开发人员非常有信心代码是摇滚固体。博尔顿不仅打破了应用程序,而且在几秒钟内崩溃了服务器。他粘贴了一本书的全文古登堡计划进入应用程序的登录表单。

那么,为什么开发人员不写一个“if”语句呢?这本来可以省去他许多麻烦和难堪。它也可以说是防范众所周知的安全风险的基本软件工程能力。限制表单上输入值的大小是最基本的东西毕竟。

当一件事有了名字,它就变成了真实

现在,如果有一个软件开发人员可以做的“事情”名称和讨论(就像“通过合同设计,也许),那么他们会更容易记住照顾这一点。

随着微服务的越来越受欢迎,给定的申请可以包括许多小型服务,这些服务是独立于不起作用的人而且从未见过的人开发。有时客户端从注册表查找服务,并且他们甚至不知道他们正在调用的服务界面的哪些实现。这些应用程序生活在一个神秘的不安全的环境中,称为“互联网”。你可能听说过它。

其中一些客户甚至可能怀有敌意。事实上,我们知道有些是

DbC提供了一种确保代码契约在实际应用中得到遵守的方法,当软件组件可能被服务开发人员不了解且无法控制的客户机代码调用时。它不能自动保护所有错误或坚决的黑客,但它是一个有用的防御工具。

我们不能完全通过在部署前检查代码来管理这种情况。我们必须在生产中积极管理它。DbC意味着执行与组件交互的契约,而不仅仅是检查它。

下一个

在下一期间,我将分享我的经历寻找java,c#,ruby,javascript,python和go的dbc支持。在第三次和最后一期,我们将通过在几个主流语言中开发DBC支持的过程。

下一个;合同设计:第二部分

留下你的评论

您的电子邮件地址将不会被公布。必填字段被标记