How do Midje and Speclj compare? [closed] - clojure

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Both look reasonably good. I'd like to understand what each library is particularly good at or lacking, especially for testing of web applications.

I haven't used speclj, and I was the first author of Midje. One point that hasn't been mentioned by others is that Midje tries to exploit differences between functional and object-oriented languages.
One difference is immutability. Because most functions depend only on their inputs, not on contained state, the kind of truth statements you make about them are different in feel than their object-oriented counterparts. In OO testing, you make examples of the form: "given this history and these inputs, this method produces such and so."
It would seem that examples in a functional language would just be simpler ones: "given these inputs, this function returns such and so". But I don't think that's quite right. I think the other functions in the system play a role analogous to state/history: they're one of the things you're trying to get intellectual control over. Functions and their relationships are the things you want the tests to help you think clearly about.
For that reason, Midje is written under the assumption that a sweet development process involves saying:
What do I want to be true of this function? In the world of the system, what's a good way to think of what this function does?
In the process of doing that, what other functions would be useful---would capture an important part of the domain---and what truth statements do I want to make about them?
And then, in typical mockist style, you develop roughly top-down or outside-in, allowing for the inevitable iteration as you recover from mistakes or have better ideas.
The end result is to be a big pile of functions, with their interrelationships documented by the tests or (as Midje calls them) the "facts" about functions and the functions they depend on. Various people have commented that Midje has a Prolog/logic programming feel to it, and that's not an accident. As always, tests are examples, but Midje tries to make them read more like truth statements. That's the justification for its only actually innovative feature, metaconstants. Here's an example of them:
(fact "right changes the direction, but not the position"
(right (snapshot north ...position...)) => (snapshot west ...position...)
(right (snapshot east ...position...)) => (snapshot north ...position...)
(right (snapshot south ...position...)) => (snapshot east ...position...)
(right (snapshot west ...position...)) => (snapshot south ...position...))
In this case, the actual position is irrelevant to what's true about the function right, except that it never changes. The idea of a metaconstant is that it is a value about which nothing is known except what's explicitly stated in the test. Too often in tests, it's hard to tell what's essential and what's incidental. That has a number of bad effects: understanding, maintainability, etc. Metaconstants provide clarity. If it matters that a value is a map or record that contains the value 3 for key :a, you say that explicitly:
(fact
(full-name ..person..) => "Brian Marick"
(provided
..person.. =contains=> {:given-name "Brian", :family-name "Marick"}))
This test is explicit about what matters about people---and also explicit about what doesn't matter (anything but the two names).
In math terms, Midje is trying to let you make statements like "for all x where x..." while still being a test tool rather than a theorem prover.
This approach was inspired by "London-style" mock-heavy TDD of the sort described in Growing Object-Oriented Software, which is the approach I usually use in writing Ruby code. But it's turned out to have a pretty different feel, in a way that's hard to describe. But it's a feel that needs more tool support than just with-redefs.
The upshot is that Midje is in part an attempt to find a style of functional TDD that's not just a port of OO TDD. It tries to be a general-purpose tool, too, but it's semi-opinionated software. As Abraham Lincoln said, "Those who like this sort of thing will find this the sort of thing they like."

