在哪里投放Clojure.Spec?

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

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

全球规格文件

在大多数例子中,我在网上发现,有一个大的spec.clj文件,在主命名空间中需要。 它具有所有“数据types”和函数的所有(s/def)(s/fdef)

优点:

  • 一个文件来统治他们

魂斗罗:

  • 这个文件可能很大
  • 单一责任原则受到侵犯?

规范在生产命名空间

你可以把你的(s/def)(s/fdef)放在生产代码的旁边。 因此,实现和spec在同一个命名空间中共存。

优点:

  • 实施和规格的共同定位
  • 一个命名空间 – 一个关注?

魂斗罗:

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

专用spec命名空间结构

然后我想,也许Specs是第三种代码(旁边的生产和testing)。 所以也许他们应该拥有自己的名字空间结构,就像这样:

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

优点:

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

魂斗罗:

  • 您必须提供并要求正确的名称空间

谁有经验的方法之一?
还有其他的select吗?
你怎么看待不同的select?

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

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

 (ns my.app.foo.specs (:require [my.app.foo :as f])) (s/def ::f/name string?) 

我会远离试图把所有东西放在一个巨大的规范命名空间(什么是恶梦)。虽然我当然可以把它们放在同一个文件中的spec'd代码,这伤害了可读性海事组织。

可以把你所有的spec命名空间放在一个单独的源代码path中,但是除非你想要分发代码而不是规范,否则没有真正的好处,反之亦然……很难想象是什么但是,即使如此。

在我看来,规范应该在代码相同的纳秒。

我的主要考虑是我的个人理念,从技术上讲它运作良好。 我的哲学是,function的规格是它的一个组成部分。 这不是一个额外的事情。 在OP中绝对不是“两个顾虑”。 其实,这就是function,因为在正确性方面:谁在乎执行? 谁在乎你在你的defn写了什么? 谁在乎标识符? 谁关心什么,但规格?
我认为这很奇怪,因为不仅clojure.spec迟来了,大多数语言也不会让你的规范成为一个整体,即使你想要它,任何接近的东西(代码中的testing)通常都会被忽略,所以当然这似乎很奇怪。 但是可以考虑一下,你可能会像我一样得出一个结论(或者你可能不会,这部分是自以为是的)。

我可以想到的只有很好的理由,为什么你不会在同一时间规格是这两个原因:

  1. 它混淆了你的代码。
  2. 你希望在Clojure 1.9.0之前支持Clojure版本。

至于第一个原因,那么我认为这是你职能的一个组成部分。 如果你发现它真的太多了,我的build议是一样的,就好像你的ns不pipe规格太混乱了,看你是否可以分解它。

至于第二个原因,如果你真的关心,你可以检查代码,如果clojure.spec ns是可用的,如果不是,那么阴影与NOP的函数/macros的名称。 另一个select是使用clojure-future-spec,但是我没有尝试过,所以我不知道它的工作效果如何。

另一种方法是在技术上有效的做法是,有时候会有循环依赖,你不能用不同的命名空间来处理,例如,当你的规范依赖你的代码(对于函数规范),你的代码依赖于你的规范parsing(见这个问题 )。

根据您的使用情况,另一个考虑因素是将规范放在主代码旁边,将您的代码用于Clojure 1.9客户端,这可能会或可能不是您想要的。 像@levand一样,我会为每个代码命名空间推荐一个并行命名空间。