Менеджмент зависимостей с состоянием в Clojure

49 views
Skip to first unread message

ggenikus

unread,
Apr 25, 2014, 5:15:24 PM4/25/14
to clojure...@googlegroups.com
Всем привет!

Мучает меня вопрос того какой правильный подход для менеджмента внешних зависимостей в Clojure.

Допусти у нас есть stateful зависимость, например конекшен к базе, как бы вы работали с ним ? Хранили его в атоме ?
Биндили ли бы в динамическую переменную ? Тащили структуру с конекшеном в параметы функций которые его требуют для работы?
И как при этом обеспечить гибкость, например одновременная работа нужной функций с разными конекшенами и легкость тестирования.

Мне кажется подход  предложенный в Component является самым взрослым, он обеспечивает гибкость и модульность.
Но после его использования  у меня начало возникать чувство того что запахло ООП, и что по сути это тот же депенденси инджекшен но в языке в котором разрешается создавать только immutable объекты. И как бы не кричали все о том что не нужен нам депенденси инджекшен и ооп оно все таки просочилось.

Как вы решаете эту проблему ? Может есть какие то мысли по этому поводу ?

Дмитрий Омелечко

unread,
Apr 25, 2014, 5:22:27 PM4/25/14
to clojure...@googlegroups.com
Возможно я не совсем в питницу ночью понял вопрос, но в озвученном контексте https://github.com/weavejester/environ меня вполне устраивает. 


26 апреля 2014 г., 0:15 пользователь ggenikus <ggen...@gmail.com> написал:

--
Вы получили это сообщение, поскольку подписаны на группу "Clojure Russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес clojure-russi...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

Ilshad Khabibullin

unread,
Apr 25, 2014, 5:49:40 PM4/25/14
to clojure...@googlegroups.com
Никаких биндингов и никаких хранений в атоме. Коннект к базе возвращается специальной функцией, которую можно и в REPL вызвать, и в тестах, и через ring middleware завернуть в request, и так потом "протаскивать" везде. В большинстве случаев протаскивать не сильно далеко, не страшно.

По соглашению у меня в проекте все функции, которым он нужен коннеккт, принимают его (или database value, полезный для случая с datomic, например) последним аргументом. Всякие конфиги тоже читаются желательно где-то вначале, в start / init.

component хорош как урок, но сейчас обхожусь без него, хотя stateful компонент несколько, не только БД.

--

Nikita Beloglazov

unread,
Apr 25, 2014, 6:03:55 PM4/25/14
to clojure...@googlegroups.com

Ммм, а чем специальная функция отличается от хранения в атоме?

Ilshad Khabibullin

unread,
Apr 25, 2014, 6:16:12 PM4/25/14
to clojure...@googlegroups.com
А зачем хранить в атоме то, что вызывается один раз и дальше "протаскивается"? Во время разработки, она, например, вызывается вместе с инициализацией других нужных компонент в нужной мне последовательности, с тестовыми данными и т.д. (go / clear). Впрочем, как раз для удобства работы в REPL коннект сохраняется в атом, но я его не дергаю в коде где попало, это только в dev/user.clj

Nikita Beloglazov

unread,
Apr 25, 2014, 6:22:09 PM4/25/14
to clojure...@googlegroups.com

Т.е. как я понял используется третий вариант, который предлагал автор вопроса - соединение передаётся как аргумент функции.

Ilshad Khabibullin

unread,
Apr 25, 2014, 6:25:49 PM4/25/14
to clojure...@googlegroups.com
Да, именно.

ggenikus

unread,
Apr 26, 2014, 1:07:19 PM4/26/14
to clojure...@googlegroups.com
А в ситуации когда больше одной зависимости - вы передаете их как Map последним аргументом ?

Думал про такой подход, мне кажется что в таком подходе есть концептуальная проблема, если оставаться в контексте конекшена к базе и представить что по мимо него у нас есть слой обработки данных (логика нашего приложения) получается мы передаем в сущности (слой обработки) которые находятся
на более абстрактном уровне чем слой доступа к данным детали которые нужны для слоя доступа к данным. Таким
образом это усложняет саму сущность, размывает абстракцию и делает сложным возможность изменить слой доступа к данным при этом
не поломав остальные слои.

Ilshad Khabibullin

unread,
Apr 26, 2014, 2:47:54 PM4/26/14
to clojure...@googlegroups.com
Ну да, теоретически. А на деле, бывает и так: когда разделяешь ответственность по границе абстрактный уровень / менее абстрактный уровень ("бизнес логика", что бы под ней не подразумевали / "представление" и т.д.) - потом смотришь в код и думаешь "эх, перемудрил". Дефрагментация логики, разбрасывание одной задачи по искусственно формальным компонентам там, где это не нужно.

Если это веб-аппликация, то в ring request map вообще принято много чего складывать, и кажется, это практично и удобно. Почему бы и коннект там не тоже держать.

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


Ilshad Khabibullin

unread,
Apr 26, 2014, 5:03:58 PM4/26/14
to clojure...@googlegroups.com
Id est, абстракции это абстракции, а разделение ответственности - это разделение ответственности.
Reply all
Reply to author
Forward
0 new messages