Daniel Compton

The personal blog of Daniel Compton - Projects

Announcing defn-spec, a library to create specs inline with your defn

I’m pleased to announce the initial release of defn-spec, a library to create specs inline with your defn.

[net.danielcompton/defn-spec-alpha "0.1.0"]

A quick peek at defn-spec:

(ds/defn to-zoned-dt :- ::zoned-date-time
  [instant :- ::instant
   zone-id :- ::zone-id]
  (ZonedDateTime/ofInstant instant zone-id))

One of the features in Schema that I always appreciated was inline function schemas, using a schema.core/defn macro.

When spec was released it had many similarities to Schema, but one thing it didn’t have was a way of expressing specs inline with your function definition. Spec only supported defining function specs separately with fdef. This does have some advantages, it forces you to think carefully about changing your specs, and to be aware of possibly breaking consumers. While this is valuable, not all code is written to these constraints, and I found having fdef’s separate from the function definition had a number of downsides.

When writing Clojure, I noticed that I often resisted writing specs for functions. After thinking about it I realised that I didn’t want to duplicate information from the defn into the fdef. It’s not a huge deal, but it was enough to deter me from writing specs on code that was being heavily modified. This is a really useful time to have basic specs on your functions, so that you can catch refactorings gone wrong early.

I created defn-spec to increase the locality of the spec definitions, and to reduce the activation energy to start adding specs to your codebase. defn-spec copies the syntax (and implementation) of Schema’s defn macro. This has the advantage of adopting a proven design, familiarity for many Clojurists, and the ability to work with existing tooling that understands the Schema defn macro.

Benefits and tradeoffs

Like all things in life, defn-spec has benefits and tradeoffs:

Benefits

Tradeoffs

This is similar to Orchestra’s defn-spec macro, but allows for optionally only speccing part of the function, and matches the well-known Schema defn syntax. Try them both out though, and see which one works best for you. defn-spec is still missing some features from the defn macro like destructuring, but they are on the roadmap to be added soon. I’m releasing this early to get feedback from other users.

defn-spec will follow Spec’s release cycle, and there will be a new set of namespaces and artifacts for spec-alpha2 and beyond. If you have features/bug reports, feel free to post them on GitHub.