Macros that makes namespace aliases easy.
https://github.com/aelfsyg/alias-ns.git
Qualified keywords have ballooned in popularity since the release of spec with Clojure 1.9. And thankfully so! A creed amongst Clojurians is that maps should be open to modification, meaning that I should be able to add data to a map without worrying that it will break its consumer, and that when processing maps we shouldn't remove data using something like select-keys without good reason.
But there was a problem that occasionally (assoc m k v) would be destructive — because we were all using the same keys. Every application seemingly has its own :id, :user, :service, :credentials; and associng a new one would dissoc the previous and break whoever was waiting to consume it. With the introduction of qualified keywords, I can instead assoc :ae.bespoke/id without fear.
Qualified, sometimes called namespaced, keywords abound in my code. For larger projects there might be up to ten namespaces to which a keyword belongs, think: :ae.bespoke.user/id, :ae.bespoke.item/id, :ae.bespoke.process/id. And Clojure allows us to use aliases, most commonly defined within (ns ... (:require [ae.bespoke.user :as user])), so the keywords can be shrunk to just ::user/id.
I only very occasionally have a problem with this, here's an example. You start developing your application in ae.bespoke.core, but decide to split user functionality into ae.bespoke.user. This works well until you want to reference a user's id in core, and try ::user/id as you do in many of your other source files. It fails because core doesn't require user, and if it did you would have a circular dependency because user itself requires core.
What are the alternatives? Use :ae.bespoke.user/id instead of ::user/id. This is what I would recommend most of the time, but it has the principal drawback that when referencing this key throughout our code we must always be thinking about whether the current namespace depends upon the user namespace.
To aleviate this aspect of cognitive load, I have created alias+ns. It's a macro that allows one to alias a namespace that has not been required in the current namespace. So in ae.bespoke.user, this would be valid:
| |
And if using many aliases, use aliases+ns:
| |
You can do all this without the worry of circular dependencies. Just don't try to define functions or variables in the aliased namespace, or maybe do but I haven't a clue what would happen.
I won't be arrogant and claim that this is the best thing to do in all cases, or even that it is best in most cases; but I have found it to be very useful in projects with large numbers of namespaces, where it also reduces the pain of refactoring when code moves between them. I hope you find a use for it too.