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

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

Будучи привыкшим к Java, я довольно хорошо знаком с парадигмой одного класса на файл исходного кода, связывая все данные и определения методов с соответствующими комментариями и аннотациями и т. Д.

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

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

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

1 ответ

Решение

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

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

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

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

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

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

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

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