在哪里列出Clojure.Spec的规格?

时间:2016-06-21 10:54:32

标签: clojure clojure.spec

所以,我越来越深入地进入 Clojure.Spec

我偶然发现的一件事是,在哪里放置我的规格。我看到三个选项:

全局规范文件

在大多数示例中,我发现在线,有一个大的spec.clj文件,在主命名空间中需要。它包含所有"数据类型的所有(s/def)(s/fdef)"和功能。

亲:

  • 一个文件来统治所有

魂斗罗:

  • 此文件可能很大
  • 违反单一责任原则?

生产命名空间中的规范

您可以将(s/def)(s/fdef)放在生产代码旁边。因此,实现和规范在同一名称空间中共存。

临:

  • 实施和规范的共同位置
  • 一个名称空间 - 一个关注点?

魂斗罗:

  • 生产代码可能会变得混乱
  • 一个名称空间 - 两个问题?

专用规范命名空间结构

然后我想,也许Specs是第三种代码(在生产和测试之后)。所以也许他们应该拥有自己的名称空间结构,如下所示:

├─ src
│  └─ package
│     ├─ a.clj
│     └─ b.clj
├─ test
│  └─ package
│     ├─ a_test.clj
│     └─ b_test.clj
└─ spec
   └─ package
      ├─ a_spec.clj
      └─ b_spec.clj

临:

  • 规范的专用(但相关)命名空间

魂斗罗:

  • 您必须提供并且需要正确的命名空间

谁有使用其中一种方法的经验?
还有其他选择吗?
您如何看待不同的选择?

3 个答案:

答案 0 :(得分:20)

我通常将specs放在他们自己的命名空间中,以及他们描述的命名空间。只要它们使用一些一致的命名约定,它们的命名并不特别重要。例如,如果我的代码位于my.app.foo,我会将规范放在my.app.foo.specs中。

规范密钥名称最好位于代码的名称空间中,但不是规范的名称空间。通过在关键字上使用命名空间别名,这仍然很容易做到:

(ns my.app.foo.specs
  (:require [my.app.foo :as f]))

(s/def ::f/name string?)

我不会试图将所有内容放在一个巨大的规范名称空间中(这真是一场噩梦。)虽然我当然可以将它们放在同一文件中的规范代码旁边,这会伤害IMO的可读性。

可以将所有规范名称空间放在一个单独的源路径中,但这样做没有任何实际好处,除非您处于要分发代码而不是规范或反之亦然......很难想象那会是什么。

答案 1 :(得分:14)

在我看来,规格应与代码在同一个ns中。

我的主要考虑因素是我的个人理念,从技术上讲,它的效果很好。我的理念是函数的规范是整数的一部分。这不是一件额外的事情。它的绝对不是"两个问题"如在OP中。实际上,它的功能是什么,因为在正确性方面:谁在乎实施?谁在乎你在defn写的内容?谁在乎标识符?谁关心任何事情但规范? 我认为这很奇怪,因为不仅clojure.spec后来出现,大多数语言也不会让你将规格作为一个整体的东西,即使你想要它,并且任何接近(在代码中测试)通常都是不满意,所以当然看起来很奇怪。但是要考虑一下,你可能会像我一样得出结论(或者你可能没有,这部分是固执己见的。)

我能想到为什么你不想在相同的ns中使用规格的唯一理由是这两个原因:

  1. 它使您的代码混乱。
  2. 您希望在Clojure 1.9.0之前支持Clojure版本。
  3. 至于第一个原因,嗯,我认为它是你职能中不可或缺的一部分。如果你发现它确实太多了,我的建议就像你的ns太乱了一样,无论规格如何:看看你是否可以拆分它。

    至于第二个原因,如果你真正关心,你可以检查代码是否可用clojure.spec ns,如果没有,则使用NOP的函数/宏来遮蔽名称。另一种选择是使用clojure-future-spec,但我自己没有尝试过,所以我不知道它的效果如何。

    另一种在技术上运作良好的方法是,有时存在一个循环依赖,你不能用不同的命名空间来处理,例如:当您的规范依赖于您的代码(对于函数规范)而您的代码取决于您的解析规范(请参阅此question)。

答案 2 :(得分:7)

另一个考虑因素取决于您的使用案例 - 将规范与主代码放在一起限制了您的代码使用Clojure 1.9客户端,这可能是您想要的,也可能不是。和@levand一样,我建议为每个代码名称空间使用并行命名空间。