Idiomatic approach for structuring Clojure source code [closed]
Asked Answered
D

1

11

I'm interested in how people structure their Clojure source code.

Being used to Java, I'm pretty familiar with the paradigm of one class per source code file, bundling all the data and method definitions with appropriate comments and annotations etc.

However Clojure offers a lot more flexibility, and I'm not sure how I should structure my project (likely to end up as a medium sized app, maybe 5,000 lines with three or four distinct subsystems)

In particular I'm wrestling with:

  • What guidelines should I use to determine whether code should be in a single namespace vs. separated out into different namespaces?
  • Should each protocol/datatype have it's own namespace + source file with associated set of functions?
  • When should I require vs. use other namespaces?
Dyarchy answered 17/6, 2010 at 14:47 Comment(0)
A
8

I'm from a Java background as well, along with quite a bit of Ruby and a little Go. Here's what I'm doing at the moment, about a month into Clojure:

  • I'm thinking of a namespace as a semantic unit, it's code that goes together for a particular purpose, like a datatype and the operations on it.

I have two conventions for namespaces vs files:

  • For smallish units that fit comfortably in one file (I'm using ~1000 lines as the limit where a file should be split) I have one namespace per file, with the directory path plus file name the same as the namespace. This is a good thing in Java, I think, it makes finding the namespace from the file or vice versa a breeze.
  • For larger units that need several files, I'm using the Go convention: The namespace matches the directory path, and all the files in the directory share the same namespace. In these cases I normally assign a primary file with a fixed name ('main') that loads and interacts with the others.

As a namespace example, I have a parser that reads a format and converts it to HTML. I have a single namespace for the parser (the semantic unit) and several files in the directory split on sub-functionality: Lexer, parser, HTML conversion and a main file that contains the primary public API for using the parser.

I wouldn't automatically use one namespace per datatype, it depends on the scope of the datatype. If it's a big one, perhaps. But for a datatype like Point, with two fields and a couple of functions, I'd rather subsume it into a more general namespace like Geometry.

Require vs. use:

  • Require with a suitably short alias almost everywhere.
  • This also allows reuse of core names: My special-purpose tree datatype has the operation "get" to fit with maps; using require there is no conflict: "get" is the Clojure core get, "tree/get" is the one for my datatype.
  • I'm using "use" only for what I consider "core extensions", like when I make my own "map-if" which is map and filter rolled into one.
Alverta answered 17/6, 2010 at 15:58 Comment(1)
thanks - that seems to make a lot of sense, great to get your perspectives!Dyarchy

© 2022 - 2024 — McMap. All rights reserved.