Where to put specs for Clojure.Spec?

六眼飞鱼酱① 提交于 2019-12-02 16:58:12

I usually put specs in their own namespace, alongside the namespace that they are describing. It doesn't particularly matter what they're named, as long as they use some consistent naming convention. For example, if my code is in my.app.foo, I'll put specs in my.app.foo.specs.

It is preferable for spec key names to be in the namespace of the code, however, not the namespace of the spec. This is still easy to do by using a namespace alias on the keyword:

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

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

I'd stay away from trying to put everything in one giant spec namespace (what a nightmare.) While I certainly could put them right alongside the spec'd code in the same file, that hurts readability IMO.

You could put all your spec namespaces in a separate source path, but there's no real benefit to doing so unless you're in a situation where you want to distribute the code but not the specs or vice versa... hard to imagine what that'd be though.

MasterMastic

In my opinion the specs should be in the same ns as the code.

My main consideration is my personal philosophy, and technically it works out well. My philosophy is that the spec of a function is an integral part of it. It isn't an extra thing. It's definitely not "two concerns" as put in the OP. Actually, it's what the function is, because in terms of correctness: who cares about the implementation? who cares what you wrote in your defn? who cares about the identifier? who cares about anything but the spec?
I think it's weird because not only clojure.spec came later, also most languages will not let you have specs as an integral thing even if you wanted it to be, and anything close (tests in the code perhaps) is usually frowned upon, so of course it seems weird. But give it some thought, and you might reach a conclusion like I did (or you may not, this part is opinionated).

The only good reasons I can think of as to why you wouldn't want specs in the same ns are these two reasons:

  1. It clutters your code.
  2. You want to support Clojure versions pre Clojure 1.9.0.

As for the first reason, well, again, I think it's an integral part of your functions. If you find that it really is too much, my advice would be the same as if your ns would be too cluttered up regardless of spec: see if you can split it up.

As for the second reason, if you truly care, you can check in code if the clojure.spec ns is available, if not then shadow the names with functions/macros that are NOP. Another option is to use clojure-future-spec but I haven't tried it myself so I don't know how well it works.

Another way this works out well technically is that sometimes there's a cyclic dependency that you cannot handle with different namespaces, e.g. when your specs depend on your code (for function specs) and your code depends on your specs for parsing (see this question).

One other consideration depending on your use case - putting the specs alongside your main code limits use of your code to Clojure 1.9 clients, which may or may not be what you want. Like @levand, I would recommend a parallel namespace for each of your code namespaces.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!