Stop abstracting early
When I started working with Clojure, I wanted everything to be Clojure.
HTML? Vectors through Hiccup.
Configuration? Clojure maps.
SQL queries? Clojure lists.
After all, I might one day need to take advantage of Clojure’s functional abstractions to… um… well… I might need it, right?
Yes, s-expressions are elegant and trivial to handle with structural editing. Korma is indeed tasty and you get to manipulate queries using all the nice features that Cursive gives you.
Until you run into something that your library doesn’t directly support. Say you’re using PostgreSQL and want to use JSONB to store a particular map. Has the library maintainer already added support for JSONB? Are they going to do it at all, or will you need to get sidetracked to do it? Will you just end up taking some unsightly raw SQL to your Clojure code?
Moreover, if you start writing code at a higher layer of abstraction, will you lose access to tooling? On IDEA, I get SQL code validation for free, but lose that if I start writing my queries as nested Clojure lists.
I have a different approach now. I aim to stop abstracting as early as possible.
As Kris A. Jenkins pointed out on the YeSQL README:
Clojure is a great language for writing DSLs, but we don’t need a new one. SQL is already a mature DSL. And s-expressions are great, but here they’re not adding anything. This is parens-for-parens sake.
HugSQL, my current library of choice for SQL access from Clojure, follows the same philosophy. You keep your SQL code as SQL, generate function signatures from one or more files containing your queries, and just pass parameters to the resulting functions.
There are cases where going to a higher level might be the right decision for you. On Clojurians, Donald Ball described HoneySQL as “essentially just an AST for the most common 90% of sql“. That’s perfectly valid. If you need to build arbitrary queries on the fly, HoneySQL is definitely a better choice than concatenating strings as you go. Then again, maybe HugSQL’s snippets are enough.
Whatever path you end up taking, you need to be aware of the tradeoffs you’re making. Make sure you stop at the right level for your current use case. Chances are you’re not going to need a higher one, and if you do, you can always climb up that extra rung.