【问题标题】:Clojure.spec - Why is it useful and when is it usedClojure.spec - 为什么有用以及何时使用
【发布时间】:2023-03-03 03:17:01
【问题描述】:

我最近看了Rich Hickeys talk at Cojure Conj 2016,虽然它很有趣,但我并没有真正理解clojure.spec 的意义,或者你什么时候会使用它。似乎大多数想法,例如符合、有效等,在 Clojure 中已经具有类似的功能。

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

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

【问题讨论】:

  • What is Clojure spec?的可能重复
  • conform 的现有定义在哪里? (你怎么可能一个,没有一个规范格式来检查它?)

标签: clojure clojure.spec


【解决方案1】:

在上周的 clojure/conj 会议上,可能有一半的演示文稿都以某种方式介绍了规范,而且它甚至还没有结束 Alpha 版。 spec 是 clojure 的一个主要特性;它会一直存在,而且很强大。

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

关于工作流程:

关系检查相对于类型检查的好处的一个典型例子是计算字符串的子字符串的函数。类型检查确保(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 作为运行函数的前置条件和后置条件。我对此不太感兴趣,因为它在生产系统中是开销,但这是一种可能性。

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

【讨论】:

  • clojure-future-spec 是 Clojure 1.8 的 clojure.spec 的反向移植。不知道它是什么样的。
  • @Thumbnail 不确定您为什么要使用任何类型的后端端口? 1.9 最有可能在 4-6 个月内投入生产。
  • ...为什么要使用任何类型的后端端口? - 现在认真使用spec
  • 我会相信 alpha14,它已经相当成熟并且已经 7 个月大了,而不是几个月后就会过时的第三方后端。
  • 反向移植只是从 1.9 复制的 clojure.specclojure.spec.genclojure.spec.test;将 1.9 的 clojure.core 中的附加功能向后移植到 clojure.future。 1.8 版将在几个月后过时。
【解决方案2】:
  • 您是否厌倦了记录您的程序?
  • 进行更多测试的前景是否会导致拖延?
  • 当老板说“测试覆盖”时,你害怕吗?
  • 您是否忘记了数据名称的含义?

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


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

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

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

【讨论】:

  • 你在测试中使用它吗?工作流程是什么?我设想在 repl 模式下使用 s/instrument,对使用规范的测试有某种测试流程。
  • @JustinThomas 工作流程是什么? - 这是个好问题。我认为你应该用这些术语来问它。
猜你喜欢
  • 2013-06-13
  • 2021-01-24
  • 2013-01-05
  • 2017-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-10
  • 2020-02-12
相关资源
最近更新 更多