The biggest benefit of using Midje is that it provides focused abstractions for testing things without testing all of their parts, parts that often drag in the whole rest of the world.
If you have a function that involves calling a subsidiary function to generate a timestamp, putting something in a database or message queue, make an API request, caching something, logging something, etc, you want know that these world-involving function calls occurred (and sometimes how many times they occurred), however actually executing them is irrelevant to the function you are testing, and the called functions will often deserve having their own unit tests.
Say you have this in your code:
(defn timestamp [] (System/currentTimeMillis))
(defn important-message [x y] (log/warnf "Really important message about %s." x))
(defn contrived [x & y]
(important-message x y)
{:x x :timestamp (timestamp)})
Here is how you could test it with midje:
(ns foo.core-test
(:require [midje.sweet :refer :all]
[foo.core :as base]))
(fact
(base/contrived 100) => {:x 100 :timestamp 1350526304739}
(provided (base/timestamp) => 1350526304739
(base/important-message 100 irrelevant) => anything :times 1))
This example is just a quick glimpse at what you can do with midje but demonstrates the essence of what it is good at. Here you can see there is very little extraneous complexity needed to express:
what the function should produce (despite the fact that what the
timestamp function would produce would be different each time you
call the function),
that the timestamp function and the logging function were called,
that the logging function was only called one time,
that the logging function received the expected first argument, and
that you don't care what the second argument it received was.
The main point I am trying to make with this example is that it's a very clean and compact way of expressing tests of complex code (and by complex I mean it has embedded parts that can be separated) in simple pieces rather than trying to test everything all at once. Testing everything all at once has its place, namely in integration testing.
I am admittedly biased because I actively use midje, whereas I have only looked at speclj, but my sense is that speclj is probably most attractive to people who have used the analogous Ruby library and find that way of thinking about tests ideal, based on that experience. That is a perfectly rspectable reason to chose a testing framework, and there are probably other nice things about it as well that hopefully others can comment on.

