在上周的 clojure/conj 会议上,可能有一半的演示文稿都以某种方式介绍了规范,而且它甚至还没有结束 Alpha 版。 spec 是 clojure 的一个主要特性;它会一直存在,而且很强大。
以静态类型检查为例,它被许多人誉为一种安全网,也是许多编程语言的定义特征。它非常有限,因为它只适用于编译时,并且只检查类型。另一方面,spec 验证并符合 args、return 的任何谓词(不仅仅是类型),还可以验证两者之间的 relationships。所有这些都在函数代码之外,将函数的逻辑与代码的验证和文档分开。
关于工作流程:
关系检查相对于类型检查的好处的一个典型例子是计算字符串的子字符串的函数。类型检查确保(subs s start end) 中的s 是字符串,start 和end 是整数。但是,必须在函数内进行额外检查,以确保start 和end 是正整数,end 大于start,并且生成的子字符串不大于原始字符串。例如,所有这些东西都可以指定出来(如果其中有些内容有点多余甚至不准确,请原谅我):
(s/fdef clojure.core/subs
:args (s/and (s/cat :s string? :start nat-int? :end (s/? nat-int?))
(fn [{:keys [s start end]}]
(if end
(<= 0 start end (count s))
(<= 0 start (count s)))))
:ret string?
:fn (fn [{{:keys [s start end]} :args, substring :ret}]
(and (if end
(= (- end start) (count substring))
(= (- (count s) start) (count substring)))
(<= (count substring) (count s)))))
使用符合上述args规范的样本数据调用函数:
(s/exercise-fn `subs)
或者运行 1000 次测试(这可能会失败几次,但继续运行它会工作的——这是由于内置生成器无法满足 :args 谓词的第二部分;自定义如果需要,可以编写生成器):
(stest/check `subs)
或者,想查看您的应用在实时运行时是否对subs 进行了无效调用?只需运行它,如果调用该函数并且不满足规范,您将得到规范异常:
(stest/instrument `subs)
我们尚未将此集成到我们的工作流程中,并且由于它仍处于 Alpha 阶段,因此无法投入生产,但首要目标是编写规范。我将它们放在同一个命名空间中,但目前放在不同的文件中。
我预计我们的工作流程是使用这个(在 clojure 规范指南中找到)运行规范函数的测试:
(-> (stest/enumerate-namespace 'user) stest/check)
然后,最好为所有功能打开检测,并像我们通常测试它一样在负载下运行应用程序,并确保“真实世界”数据正常工作。
您还可以使用s/conform 来解构函数本身中的复杂数据,或者使用s/valid 作为运行函数的前置条件和后置条件。我对此不太感兴趣,因为它在生产系统中是开销,但这是一种可能性。
天空是极限,我们只是触及了表面!在接下来的几个月和几年里,随着规范的到来,很酷的事情!