# Clojure's keyword namespacing convention Considered Harmful

**URL:** https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169
**Category:** Blogs
**Created:** [June 29, 2020, 11:48am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169 "2020-06-29T11:48:24Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![vvvvalvalval](https://clojureverse.org/user_avatar/clojureverse.org/vvvvalvalval/32/792_2.png) [@vvvvalvalval](https://clojureverse.org/u/vvvvalvalval)
#### Post date: [June 29, 2020, 11:48am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/1 "2020-06-29T11:48:24Z")

</div>

[https://vvvvalvalval.github.io/posts/clojure-key-namespacing-convention-considered-harmful.html](https://vvvvalvalval.github.io/posts/clojure-key-namespacing-convention-considered-harmful.html)

---

<div class="post-metadata">

### Author: ![shomiyamoto](https://clojureverse.org/user_avatar/clojureverse.org/shomiyamoto/32/3034_2.png) [@shomiyamoto](https://clojureverse.org/u/shomiyamoto)
#### Post date: [June 29, 2020, 2:19pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/2 "2020-06-29T14:19:47Z")

</div>

> Don’t do that. Don’t treat Clojure keywords as composite data structures. This is accidental complexity waiting to happen. Programmatic names are meant for humans to read, not for programs to interpret. Changing an attribute name should not be able to change the behaviour of your program. In Hickeyian terms: you’d be complecting naming with structure.

I include this into my personal list of Clojure don’ts. I’ve commited this mistake once or twice for the sake of conciseness (e.g., `:a/b` instead of `[:a :b]` or `{:something :a :other-thing :b}`) only to regret later for one reason or another.

Speaking of portability, do you have particular opinions about keywords vs strings as constants? I’ve recently converted all constants from keywords to strings (e.g, converted the values of `:user/language` from `:en-US` to `"en-US"`). By this change, I could eliminate all the code that keywordizes strings when I get them from browsers or stringifies keywords when I write them to database. Furthermore, it gave me a system-wide invariance that keywords never show up in entity values. The only downside is that strings don’t implement IFn unlike keywords, but this seems to me such a small price for big accidential complexity.

---

<div class="post-metadata">

### Author: ![mvarela](https://clojureverse.org/user_avatar/clojureverse.org/mvarela/32/1478_2.png) [@mvarela](https://clojureverse.org/u/mvarela)
#### Post date: [June 29, 2020, 2:41pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/3 "2020-06-29T14:41:54Z")

</div>

> [@shomiyamoto](#):
>
> I include this into my personal list of Clojure don’ts. I’ve commited this mistake once or twice for the sake of conciseness (e.g., `:a/b` instead of `[:a :b]` or `{:something :a :other-thing :b}` ) only to regret later for one reason or another.

It’s interesting, as this is often proposed as a means to avoid deeply-nested structures…

---

<div class="post-metadata">

### Author: ![shomiyamoto](https://clojureverse.org/user_avatar/clojureverse.org/shomiyamoto/32/3034_2.png) [@shomiyamoto](https://clojureverse.org/u/shomiyamoto)
#### Post date: [June 29, 2020, 4:00pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/4 "2020-06-29T16:00:09Z")

</div>

I’m afraid you misunderstood me. I didn’t talk about the usage of namespaced keywords as map keys. I’m simply opposed to expressing arbitrary data of two components as a single namespaced keyword.

When we use `:user/id` to express the user’s id, it’s a pointer to one definite thing. We could decompose it to the namespace and name parts, but we can consider it as one concept.

What I’d discourage is to use `:en/US` to mean “english used in the United States”. This is bad because you compress two separate ideas (language and region) into one thing. In such a data form, one cannot express “english (standard)” or “english spoken by Hispanics in the United States.” If we instead treat each idea separately, it’s a business just as normal as writing maps `{:language "en"}` and `{:language "en" :speakers "Hispanics" :region "US"}`.

---

<div class="post-metadata">

### Author: ![mvarela](https://clojureverse.org/user_avatar/clojureverse.org/mvarela/32/1478_2.png) [@mvarela](https://clojureverse.org/u/mvarela)
#### Post date: [June 29, 2020, 4:16pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/5 "2020-06-29T16:16:36Z")

</div>

Ok, I got you now…

---

<div class="post-metadata">

### Author: ![isaksky](https://clojureverse.org/letter_avatar_proxy/v4/letter/i/aeb1de/32.png) [@isaksky](https://clojureverse.org/u/isaksky)
#### Post date: [June 29, 2020, 5:20pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/6 "2020-06-29T17:20:39Z")

</div>

> “But I can just write a key-translation layer at the edge of my Clojure program…”  
> … and then you’d lose the main benefit of namespacing, which is the ability to track a data attribute across your entire system rather than just one component of it.

1. Sometimes there are other reasons for translating key names, like storage size. For example, longer key names lead to bigger storage size for for JSON (string) columns in SQL Server and even JSONB columns in Postgres.
2. Translating keys does not always mean you lose the ability to track it across your system. Sometimes it just means you search via a regex (for example, accepting either `_` or `/`.)

---

<div class="post-metadata">

### Author: ![isaksky](https://clojureverse.org/letter_avatar_proxy/v4/letter/i/aeb1de/32.png) [@isaksky](https://clojureverse.org/u/isaksky)
#### Post date: [June 29, 2020, 5:25pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/7 "2020-06-29T17:25:51Z")

</div>

> Don’t do that. Don’t treat Clojure keywords as composite data structures. …  
> …  
> As a basic example of how this may break, consider that it’s normal and expected to find in the same entity keys with different namespaces, e.g `:person/first-name` and `:myapp.user/singup-date` .

Why would checking the name/namespace of keys in the above map necessarily cause problems?

---

<div class="post-metadata">

### Author: ![seancorfield](https://clojureverse.org/user_avatar/clojureverse.org/seancorfield/32/195_2.png) [@seancorfield](https://clojureverse.org/u/seancorfield)
#### Post date: [June 29, 2020, 6:21pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/8 "2020-06-29T18:21:43Z")

</div>

I commented on Val’s blog post, but I’ll repeat it here:

If you have a name like `:customer_invoice_id` you cannot tell whether it “belongs” to a customer as `:customer/invoice_id` or to an invoice as `:customer_invoice/id` and that is a useful distinction to have in your code. It’s why `next.jdbc` defaults to `:table_name/column_name` for keywords in result set data.

But I do agree that slavishly translating snake\_case to kebab-case and back is not worthwhile if it adds no semantic value, i.e., don’t change `:table_name/column_name` to `:table-name/column-name` for no reason other than aesthetics.

It’s interesting to compare the default Clojure to JSON behavior in Cheshire and `clojure.data.json`:

```clojure
;; Cheshire default
user=> (json/generate-string {:a/b 42 :c/d "Sean"})
"{\"a/b\":42,\"c/d\":\"Sean\"}"
;; clojure.data.json default
user=> (j/write-str {:a/b 42 :c/d "Sean"})
"{\"b\":42,\"d\":\"Sean\"}"
;; Cheshire with just the name portion
user=> (json/generate-string {:a/b 42 :c/d "Sean"} {:key-fn name})
"{\"b\":42,\"d\":\"Sean\"}"
;; clojure.data.json with the qualified name
user=> (j/write-str {:a/b 42 :c/d "Sean"} :key-fn #(subs (str %) 1))
"{\"a\\/b\":42,\"c\\/d\":\"Sean\"}"
user=> 

```

I prefer `clojure.data.json`'s default behavior (and notice that it also explicitly escapes `/` for JSON whereas Cheshire does not).

---

<div class="post-metadata">

### Author: ![isaksky](https://clojureverse.org/letter_avatar_proxy/v4/letter/i/aeb1de/32.png) [@isaksky](https://clojureverse.org/u/isaksky)
#### Post date: [June 29, 2020, 7:44pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/9 "2020-06-29T19:44:05Z")

</div>

> [@seancorfield](#):
>
> If you have a name like `:customer_invoice_id` you cannot tell whether it “belongs” to a customer as `:customer/invoice_id` or to an invoice as `:customer_invoice/id` and that is a useful distinction to have in your code. It’s why `next.jdbc` defaults to `:table_name/column_name` for keywords in result set data.

This problem can be avoided by adding one more underscore between the namespace and the name. E.g., `:customer_invoice__id`.

---

<div class="post-metadata">

### Author: ![seancorfield](https://clojureverse.org/user_avatar/clojureverse.org/seancorfield/32/195_2.png) [@seancorfield](https://clojureverse.org/u/seancorfield)
#### Post date: [June 29, 2020, 7:51pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/10 "2020-06-29T19:51:10Z")

</div>

As I said in a comment on Val’s blog, that is a _horrible_ suggestion, in my opinion. Scanning code and expecting people to visually distinguish `_` from `__` in the middle of identifiers is a very error prone way to avoid/workaround a _core language feature that Clojure has had for years_ that has a very intentional and well-designed usage.

---

<div class="post-metadata">

### Author: ![StanDyck](https://clojureverse.org/user_avatar/clojureverse.org/standyck/32/2549_2.png) [@StanDyck](https://clojureverse.org/u/StanDyck)
#### Post date: [June 30, 2020, 1:44am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/11 "2020-06-30T01:44:57Z")

</div>

I can easily conceive of situations where it would be useful to do something like…

```clojure
(filter #(= (namespace %) "foo") some-sequence-of-namespaced-keywords)

```

Those situations would be made much more painful and error prone if my predicate function had to wrestle with parsing between the underscores in strings.

It’s also not clear to me how using namespaced keywords degrades the readability of my programmatic names.

---

<div class="post-metadata">

### Author: ![Anthony\_Leonard](https://clojureverse.org/user_avatar/clojureverse.org/anthony_leonard/32/2054_2.png) [@Anthony\_Leonard](https://clojureverse.org/u/Anthony_Leonard)
#### Post date: [July 1, 2020, 12:31am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/12 "2020-07-01T00:31:24Z")

</div>

Thought I’d link to the last time this came up on here as noone else had:

[https://v2.clojureverse.org/t/should-we-really-use-clojures-syntax-for-namespaced-keys](https://v2.clojureverse.org/t/should-we-really-use-clojures-syntax-for-namespaced-keys)

For me I think there is a lot of power in namespacing keys, and in keeping the names the same everywhere (e.g. as defined in a data dictionary or schema elsewhere, and allowing quick tracing of an attribute through code and logs.) But there is also power in having syntactic support in the language to shorten those names where (in context) there’s no ambiguity. So no need to be too strong on this. “sales\_customerInvoice\_id” in your DB and JSON APIs can be unambiguously translated to :sales.customer-invoice/id in Clojure I think, with little loss of meaning? In the end it’s what it’s called in the APIs and DB that counts.

Tend to agree that the name is just a longer structured name and the “first part” should not map to entities. But I am a (long-toothed) student of such matters.

---

<div class="post-metadata">

### Author: ![Anthony\_Leonard](https://clojureverse.org/user_avatar/clojureverse.org/anthony_leonard/32/2054_2.png) [@Anthony\_Leonard](https://clojureverse.org/u/Anthony_Leonard)
#### Post date: [July 1, 2020, 9:53am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/13 "2020-07-01T09:53:37Z")

</div>

Then again if your DB and API wire formats don’t support this, that could be seen as a failing of your DBs and API wire formats 😉 I wonder whether the term “lisp-case” is right? Perhaps “edn-case” or just “edn standard for namespaced keys” is better?

I guess accepting a lowest common denominator convention that trades universailty for loss of well understood structural semantics and related syntactic power is not an advance in general? The syntactic power to shorten where there’s no ambiguity is important I think. After all using fully qualified names all the time in real life would get pretty vexing! Only my Mother addresses me that way (occasionally.) Similarly try getting business users (and developers) to stop using the quick off-hand term they’ve used for years in their (bounded) context about a thing and start fully qualifying everywhere - including stories and documentation. They’re really not going to do it except for in those specific conversations where they’ll start crossing boundaries and there is an ambiguity,

Sorry for the ramble. I think it is an interesting topic. “Naming things …” It comes down to language itself, and how to express idiomatically in context while being globally precise in the words we use and their semantics if we can.

---

<div class="post-metadata">

### Author: ![mdiin](https://clojureverse.org/user_avatar/clojureverse.org/mdiin/32/3599_2.png) [@mdiin](https://clojureverse.org/u/mdiin)
#### Post date: [July 1, 2020, 11:27am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/14 "2020-07-01T11:27:47Z")

</div>

> [@Anthony\_Leonard](#):
>
> I wonder whether the term “lisp-case” is right? Perhaps “edn-case” or just “edn standard for namespaced keys” is better?

I think the usual name for this casing is kebab-case. 🙂🍢

---

<div class="post-metadata">

### Author: ![TristeFigure](https://clojureverse.org/user_avatar/clojureverse.org/tristefigure/32/2076_2.png) [@TristeFigure](https://clojureverse.org/u/TristeFigure)
#### Post date: [July 15, 2020, 11:07am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/15 "2020-07-15T11:07:11Z")

</div>

There is one reason keywords accept a namespace: to associate them with data in “public” maps such as metas.

For instance, observe this lib: [dvlopt.linux.gpio](https://github.com/dvlopt/linux.gpio.clj)

```
(gpio/handle device
  {17 {::gpio/state false
       ::gpio/tag :led-1}
   18 {::gpio/state true
       ::gpio/tag :led-2}}
  {::gpio/direction :output})

```

To me there is no point in using namespaces for the keywords. It’s a config map, it’s private to this lib, the collision risk is null, so this should be avoided. This is something I see too often. Discuss.

---

<div class="post-metadata">

### Author: ![Kah0ona](https://clojureverse.org/user_avatar/clojureverse.org/kah0ona/32/3056_2.png) [@Kah0ona](https://clojureverse.org/u/Kah0ona)
#### Post date: [July 15, 2020, 2:15pm UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/16 "2020-07-15T14:15:53Z")

</div>

> [@TristeFigure](#):
>
> It’s a config map, it’s private to this lib, the collision risk is null, so this should be avoided. This is something I see too often. Discuss.

Yeah, ok, but is it problematic that there are namespaces there? I don’t think so. And even though it’s private, it could mean in this lib other functions use this config. So for inspectability it might be useful, if you tap\> some values from a function, and you see namespaced keys you might have a better clue of what’s going on. If the config is combined into a big map that’s used as an `opts` argument, and travels trhough the functions of the whole lib, it might make sense.

Although, having said that, it’s probably not a big problem if it’s not namespaced either, but I kind of like it when it’s namespaced for the purpose of self-description when inspecting code.

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [January 14, 2021, 2:15am UTC](https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/17 "2021-01-14T02:15:54Z")

</div>

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