While working on stuff (of course in Clojure), I kept running into problems with namespaces having circular dependencies. For example I’d have an app.router namespace that defines the, uh, routes. I’d have an app.url namespace that contains helper functions to generate absolute URLs based on route data (so it depends on app.router). I’d have an app.views namespace that uses those URL helpers (thus depending on app.url), and these views would be referenced in the routes so app.router would require app.views.

This completes the dependency circle and is the beginning of my journey. There are a bunch of ways to deal with circular dependencies in Clojure, but I won’t go in-depth about all of them.

timelapse photography of fire

Protocols and multimethods

These are my go-to tools for breaking the dependency circle. Put the declaration of the protocol (defprotocol) or multimethod (defmulti) in a separate namespace that then others can reference. In the example above, I’d have the Link protocol in the app.url namespace setting up an href function, while in app.router I’d have the implementation (extend-protocol) that closes over the router, and in the app.views I could use the protocol function without issue. It’d be the same with a multimethod too.

:as-alias

Especially in a re-frame frontend app, I often require namespaces just so I have a shorter alias to use with namespaced keywords. In newer Clojure versions it’s possible to use :as-alias to only introduce the namespace alias without actually requiring the namespace. Just be sure that the aliased namespace is required “properly” somewhere or it won’t be loaded at all and any defs, reg-subs or similar re-frame registrations won’t happen.

Passing the functions around

In a functional language like Clojure, functions are things too that can be passed around just like strings or maps can be. So it’s possible to pass the dependencies around as well as a form of dependency injection. Personally I’m not a big fan of this, as it just doesn’t feel right to me, but that’s just me.