I'd definitely go with Speclj.
Speclj is simple to integrate and use. Its syntax is less flamboyant than Midje's. Speclj is based on RSpec to give you all the conforts that Ruby programmers are used to without losing the idiosyncrasies of Clojure.
And the auto runner in Speclj is great.
lein spec -a
Once you've used that for a while, you'll wonder how you ever got work done when you had to manually run tests.
Mocking is a non-issue since you can simply use with-redefs. #rplevy's example in Speclj would look like this.
(ns foo.core-spec
(:require [speclj.core :refer :all ]
[foo.core :as base]))
(describe "Core"
(it "contrives 100"
(let [message-params (atom nil)]
(with-redefs [base/timestamp (fn [] 1350526304739)
base/important-message #(reset! message-params [%1 %2])]
(should= {:x 100 :timestamp 1350526304739} (base/contrived 100))
(should= 100 (first #message-params))))))
This bare-bones approach to mocking is to-the-point; no misdirection.
As for testing web apps, Speclj works fine. In fact Speclj support is build into Joodo.
disclaimer: I wrote Speclj

I'd say that Midje is especially good at creating a DSL for expressing stubbing and mocking. If you care about stubbing and mocking, and want to use it a lot, I'd choose Midje over Speclj, because it has abstractions for expressing those types of tests that are more concise than the approach slagyr offered in his answer.
Another option, if you want a more light-weight approach, is the Conjure stubbing/mocking library intended to be used with clojure.test.
Where Speclj shines is in being a lot like RSpec, having 'describe' and 'it' included... Midje can support nested facts actually, but not as elegantly as Speclj.
disclaimer: I'm a contributor to Midje and Conjure. :)

I would suggest Midje over Speclj
For speclj, I don't think if it has good support for mocks, the documentation also looks sparse as compared to Midje.
Also the syntax for Midje is better:
(foo :bar) => :result compared to (should= (foo :bar) :result)

Related

Is there an idiomatic alternative to nil-punning in Clojure?

I'm reading some Clojure code at the moment that has a bunch of uninitialised values as nil for a numeric value in a record that gets passed around.
Now lots of the Clojure libraries treat this as idiomatic. Which means that it is an accepted convention.
But it also leads to NullPointerException, because not all the Clojure core functions can handle a nil as input. (Nor should they).
Other languages have the concept of Maybe or Option to proxy the value in the event that it is null, as a way of mitigating the NullPointerException risk. This is possible in Clojure - but not very common.
You can do some tricks with fnil but it doesn't solve every problem.
Another alternative is simply to set the uninitialised value to a symbol like :empty-value to force the user to handle this scenario explicitly in all the handling code. But this isn't really a big step-up from nil - because you don't really discover all the scenarios (in other people's code) until run-time.
My question is: Is there an idiomatic alternative to nil-punning in Clojure?
Not sure if you've read this lispcast post on nil-punning, but I do think it makes a pretty good case for why it's idiomatic and covers various important considerations that I didn't see mentioned in those other SO questions.
Basically, nil is a first-class thing in clojure. Despite its inherent conventional meaning, it is a proper value, and can be treated as such in many contexts, and in a context-dependent way. This makes it more flexible and powerful than null in the host language.
For example, something like this won't even compile in java:
if(null) {
....
}
Where as in clojure, (if nil ...) will work just fine. So there are many situations where you can use nil safely. I'm yet to see a java codebase that isn't littered with code like if(foo != null) { ... everywhere. Perhaps java 8's Optional will change this.
I think where you can run into issues quite easily is in java interop scenarios where you are dealing with actual nulls. A good clojure wrapper library can also help shield you from this in many cases, and its one good reason to prefer one over direct java interop where possible.
In light of this, you may want to re-consider fighting this current. But since you are asking about alternatives, here's one I think is great: prismatic's schema. Schema has a Maybe schema (and many other useful ones as well), and it works quite nicely in many scenarios. The library is quite popular and I have used it with success. FWIW, it is recommended in the recent clojure applied book.
Is there an idiomatic alternative to nil-punning in Clojure?
No. As leeor explains, nil-punning is idiomatic. But it's not as prevalent as in Common Lisp, where (I'm told) an empty list equates to nil.
Clojure used to work this way, but the CL functions that deal with lists correspond to Clojure functions that deal with sequences in general. And these sequences may be lazy, so there is a premium on unifying lazy sequences with others, so that any laziness can be preserved. I think this evolution happened about Clojure 1.2. Rich described it in detail here.
If you want option/maybe types, take a look at the core.typed library. In contrast to Prismatic Schema, this operates at compile time.

Lisp-family: how to escape object-oriented java-like thinking? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Backstory: I've made a lot of large and relatively complex projects in Java, have a lot of experience in embedded C programming. I've got acquainted with scheme and CL syntax and wrote some simple programms with racket.
Question: I've planned a rather big project and want to do it in racket. I've heard a lot of "if you "get" lisp, you will become a better programmer", etc. But every time I try to plan or write a program I still "decompose" the task with familiar stateful objects with interfaces.
Are there "design patterns" for lisp? How to "get" lisp-family "mojo"? How to escape object-oriented constraint on your thinking? How to apply functional programming ideas boosted by powerful macro-facitilties? I tried studying source code of big projects on github (Light Table, for instance) and got more confused, rather than enlightened.
EDIT1 (less ambigious questions): is there a good literatue on the topic, that you can recommend or are there good open source projects written in cl/scheme/clojure that are of high quality and can serve as a good example?
A number of "paradigms" have come into fashion over the years:
structured programming, object oriented, functional, etc. More will come.
Even after a paradigm falls out of fashion, it can still be good at solving the particular problems that first made it popular.
So for example using OOP for a GUI is still natural. (Most GUI frameworks have a bunch of states modified by messages/events.)
Racket is multi-paradigm. It has a class system. I rarely use it,
but it's available when an OO approach makes sense for the problem.
Common Lisp has multimethods and CLOS. Clojure has multimethods and Java class interop.
And anyway, basic stateful OOP ~= mutating a variable in a closure:
#lang racket
;; My First Little Object
(define obj
(let ([val #f])
(match-lambda*
[(list) val]
[(list 'double) (set! val (* 2 val))]
[(list v) (set! val v)])))
obj ;#<procedure:obj>
(obj) ;#f
(obj 42)
(obj) ;42
(obj 'double)
(obj) ;84
Is this a great object system? No. But it helps you see that the essence of OOP is encapsulating state with functions that modify it. And you can do this in Lisp, easily.
What I'm getting at: I don't think using Lisp is about being "anti-OOP" or "pro-functional". Instead, it's a great way to play with (and use in production) the basic building blocks of programming. You can explore different paradigms. You can experiment with ideas like "code is data and vice versa".
I don't see Lisp as some sort of spiritual experience. At most, it's like Zen, and satori is the realization that all of these paradigms are just different sides of the same coin. They're all wonderful, and they all suck. The paradigm pointing at the solution, is not the solution. Blah blah blah. :)
My practical advice is, it sounds like you want to round out your experience with functional programming. If you must do this the first time on a big project, that's challenging. But in that case, try to break your program into pieces that "maintain state" vs. "calculate things". The latter are where you can try to focus on "being more functional". Look for opportunities to write pure functions. Chain them together. Learn how to use higher-order functions. And finally, connect them to the rest of your application -- which can continue to be stateful and OOP and imperative. That's OK, for now, and maybe forever.
A way to compare programming in OO vs Lisp (and "functional" programming in general) is to look at what each "paradigm" enables for the programmer.
One viewpoint in this line of reasoning, which looks at representations of data, is that the OO style makes it easier to extend data representations, but makes it more difficult to add operations on data. In contrast, the functional style makes it easier to add operations but harder to add new data representations.
Concretely, if there is a Printer interface, with OO, it's very easy to add a new HPPrinter class that implements the interface, but if you want to add a new method to an existing interface, you must edit every existing class that implements the interface, which is more difficult and may be impossible if the class definitions are hidden in a library.
In contrast, with the functional style, functions (instead of classes) are the unit of code, so one can easily add a new operation (just write a function). However, each function is responsible for dispatching according to the kind of input, so adding a new data representation requires editing all existing functions that operate on that kind of data.
Determining which style is more appropriate for your domain depends on whether you are more likely to add representations or operations.
This is a high-level generalization of course, and each style has developed solutions to cope with the tradeoffs mentioned (eg mixins for OO), but I think it still holds to a large degree.
Here is a well-known academic paper that captured the idea 25 years ago.
Here are some notes from a recent course (I taught) describing the same philosophy.
(Note that the course follows the How to Design Programs curriculum, which initially emphasizes the functional approach, but later transitions to the OO style.)
edit: Of course this only answers part of your question and does not address the (more or less orthogonal) topic of macros. For that I refer to Greg Hendershott's excellent tutorial.
A personal view:
If you parameterise an object design in the names of the classes and their methods - as you might do with C++ templates - then you end up with something that looks quite like a functional design. In other words, functional programming does not make useless distinctions between similar structures because their parts go by different names.
My exposure has been to Clojure, which tries to steal the good bit from object programming
working to interfaces
while discarding the dodgy and useless bits
concrete inheritance
traditional data hiding.
Opinions vary about how successful this programme has been.
Since Clojure is expressed in Java (or some equivalent), not only can objects do what functions can do, there is a regular mapping from one to the other.
So where can any functional advantage lie? I'd say expressiveness. There are lots of repetitive things you do in programs that are not worth capturing in Java - who used lambdas before Java provided compact syntax for them? Yet the mechanism was always there.
And Lisps have macros, which have the effect of making all structures first class. And there's a synergy between these aspects that you will enjoy.
The "Gang of 4" design patterns apply to the Lisp family just as much as they do to other languages. I use CL, so this is more of a CL perspective/commentary.
Here's the difference: Think in terms of methods that operate on families of types. That's what defgeneric and defmethod are all about. You should use defstruct and defclass as containers for your data, keeping in mind that all you really get are accessors to the data. defmethod is basically your usual class method (more or less) from the perspective of an operator on a group of classes or types (multiple inheritance.)
You'll find that you'll use defun and define a lot. That's normal. When you do see commonality in parameter lists and associated types, then you'll optimize using defgeneric/defmethod. (Look for CL quadtree code on github, for an example.)
Macros: Useful when you need to glue code around a set of forms. Like when you need to ensure that resources are reclaimed (closing files) or the C++ "protocol" style using protected virtual methods to ensure specific pre- and post-processing.
And, finally, don't hesitate to return a lambda to encapsulate internal machinery. That's probably the best way to implement an iterator ("let over lambda" style.)
Hope this gets you started.

Clojure loop/recur pattern, is it bad to use?

I'm in the process of learning Clojure, and I'm using 4Clojure
as a resource. I can solve many of the "easy" questions on the site, but for me thinking in a functional programming mindset still doesn't come naturally (I'm coming from Java). As a result, I use a loop/recur iterative pattern in most of my seq-building implementations because that's how I'm used to thinking.
However, when I look at the answers from more experienced Clojure users, they do things in a much more functional style. For example, in a problem about implementing the range function, my answer was the following:
(fn [start limit]
(loop [x start y limit output '()]
(if (< x y)
(recur (inc x) y (conj output x))
(reverse output))))
While this worked, other users did things like this:
(fn [x y] (take (- y x) (iterate inc x)))
My function is more verbose and I had no idea the "iterate" function even existed. But was my answer worse in an efficiency sense? Is loop/recur somehow worse to use than alternatives? I fear this sort of thing is going to happen a lot to me in the future, as there are still many functions like iterate I don't know about.
The second variant returns a lazy sequence, which may indeed be more efficient, especially if the range is big.
The other thing is that the second solution conveys the idea better. To put it differently, it describes the intent instead of implementation. It takes less time to understand it as compared to your code, where you have to read through the loop body and build a model of control flow in your head.
Regarding the discovery of the new functions: yes, you may not know in advance that some function is already defined. It is easier in, say, Haskell, where you can search for a function by its type signature, but with some experience you will learn to recognize the functional programming patterns like this. You will write the code like the second variant, and then look for something working like take and iterate in the standard library.
Bookmark the Clojure Cheetsheet website, and always have a browser tab open to it.
Study all of the functions, and especially read the examples they link to (the http://clojuredocs.org website).
The site http://clojure-doc.org is also very useful (yes, the two names are almost identical but not quite)
The question should not be about performance (it depends!) but about communication: when using loop/recur or plain recursion or lazy-seq or sometimes even reduce, you make your code harder to understand: because the reader has to understand how you perform your iteration before getting to understand what you are computing.
loop/recur is real Clojure, and idiomatic. It's there for a reason. And often there is no better way. But many people find that once one gets used to it, it's very convenient to build many functions out of building blocks such as iterate. Clojure has a very nice collection of them. I started out writing things from scratch using truly recursive algorithms and then loop/recur. Personally, I wouldn't claim that it's better to use the functional building blocks functions, but I've come to love using them. It's one of the things that's great about Clojure.
(Yes, the many of the building block functions are lazy, as are e.g. for and map, which are more general-purpose. Laziness can be good, but I'm not religious about it. Sometimes it's more efficient. Sometimes it's not. Sometimes it's beautiful. Sometimes it's a pain in the rear. Sometimes all that.)
Loop and recur are not bad - in fact, if you look at the source code for many of the built-in functions, you will find that is what they do - the provided functions are often an abstraction of common patterns which can make your code easier to understand. How you are doing things is typical for many when they first start. How you are approaching this seems correct to me. You are not just writing your solution and moving on. You are writing your solution and then looking at how others have solved the same problem and making a comparison. This is the right road to improvement. Highly recommend that when you find an alternative solution which seems more elegant/efficient/clear, analyse it, look at the source code of the built-in functions it uses and things will slowly come together.
loop ... recur is an optimisation for recursive tail calls, and should
always be used where it applies.
range is lazy, so your version of it should strive to be so.
loop ... recur can't do this.
All the sequence functions that can sensibly be lazy (iterate,
filter, map, take-while ...) are so. As you know, you can use some of these
to build a lazy range. As #cgrand explains, this is the preferred approach.
If you prefer, you can build a lazy range from scratch:
(defn range [x y]
(lazy-seq
(when (< x y)
(cons x (range (inc x) y)))))
I wondered the same thing for some days but truly many tims I do not see any better alternative than loop recur.
Some jobs are not fully "reduce" or "map". It is the case when you update data base on a buffer you mutates at every iteration.
Loop recur is very convienient where "non linear precise work" is require. It looks like more imperative but if I remember well Clojure was designed with pragmatism. Buy yet, pragmatism means choosing what is more effficient.
That is why in complex programs, I use both Clojure and java code mixed. sometimes java is just more clear for "low level" or iterative jobs like taking a specific value and so on while I see Clojure functions more useful for big data processing (without so much level of detail : global filters, etc.).
Some people say that we must stock with Clojure as much as possible but I do not see any reason not to use Java. I did not programmed a lot but Clojure/Java is the best interop I have ever seen, very complementary approaches.

Clojure closure efficiency?

Quite often, I swap! an atom value using an anonymous function that uses one or more external values in calculating the new value. There are two ways to do this, one with what I understand is a closure and one not, and my question is which is the better / more efficient way to do it?
Here's a simple made-up example -- adding a variable numeric value to an atom -- showing both approaches:
(def my-atom (atom 0))
(defn add-val-with-closure [n]
(swap! my-atom
(fn [curr-val]
;; we pull 'n' from outside the scope of the function
;; asking the compiler to do some magic to make this work
(+ curr-val n)) ))
(defn add-val-no-closure [n]
(swap! my-atom
(fn [curr-val val-to-add]
;; we bring 'n' into the scope of the function as the second function parameter
;; so no closure is needed
(+ curr-val val-to-add))
n))
This is a made-up example, and of course, you wouldn't actually write this code to solve this specific problem, because:
(swap! my-atom + n)
does the same thing without any need for an additional function.
But in more complicated cases you do need a function, and then the question arises. For me, the two ways of solving the problem are of about equal complexity from a coding perspective. If that's the case, which should I prefer? My working assumption is that the non-closure method is the better one (because it's simpler for the compiler to implement).
There's a third way to solve the problem, which is not to use an anonymous function. If you use a separate named function, then you can't use a closure and the question doesn't arise. But inlining an anonymous function often makes for more readable code, and I'd like to leave that pattern in my toolkit.
Thanks!
edit in response to A. Webb's answer below (this was too long to put into a comment):
My use of the word "efficiency" in the question was misleading. Better words might have been "elegance" or "simplicity."
One of the things that I like about Clojure is that while you can write code to execute any particular algorithm faster in other languages, if you write idiomatic Clojure code it's going to be decently fast, and it's going to be simple, elegant, and maintainable. As the problems you're trying to solve get more complex, the simplicity, elegance and maintainability get more and more important. IMO, Clojure is the most "efficient" tool in this sense for solving a whole range of complex problems.
My question was really -- given that there are two ways that I can solve this problem, what's the more idiomatic and Clojure-esque way of doing it? For me when I ask that question, how 'fast' the two approaches are is one consideration. It's not the most important one, but I still think it's a legitimate consideration if this is a common pattern and the different approaches are a wash from other perspectives. I take A. Webb's answer below to be, "Whoa! Pull back from the weeds! The compiler will handle either approach just fine, and the relative efficiency of each approach is anyway unknowable without getting deeper into the weeds of target platforms and the like. So take your hint from the name of the language and when it makes sense to do so, use closures."
closing edit on April 10, 2014
I'm going to mark A. Webb's answer as accepted, although I'm really accepting A. Webb's answer and omiel's answer -- unfortunately I can't accept them both, and adding my own answer that rolls them up seems just a bit gratuitous.
One of the many things that I love about Clojure is the community of people who work together on it. Learning a computer language doesn't just mean learning code syntax -- more fundamentally it means learning patterns of thinking about and understanding problems. Clojure, and Lisp behind it, has an incredibly powerful set of such patterns. For example, homoiconicity ("code as data") means that you can dynamically generate code at compile time using macros, or destructuring allows you to concisely and readably unpack complex data structures. None of the patterns are unique to Clojure, but Clojure brings them all together in ways that make solving problems a joy. And the only way to learn those patterns is from people who know and use them already. When I first picked Clojure more than a year ago, one of the reasons that I picked it over Scala and other contenders was the reputation of the Clojure community for being helpful and constructive. And I haven't been disappointed -- this exchange around my question, like so many others on StackOverflow and elsewhere, shows how willing the community is to help a newcomer like me -- thank you!
After you figure out the implementation details of the current compiler version for the current version of your current target host, then you'll have to start worrying about the optimizer and the JIT and then the target computer's processors.
You are too deep in the weeds, turn back to the main path.
Closing over free variables when applicable is the natural thing to do and an extremely important idiom. You may assume a language named Clojure has good support for closures.
I prefer the first approach as being simpler (as long as the closure is simple) and somewhat easier to read. I often struggle reading code where you have an anonymous function immediately called with parameters ; I have to resolve to count parentheses to be sure of what's happening, and I feel it's not a good thing.
I think the only way it could be the wrong thing to do is if the closures closes over a value that shouldn't be captured, like the head of a long lazy sequence.

Resolving Clojure circular dependencies

I'm working on some Clojure code that has some circular dependencies between different namespaces and I'm trying to work out the best way of resolving them.
Basic issue is that I get a "No such var: namespace/functionname" error in one of the files
I tried to "declare" the function but then it complains with: "Can't refer to a qualified var that doesn't exist"
I could of course refactor the entire codebase but that seems impractical to do every time you have a dependency to resolve..... and might get very ugly for certain networks of circular dependencies
I could separate out a bunch of interfaces / protocols / declarations into a separate file and have everything refer to that.... but that seems like it would end up getting messy and spoil the current nice modular structure that I have with related functionality grouped together
Any thoughts? What is the best way to handle this kind of circular dependency in Clojure?
I remember a number of discussions on namespaces in Clojure -- on the mailing list and elsewhere -- and I have to tell you that the consensus (and, AFAICT, the current orientation of Clojure's design) is that circular dependencies are a design's cry for refactoring. Workarounds might occasionally be possible, but ugly, possibly problematic for performance (if you make things needlessly "dynamic"), not guaranteed to work forever etc.
Now you say that the circular project structure is nice and modular. But, why would you call it that if everything depends on everything...? Also, "every time you have a dependency to resolve" shouldn't be very often if you plan for a tree-like dependency structure ahead of time. And to address your idea of putting some basic protocols and the like in their own namespace, I have to say that many a time I've wished that projects would do precisely that. I find it tremendously helpful to my ability to skim a codebase and get an idea of what kind of abstractions it's working with quickly.
To summarise, my vote goes to refactoring.
I had a similar problem with some gui code, what I ended up doing is,
(defn- frame [args]
((resolve 'project.gui/frame) args))
This allowed me to resolve the call during runtime, this gets called from a menu item in frame so I was 100% sure frame was defined because it was being called from the frame itself, keep in mind that resolve may return nil.
I am having this same problem constantly. As much as many developers don't want to admit it, it is a serious design flaw in the language. Circular dependencies are a normal condition of real objects. A body cannot survive without a heart, and the heart can't survive without the body.
Resolving at call time may be possible, but it won't be optimal. Take the case where you have an API, as part of that api is error reporting methods but the api creates an object that has its own methods, those objects will need the error reporting and you have your circular dependency. Error checking and reporting functions will be called often so resolving at the time they are called isn't an option.
The solution in this case, and most cases, is to move code that doesn't have dependencies into separate (util) namespaces where they can be freely shared. I have not yet run into a case where the problem cannot be resolved with this technique. This makes maintaining complete, functional, business objects nearly impossible but it seems to be the only option. Clojure has a long way to go before it is a mature language capable of accurately modeling the real world, until then dividing up code in illogical ways is the only way to eliminate these dependencies.
If A.a() depends on B.a() and B.b() relies on A.b() the only solution is to move B.a() to C.a() and/or A.b() into C.b() even though C technically doesn't exist in the real world.
Either move everything to one giant source file so that you have no external dependencies, or else refactor. Personally I'd go with refactor, but when you really get down to it, it's all about aesthetics. Some people like KLOCS and spaghetti code, so there's no accounting for taste.
It's good to think carefully about the design. Circular dependencies may be telling us that we're confused about something important.
Here's a trick I've used to work around circular dependencies in one or two cases.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; example/a.cljc
(ns example.a
(:require [example.b :as b]))
(defn foo []
(println "foo"))
#?(
:clj
(alter-var-root #'b/foo (constantly foo)) ; <- in clojure do this
:cljs
(set! b/foo foo) ; <- in clojurescript do this
)
(defn barfoo []
(b/bar)
(foo))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; example/b.cljc
(ns example.b)
;; Avoid circular dependency. This gets set by example.a
(defonce foo nil)
(defn bar []
(println "bar"))
(defn foobar []
(foo)
(bar))
I learned this trick from Dan Holmsand's code in Reagent.