在哪里投放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)通常都会被忽略,所以当然这似乎很奇怪。 但是可以考虑一下,你可能会像我一样得出一个结论(或者你可能不会,这部分是自以为是的)。
我可以想到的只有很好的理由,为什么你不会在同一时间规格是这两个原因:
- 它混淆了你的代码。
- 你希望在Clojure 1.9.0之前支持Clojure版本。
至于第一个原因,那么我认为这是你职能的一个组成部分。 如果你发现它真的太多了,我的build议是一样的,就好像你的ns不pipe规格太混乱了,看你是否可以分解它。
至于第二个原因,如果你真的关心,你可以检查代码,如果clojure.spec ns是可用的,如果不是,那么阴影与NOP的函数/macros的名称。 另一个select是使用clojure-future-spec,但是我没有尝试过,所以我不知道它的工作效果如何。
另一种方法是在技术上有效的做法是,有时候会有循环依赖,你不能用不同的命名空间来处理,例如,当你的规范依赖你的代码(对于函数规范),你的代码依赖于你的规范parsing(见这个问题 )。
根据您的使用情况,另一个考虑因素是将规范放在主代码旁边,将您的代码用于Clojure 1.9客户端,这可能会或可能不是您想要的。 像@levand一样,我会为每个代码命名空间推荐一个并行命名空间。