Синглтон (2)
Вдогонку о синглтоне — пара мелочей, о которых забыл вчера. Рассмотрим простую функцию:
(func get-user-by-id [db id]
(first (jdbc/execute! db "where id = ?" id)))
Она принимает объект базы и работает с ним. Все прозрачно и логично. А вот варианты этой же функции, которые рассчитывают на глобальное подключение к базе:
(func get-user-by-id [id]
(let [db some.namespace/*DB*]
(first (jdbc/execute! db "..." id))))
или
(func get-user-by-id [id]
(let [db (db/get-or-create ...)]
(first (jdbc/execute! db "..." id))))
Оба варианта плохи по многим критериям. Если глобальный объект куда-то переедет, придется менять все функции. Нарушается связность системы — функции лезут в кишки, куда им лезть не следует. Объект может быть не инициирован — вполне возможная ситуация, если он включается по запросу. Наконец, функцию db/get-or-create нужно проверить на потокобезопасность, чтобы несколько потоков не наплодили более одного объекта.
А теперь вернемся к первому варианту:
(func get-user-by-id [db id]
(first (jdbc/execute! db "..." id)))
Очевидно, что когда функция принимает объект, все претензии снимаются. Ей все равно, синглтон это или нет, это не играет роли. Даже если в системе десять подключений к разным базам, на функции это не скажется. Наоборот, сплошная польза: я могу прочитать пользователя из мастера, из реплики, из исторической базы. В некоторых случаях это важно.
Если отбросить красивые слова, синглтон — это глобальное состояние, подпертое костылями. А состояния лучше избегать — сегодня это ясно как день, причем независимо от языка.
Пока писал, вспомнил, как словил неприятное поведение из-за синглтона. В одном проекте авторы сделали глобальный пул соединений с базой. Синглтон, все по статьям в интернете. А потом я стал писать тесты и обнаружил: если тест закроет пул, то все, капут — система становится нерабочей. При попытке обратиться к пулу получишь исключение, что он закрыт. А пересоздать нельзя, потому что пул глобален. Нога прострелена, и нужно перезапускать приложение. Я это починил, но шлю авторам лучиков знаний, чтобы так не делать.
Повторюсь, сегодня нет причин использовать синглтон. Ни под каким видом. Знать, что это такое, нужно, но только за тем, чтобы не напороться на описанные грабли.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter