How to Name Clojure Protocols

This is a blog about the development of Yeller, The Exception Tracker with Answers

Read more about Yeller here

Is there any sensible consensus on good naming convention for Clojure Protocols?

Naming things is pretty hard. Naming the abstractions used by your software is often even more difficult. But aside from just the words you use, Clojure programmers face another issue:

Do you name a protocol:

  • IDeref
  • or Deref

This came up recently on the clojure mailing list, and I thought I’d do some digging into what the different conventions across clojure libraries are:

IBlah

Blah

That’s an incomplete list, partly taken from Yeller’s dependencies, partly from the clojure toolbox, but you can see that nearly all clojure libraries avoid the I prefix. That seems pretty conclusive.

The Right Approach to Protocol Names

So, given these two options, which style should you use to name your protocols? I strongly recommend the former: plain names without an I prefix. The I prefix seems to be mostly left over Java legacy - we have tools that let you see what’s a protocol vs a type, and adding that “this is an interface” is just line noise.

Further, if you’re dealing with business oriented software (which many of us are), the business names don’t ever start with I. They’re just “Auction” or “Store” and so on. Your code should reflect that.

This does go against the convention from Clojure.core for interfaces, but even there this convention isn’t always applied. Here are the defprotocol calls from clojure.core:

ag defprotocol src

src/clj/clojure/core/reducers.clj
81:(defprotocol CollFold

src/clj/clojure/core/protocols.clj
13:(defprotocol CollReduce
19:(defprotocol InternalReduce
180:(defprotocol IKVReduce

src/clj/clojure/data.clj
67:(defprotocol ^{:added "1.3"} EqualityPartition
71:(defprotocol ^{:added "1.3"} Diff

src/clj/clojure/java/io.clj
35:(defprotocol ^{:added "1.2"} Coercions
69:(defprotocol ^{:added "1.2"} IOFactory

src/clj/clojure/reflect/java.clj
184:(defprotocol ClassResolver

src/clj/clojure/reflect.clj
44:(defprotocol Reflector
48:(defprotocol TypeReference

However, basically every Java interface that clojure uses adopts this convention. Samples:

ag "public interface" src

src/jvm/clojure/lang/IKeywordLookup.java
15:public interface IKeywordLookup{

src/jvm/clojure/lang/ILookup.java
15:public interface ILookup{

src/jvm/clojure/lang/ILookupSite.java
15:public interface ILookupSite{

src/jvm/clojure/lang/ILookupThunk.java
15:public interface ILookupThunk{

src/jvm/clojure/lang/IMapEntry.java
15:public interface IMapEntry extends Map.Entry{

src/jvm/clojure/lang/IMeta.java
15:public interface IMeta {

But not all of them! So there’s little consistency in Clojure itself. No wonder folk wonder about it on the mailing list.

Here are some sample protocols named in this style from Yeller’s codebase:

ag "defprotocol" src

src/yeller/collector/offset_store.clj
8:(defprotocol OffsetStorage

src/yeller/exception_store.clj
11:(defprotocol ExceptionQuery
14:(defprotocol ExceptionLookup
18:(defprotocol ExceptionStatus
21:(defprotocol GroupsIncidents
24:(defprotocol CreateProject

src/yeller/infrastructure/pool.clj
12:(defprotocol KeyPool

src/yeller/timeseries.clj
9:(defprotocol TimeSeries

Overall, it looks like libraries overwhelmingly avoid the I prefix style, and you should probably adopt that as well.

References

This is a blog about the development of Yeller, the Exception Tracker with Answers.

Read more about Yeller here

Looking for more about running production applications, debugging, Clojure development and distributed systems? Subscribe to our newsletter: