Как быть с переменной в библиотеке, которую нужно установить вне ее?

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

Одной из проблем является работа с общей базой данных uri, от которой зависит большинство операций, но которая должна быть установлена ​​проектом с помощью библиотеки. Интересно, есть ли хорошо зарекомендовавший себя способ сделать это. Вот несколько альтернатив, о которых я думал:

  • Удаление символа uri в библиотеке и добавление uri в качестве аргумента для каждой функции, которая обращается к базе данных.

  • Изменение его с помощью alter-var-root или аналогичного механизма в функции инициализации

  • Хранить его в библиотеке как динамическую переменную *uri* и переопределять значение в, надеюсь, небольшом слое адаптера, таком как

    (def my-url...bla...)

    (defn my-fun [args] (with-datomic-uri my-uri (применить библиотеку/my-fun args))

  • Сохранение uri как атома в библиотеке


person konr    schedule 19.12.2013    source источник
comment
Ожидаете ли вы, что пользователи захотят изменить uri во время выполнения, или его нужно будет определить только один раз для данного проекта?   -  person Omri Bernstein    schedule 19.12.2013
comment
Не во время выполнения, @OmriBernstein. Есть одна база данных для тестов и другая для производства.   -  person konr    schedule 19.12.2013


Ответы (2)


Была презентация Стюарта Сьерры на последнем Clojure/West под названием Clojure in the Large., посвященный шаблонам проектирования для крупных приложений Clojure.

Одной из них была описанная вами проблема.

Подводя итог советам по решению проблемы:

1 Очистить конструктор

Итак, у вас есть четко определенное начальное состояние.

  (defn make-connection [uri]
      {:uri uri
       ...}

2 Сделайте зависимости понятными

  (defn update-db [connection] 
     ...

3 Легче проверить

(deftest t-update
  (let [conn (make-connection)]
    (is (= ... (update-db conn)))))

4 Безопаснее перезагружать

 (require ... :reload)

Сохранение uri в переменной для последующего связывания довольно распространено, но вводит скрытые зависимости, а также предполагает, что body начинается и заканчивается в одном потоке.

Смотрите выступление, много других советов по дизайну.

person guilespi    schedule 19.12.2013

Я считаю, что большая часть атомарного кода должна быть как можно более свободной от неявного состояния.

Пусть функции запроса принимают значение базы данных. Заставьте функции записи (transact) использовать соединение с базой данных. Это максимизирует потенциальное повторное использование и позволяет избежать неявных предположений, таких как обращение только к одному соединению с базой данных или непреднамеренное неявное жесткое кодирование функций запроса для работы только с текущим значением базы данных, а не с прошлыми (as-of) или «будущими» (with) значениями базы данных.

Координация единого общего соединения для стандартного варианта использования библиотеки становится задачей небольшого дополнительного пространства имен. Здесь имеет смысл использовать атом для хранения uri или соединения. Несколько удобных макросов, возможно, называемых with-connection и with-current-db, могут затем обернуть функции основной библиотеки, если ручное кодирование и передача значений соединения и базы данных доставляет неудобства.

person Alex Stoddard    schedule 19.12.2013