Как да задам конфигурационни параметри в библиотеката clojure?

Пиша библиотека на Clojure и се чудя каква е най-добрата практика за задаване на конфигурационни параметри на библиотека.

Много библиотеки (като тези в clojure-contrib) използват параметър на глобално ниво като *buffer-size*, който потребителят може да зададе, като им извика set!. Но това не изглежда най-добрият начин за мен, тъй като създава глобално състояние и има шансове за сблъсък на имена.

Другият начин е да подадете параметрите във всяко извикване на функция, което зависи от тях. Ако има много параметри, може да се използва карта от тях, вместо да се подават отделни.

Като пример, да кажем, че пиша кеш библиотека.

Използвайки първия подход, имам глобални параметри като *cache-size*, *expiry-time*, *cache-dir* и т.н. Потребителят ги set!s (или не и ги оставя да бъдат по подразбиране) и извиква функции като (set-in-cache id obj) и (get-from-cache id).

Използвайки втория подход, потребителят първо създава карта на параметрите и я предава на всяко повикване

(def cache-parameters {:cache-size 1000 
                       :expiry-time: 1440 
                       :cache-dir "c:\\cache"})
(set-in-cache cache-parameters id obj)
(get-from-cache cache-parameters id)

И така, кой е предпочитаният начин в Clojure и защо?


person Abhinav Sarkar    schedule 23.07.2010    source източник


Отговори (1)


Всъщност не можете да set! неща като тези на c.c.io *buffer-size*, освен ако не инсталирате локално обвързване за нишки за тях с binding, with-bindings и т.н. Има само няколко Vars, за които локалните обвързвания за нишки са инсталирани от машини на Clojure от по-ниско ниво, като *warn-on-reflection* и *read-eval*, правейки ги set!-способни на най-високо ниво; дефинираните от потребителя Vars не са set!-способни на най-високо ниво. Основното свързване на Var може да се промени с напр. alter-var-root, intern, def, .bindRoot ..., но това трябва да се използва умерено.

Що се отнася до частта от въпроса за повторно обвързване Vars срещу изрични параметри: използването на изрични параметри е почти винаги добре и обикновено е за предпочитане, само поради повишената поддръжка на функции, които ясно показват всички части от данни, от които зависят. Като се има предвид това, ако има вероятност някаква част от конфигурацията да бъде зададена веднъж, след което да се използва от почти всяко извикване на функция в рамките на приложението/библиотеката някога след това, това може да доведе до по-разумен код за дефиниране на антифон Var, да го документира добре и да постави конфигурацията в него (и това може да е един от редките случаи, когато промяната на основното свързване на Var извън формата, която дефинира, може да е добре).

За да обобщим, използвайте най-добрата си преценка, ако не сте сигурни - грешете от страната на изричното предаване на параметър.

person Michał Marczyk    schedule 23.07.2010
comment
Този последен бит е точно това, което направих в clj-github и gotmilk. Страхотно е да знам, че може би съм направил нещо правилно! - person Rayne; 23.07.2010
comment
it might make for saner code to define an earmuffed Var ... Можете ли да дадете пример? - person Abhinav Sarkar; 23.07.2010
comment
@Rayne: ;-) @abhin4v: Всъщност *buffer-size*, което споменахте във въпроса, е добър пример за използване на Var за поддържане на разумна стойност по подразбиране, която понякога може да бъде върната от кода на клиента. Що се отнася до повторното свързване на основната стойност на Var, Congomongo (библиотеката Clojure MongoDB) използва alter-var-root на Var, наречена *mongo-config* (чиято цел е както подсказва името). - person Michał Marczyk; 24.07.2010
comment
Благодаря. Реших проблема си с помощта на resolve. Потребителят на библиотеката ще трябва да def конкретна променлива и моята библиотека просто да я resolves. - person Abhinav Sarkar; 24.07.2010
comment
@AbhinavSarkar Никога не съм виждал библиотека да използва това. Получи ли се при вас? Как се справихте с проблемите с пространството на имената и как ги разрешихте? - person Didier A.; 28.11.2015