5

我最近在 Cojure Conj 2016 上观看了 Rich Hickeys 的演讲,虽然这很有趣,但我并不真正理解其中的意义clojure.spec或何时使用它。似乎大多数想法,例如符合、有效等,在 Clojure 中已经具有类似的功能。

我现在才学习 clojure 大约 3 个月,所以这可能是由于缺乏编程/Clojure 经验。

clojure.spec 和 cljs.spec 的工作方式与 Clojure 和 Cljs 相似,尽管它们不是 100% 相同,但它们基于相同的基本原理。

4

2 回答 2

8
  • 您是否厌倦了记录您的程序?
  • 进行更多测试的前景是否会导致拖延?
  • 当老板说“测试覆盖”时,你害怕吗?
  • 您是否忘记了数据名称的含义?

为了顺利表达硬规范,您需要Clojure.Spec


Clojure.spec 为您提供了一种统一的方法来记录、指定和自动测试您的程序,以及验证您的实时数据。

它几乎窃取了它的每一个想法。它没有你不能为自己做的事情。

但在我几乎不知情的情况下,它改变了规范的经济性,使它值得做正确的事。改变游戏规则?- 很有可能。

于 2016-12-11T20:46:04.093 回答
6

在上周的 clojure/conj 会议上,可能有一半的演示文稿都以某种方式介绍了规范,而且它甚至还没有结束 alpha。spec是clojure的一特色;它会留在这里,而且它很强大。

以静态类型检查为例,它被许多人誉为一种安全网,也是许多编程语言的定义特征。它非常有限,因为它只适用于编译时,并且只检查类型。另一方面,spec 验证并符合任何谓词(不仅仅是类型)的 args、return,并且还可以验证两者之间的关系。所有这些都在函数的代码之外,将函数的逻辑与代码的验证和文档分开。

关于工作流程:

与仅类型检查相比,关系检查的好处的一个典型示例是计算字符串的子字符串的函数。类型检查确保 in(subs s start end)s一个字符串并且startend是整数。但是,必须在函数内进行额外的检查,以确保startend是正整数,即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用作运行函数的前置条件和后置条件。我对此不太感兴趣,因为它在生产系统中是开销,但这是一种可能性。

天空是极限,我们只是触及了表面!在接下来的几个月和几年里,很酷的事情会随着规范而来!

于 2016-12-12T19:54:57.297 回答