Идиоматический подход к структурированию исходного кода 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", которое представляет собой карту и фильтр, объединенные в одно.