Лучшие практики по созданию и развертыванию приложений Clojure: хорошие учебники?

Я новичок в Clojure и начинаю экспериментировать с созданием приложения.

Пока что все, что я видел в учебниках по компиляции программ Clojure, включает в себя интерактивность. Например, "загрузите REPL и введите (load-file "this-or-that") для запуска. Это нормально, но этого недостаточно.

Я настолько привык к идиомам редактирования-компиляции языков, как C или Delphi, что меня инстинктивно заставляют вносить изменения, а затем нажимать "Mx compile".

Проблема в том, что "lein uberjar", который, как я понимаю, является эквивалентом "make", мучительно медленно выполняется даже в мире приветствия. Поэтому мне нужно выяснить, как работает этот компонент "интерактивной разработки", прекратить использовать uberjar, как будто он быстро готовится, и сохранить его только на конец дня.

Еще одна вещь, которую я заметил при сборке (используя lein uberjar), заключается в том, что небольшое графическое приложение, над которым я работаю, выдает всплывающие фреймы в процессе компиляции, как будто они выполняются во время компиляции. Это кажется мне немного нелогичным; это не так похоже на "сделать", как я думал.

Я знаю, что способ разработки Лиспа - это интерактивная работа в REPL, и я не пытаюсь это изменить: я бы хотел адаптироваться к этому образу жизни. К сожалению, я мало что видел в виде документации о том, как это сделать. Например, как сбросить текущее состояние машины. Просто кажется немного беспорядочным просто продолжать собирать отдельные фрагменты на лету, не имея возможности выполнить какой-либо сброс.

Большинство уроков, которые я видел по Clojure (и Lisp) в целом, похоже, сосредоточены на взломе в REPL. Лучшие практики по развертыванию приложений остаются для меня загадкой. Мои пользователи просто собираются быть пользователями; они не собираются быть разработчиками, которые собираются загружать файлы в REPL.

Итак, вот мой вопрос: есть ли ресурсы для полезной информации или учебных пособий по всему процессу создания приложения Clojure, включая развертывание?

(Примечание: у меня установлены все необходимые компоненты (например, Emacs, Slime, Leiningen и т. Д.), Так что это не вопрос об этом).

2 ответа

Решение

Пару быстрых подсказок, затем несколько ссылок:

Не использовать lein uberjar в процессе разработки; предпочитать lein jar, Разница в том, что lein uberjar помещает все ваши зависимости в сгенерированный jar (включая саму Clojure), так что ваш единственный jar является полностью автономным пакетом с вашим приложением внутри; lein jar только баночки свой собственный код. uberjar Подход имеет очевидные преимущества для развертывания, но для разработки вы должны просто использовать соответствующий путь к классу при запуске приложения, экономя время, необходимое для подготовки uberjar. Если вы не хотите вручную управлять classpath для тестовых прогонов, проверьте lein run плагин.

Также, скорее всего, большая часть вашего кода на самом деле не должна быть скомпилирована AOT. AOT необходим в некоторых сценариях взаимодействия с Java, но большую часть времени он приносит небольшое увеличение скорости запуска и раздражающие проблемы с двоичной совместимостью с различными выпусками Clojure. Я полагаю, что последний вопрос не имеет отношения к uberjarЭто автономный тип приложения, но любой код библиотеки, по крайней мере, должен быть оставлен для JIT-редактирования, если это вообще возможно. С Leiningen вы можете положить :namespaces пункт в defproject форма в project.clj определить, какие пространства имен должны быть скомпилированы; все, что вы пропустите, будет в настоящий момент JIT-ed по умолчанию. Старые версии Leiningen по умолчанию компилировали все, что на самом деле является хорошей причиной для обновления!

Что касается окон, появляющихся во время компиляции, я бы предположил, что вы выполняете код вывода окна во время раскрытия макроса или вне какого-либо определения функции или подобной конструкции. (Что-то вроде (println "Foo!") на верхнем уровне.) Это просто то, что вы не должны делать, я полагаю - если вы все равно не планируете запускать свой код как скрипт. Чтобы избежать проблемы, закройте побочный код в определениях функций и предоставьте точку входа в ваше приложение, используя :main пункт в project.clj, (Если вы говорите, :main fooтогда -main функция от foo Пространство имен будет использоваться в качестве точки входа в ваше приложение. Это по умолчанию, во всяком случае, и по крайней мере, вышеупомянутое lein run кажется, что имя жестко закодировано - не уверен насчет самого lein.)

Что касается сброса состояния REPL - вы можете просто перезапустить его. С SLIME Mx slime-restart-inferior-lisp будет делать это, поддерживая все остальные состояния вашего сеанса Emacs.

Смотрите также эти обсуждения в группе Google Clojure:

  1. Clojure для системного администрирования
  2. Готовим clojure для упаковки (было: Re: Clojure для системного администрирования)
  3. Leiningen, Clojure и библиотеки: что мне не хватает?

Нет, вы не вводите функции в REPL.

Вы редактируете свои исходные файлы, как обычно. Преимущество Lisp заключается в том, что система работает одновременно в фоновом режиме, поэтому вы можете скомпилировать отдельные функции из исходного файла и поместить их в работающую систему или даже заменить их там.

Если вы используете слизь, вы нажимаете C-c C-c в исходном файле, чтобы скомпилировать и загрузить функцию в точке. Затем вы можете переключиться на REPL для тестирования и изучения, но все, что вы хотите сохранить в качестве источника, вы помещаете в свои исходные файлы.

Обучающие программы обычно начинаются с того, что нужно что-то набирать в REPL, потому что для этого не нужно много настраивать, но серьезная разработка объединяет работающую систему и управление исходными файлами.


Просто чтобы проиллюстрировать, мой обычный рабочий процесс (я использую Common Lisp, но Clojure похож) выглядит так:

  • Запустить Emacs
  • M-x slime запустить Slime, систему Lisp, и соединить их через Swank
  • , (Команда) load-systemfoo загрузить текущий проект (компилируя только при необходимости) в образ
  • C-x b переключиться на исходный буфер
  • C-c ~ сделать исходный каталог текущим каталогом, а исходный пакет текущим пакетом REPL

Теперь я настроил систему в фоновом режиме. Работа - это:

  • изменить или добавить определение функции или класса
  • C-c C-c скомпилировать и загрузить его в образ
  • переключиться на REPL, проверить
  • отлаживать

Здесь нет существенных пауз для компиляции, потому что я никогда не собираю все сразу, только отдельные определения.

Другие вопросы по тегам