Spec, Re-frame, and Choosing Keywords

Hi there – I’m quite new and am adding spec to my re-frame project to verify app state on updates. I’m also trying to structure the DB map. But it seems what I want to do isn’t allowed, so maybe my approach is off :slight_smile: Any pointers would be greatly appreciated.

In structuring the DB, one way to go is nested maps:

{:person {:name "Bob"
          :passion "Painting"}}

Another way for this example might be namespaced keywords:

{:person/name "Bob"
 :person/passion "Painting"}

I started with this, but when adding Spec I tried to do something like:

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

But it didn’t seem to take – maybe because it wouldn’t be possible to resolve whether this is :person/name in the current namespace or :name in another namespace?

Is this not an idiomatic way of doing things? Am I using namespaced keywords incorrectly? Should I just stick with nested maps?


It should be :person/name with a single :. If you requre'd another namespaces, like

;;(require '[my.ns.person]) ;;EDIT: typo, pointed out by Sean below
(require '[my.ns.person :as person])

Then you can use ::person/name which will expand to :my.ns.person/name
See the section on keywords here:

As for being idiomatic, I think there is a trend towards increasing use of qualified (ie namespaced) keywords, but there are still situations where you may want or be fine with unqualified keywords. A major deciding factor is if the keys will end up inside maps where there may be name clashes. If so you can avoid this with qualified keys.


I assume you mean:

(require '[my.ns.person :as person])

otherwise you won’t get the person alias that you need for ::person/name to work.


Exactly, I forgot the actual alias

Thanks very much for your answers! I’ve tested this and it’s working.

On a related note – suppose I want to do something like:

(s/def :person/name string?)
(s/def :person/passion string?)
(s/def ::person 
  (s/keys :req [:person/name :person/passion]))

The :person map needs to be qualified, but it’s qualified under the current namespace whereas the :person/name and :person/passion keywords are “qualified” under a non-existant “:person” namespace. Correct?

It seems bad to have them be qualified to different namespaces, but I like being able to use :person/name.

You can use any qualified keyword you want for the Spec. :person/person for example. As you noted, the qualified keywords inside the hash map do not have to be tied to a code namespace – and they are “just” Specs – and neither does the overall Spec for the map.


The only argument I see for having :my.person/name be defined in the ns my.person is to make it simple to find the ns from the keyword.

Specs relying on a registry and namespace qualified keywords is a mechanism to give you the freedom to put your specs somewhere else.

1 Like

Specs relying on a registry and namespace qualified keywords is a mechanism to give you the freedom to put your specs somewhere else.

This makes sense to me. Supposing that I had two maps that shared a keyword, e.g. :name, and I wanted to spec this keyword differently:

(s/def :my.person/name string?)
(s/def :elonmusk.child/name int?)

Would you then separate those specs into different namespaces (and files)? To me, it seems like a lot to create a new file with a small number of specs, simply to namespace them – which is why the “un-namespaced” form :person/name worked for me.

Is there convention on where/how to organize specs in a project?

1 Like

I’d stick the specs in the same Clojure file unless you have a reason to do otherwise. Then you can also use the ::name shorthand to get a ns qualified key for the current ns.

An example for when you need to put specs somewhere else is if you need to add specs for someone else’s library.

I think the spec guide is the best resource you’ll find. If that doesn’t suffice, you can try posting in the Clojurians Slack and hope for a reply by Alex Miller :slight_smile:


Overall, I think I see where you’re coming from. Ns qualified keys didn’t make sense to me at first. I don’t think you have to worry too much about it. Ns qualified keys are great for avoiding conflicts. But if you don’t need that yet, normal keywords are probably fine!


No, but there are some considerations that might apply which would provide some guidance:

  • If you are writing a library that you want folks to be able to use on Clojure 1.8 or earlier, you must put the specs in a separate namespace that those users can simply ignore.
  • If you are writing a library targeting Clojure 1.9 or later, if you want usage of your specs to be optional for users, you still need to put them in a separate namespace that users can either require or not.
  • Otherwise, it’s generally easier to keep your function specs (fdef) with the functions that they describe (above them is probably clearer).
  • For data specs, it’s reasonable to keep them all together in one namespace, perhaps with predicate functions that they depend on.
  • If you have a large number of data specs, they’ll probably fall naturally into several different domain groups and each could be in its own namespace.

Specs can serve a lot of different purposes: I talk about the ways we use Spec at World Singles Networks in this blog post: https://corfield.org/blog/2019/09/13/using-spec/


Or hope for @seancorfield to reply here :smiley:


This is super helpful. Thanks very much for your response!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.