Идиоматический подход для структурирования Clojure исходного кода

Мне интересно, как люди структурируют свой исходный код Clojure.

Я привык к Java, я хорошо знаком с парадигмой одного класса для исходного кода, связывая все определения данных и методов с соответствующими комментариями и комментариями и т.д.

Однако Clojure предлагает гораздо большую гибкость, и я не уверен, как я должен структурировать свой проект (скорее всего, это приложение среднего размера, возможно, 5000 строк с тремя или четырьмя различными подсистемами)

В частности, я борюсь с:

  • Какие рекомендации следует использовать для определения того, должен ли код находиться в одном пространстве имен или разделен на разные пространства имен?
  • Должен ли каждый протокол/тип данных иметь собственное пространство имен + исходный файл с соответствующим набором функций?
  • Когда мне нужно vs. использовать другие пространства имен?

Ответ 1

Я тоже из фона Java, а также немного Ruby и немного Go. Вот что я делаю в данный момент, около месяца в Clojure:

  • Я думаю о пространстве имен как семантической единице, это код, который объединяется для определенной цели, типа типа данных и операций над ним.

У меня есть два соглашения для пространств имен и файлов:

  • Для небольших единиц, которые удобно размещаются в одном файле (я использую ~ 1000 строк в качестве предела, где нужно разбить файл). У меня есть одно пространство имен для каждого файла, а путь к каталогу плюс имя файла совпадает с именем пространства имен. Это хорошо, на мой взгляд, в Java, это делает поиск пространства имен из файла или наоборот ветерок.
  • Для больших единиц, которым требуется несколько файлов, я использую соглашение Go: пространство имен соответствует пути к каталогу, и все файлы в каталоге имеют одно и то же пространство имен. В этих случаях я обычно назначаю первичный файл с фиксированным именем ('main'), который загружает и взаимодействует с другими.

В качестве примера пространства имен у меня есть синтаксический анализатор, который читает формат и преобразует его в HTML. У меня есть одно пространство имен для синтаксического анализатора (семантическая единица) и несколько файлов в каталоге, разделенных на подфункции: Lexer, парсер, преобразование HTML и основной файл, содержащий первичный публичный API для использования парсера.

Я не буду автоматически использовать одно пространство имен для каждого типа данных, это зависит от области типа данных. Если это большой, возможно. Но для такого типа данных, как Point, с двумя полями и несколькими функциями, я предпочел бы использовать его в более общем пространстве имен, таком как Geometry.

Требовать от использования:

  • Требовать с подходящим коротким псевдонимом почти везде.
  • Это также позволяет повторно использовать имена ядер: у моего специального типа данных дерева есть операция "получить", чтобы соответствовать картам; используя require, нет конфликта: "get" - это Clojure core get, "tree/get" - это тот, который используется для моего типа данных.
  • Я использую "использование" только для того, что я считаю "основными расширениями", например, когда я делаю свой собственный "map-if", который является картой и фильтром, перекатированным в один.