metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2014-05-19 09:42 pm

Синглетоны

https://github.com/SparkViewEngine/spark/blob/master/src/Samples/DirectUsage/ConsoleTemplating/Services/MessageBuilder.cs

А вот насколько подобный код (статик _instance и его инициализация) является кошерным? Ну с interlocked все более-менее понятно, а вот собственно использование синглетонов вместо всяких модных IoC и тому подобного усложняющего все трэша?

[identity profile] vp.livejournal.com 2014-05-19 07:05 pm (UTC)(link)
Красивый код.

[identity profile] jakobz.livejournal.com 2014-05-19 07:21 pm (UTC)(link)
Это какой-то вариант синглтона с дабл-локом - который весьма распространен, видимо с явы какой-нибудь скопирован. Многие не шарят что в дотнете можно делать тупо так:

public readonly MessageBuilder Instance = new DefaultMessageBuilder()

Гарантируется отсутствие проблем с многопоточностью. Там могут быть проблемы в каких-нибудь мудреных случаях - типа проинициализируется оно раньше чем нужно если позвали статический метод, которому instance не нужен.

Но всё это волнует это только молодежь, которым важно лиду показать "смотри, я дабл-лок умею! Читал умную книжку недавно". Я лично пишу в одну строчку, и мне пофигу.

По поводу IoC и прочих фабрик - оно хорошо только там где оно точно надо. Потому что фабрика, которая может создавать более одного вида инстансов - она сразу, например, делает предельно сложным понимание без дебаггера что откуда вызывается. Типа go to definition делаешь - а там интерфейс или абстрактный класс. А учитывая как жидко в ООП текут абстракции тупых ООП-шников, ихний пустой интерфейс как-то не греет душу.

Я лично прошел как минимум один диалектический цикл - раньше использовал IoC без фанатизма, теперь же предпочитаю хардкодить всё до упора, включая даже большинство настроек. Проще максимально упростить деплой компилированного кода, чем менять в бою разлапистый XML со встроеными убогими eDLS-ями.

[identity profile] jakobz.livejournal.com 2014-05-19 07:28 pm (UTC)(link)
А если уж хочется точно контроллировать когда инстанс поднимется - можно так:
private static readonly Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton());

public static Singleton Instance
{
    get { return instanceHolder.Value; }
}

В общем я не могу придумать когда может потребоваться дабл-лок вручную.

[identity profile] aamonster.livejournal.com 2014-05-21 02:12 pm (UTC)(link)
А напомните - в C# static initialization order fiasco остался или как-то регламентирован порядок создания объектов?

[identity profile] berezovsky.livejournal.com 2014-05-21 02:22 pm (UTC)(link)
в стандарте не определён, по факту по тексту класса идёт

[identity profile] metaclass.livejournal.com 2014-05-21 02:50 pm (UTC)(link)
В одном классе хз, в разных - все как положено, по зависимостям.

[identity profile] viacheslav ivanov (from livejournal.com) 2014-05-23 04:02 pm (UTC)(link)
10.5.5.1 Static field initialization
The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. .…

10.12 Static constructors
…It is possible to construct circular dependencies that allow static fields with variable initializers to be observed in their default value state.…

Выделение жирным моё.

[identity profile] bydlorus.livejournal.com 2014-05-19 07:30 pm (UTC)(link)
Поэтому вместо go to definition нужно юзать go to implementation, а кто не любит Resharper - Find references.

Но это не возражение, там, мелочная заметка.

[identity profile] jakobz.livejournal.com 2014-05-19 07:40 pm (UTC)(link)
Когда реализаций две или более, и они выбираются, например, из конфигурации в базе - там никакой go to implementation не поможет. Либо раскуривать как фабрика работает и смотреть что в конфиге, либо запускать дебаггер. Второе, как показывает практика - быстрее и надежнее.

По-факту, конечно, IoC с фабриками юзают подрастающие ООП-шники - просто для красоты. Типа вместо 2+2 - херакс, и пять классов с интерфейсами и XML-комментариями. И вроде работы много сделал, и выглядит умно, и законодательно говнокодом назвать нельзя - ведь так делать завещали GoF, Фаулер, и прочие фашисты. Сказать что они неправы - это пойти против enterprise-религии.

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

[identity profile] bydlorus.livejournal.com 2014-05-19 08:29 pm (UTC)(link)
У меня сложилось ощущение, что в это треде мы обсуждаем ненужность интерфейсов и абстракции. Т.е. очевидную ересь.

[identity profile] metaclass.livejournal.com 2014-05-19 07:36 pm (UTC)(link)
Ясно, я почти все нужные мне зависимости тащу вручную, передаю в конструктора. Но кое-где в фреймворках сторонних сидит IoC и можно убится с ним.

[identity profile] jakobz.livejournal.com 2014-05-19 07:56 pm (UTC)(link)
В сторонних фреймворках - оно обычно к лучшему. Всяко не хардкод - хоть подлезть можно. Бесит только если они заставляют всякое ихнее говно куда-нибудь в конфиг писать. Если из кробки запускается в пару строк, но если нужно - можно влезть - то я лично не против совсем.

[personal profile] leotsarev 2014-05-23 08:08 pm (UTC)(link)
Ну тащемта передать все зависимости в конструктор — это IoC. Нехипстерский, но вполне себе IoC.

[identity profile] blackyblack.livejournal.com 2014-05-19 07:22 pm (UTC)(link)
Такой код очень распространён. По сути это обычный сишный модуль: разово инициализируемый и глобально доступный.

[identity profile] mr-st.livejournal.com 2014-05-19 07:27 pm (UTC)(link)
Интерлокед там нафиг не нужен, кстати.

[identity profile] metaclass.livejournal.com 2014-05-19 07:37 pm (UTC)(link)
Присваивание и проверка для ссылок атомарны?

[identity profile] mr-st.livejournal.com 2014-05-19 07:38 pm (UTC)(link)
Присваивание статику да.

[identity profile] jakobz.livejournal.com 2014-05-19 07:50 pm (UTC)(link)
Кстати от вероятности создать DefaultMessageBuilder два раза, автор кода не защитился.

[identity profile] mr-st.livejournal.com 2014-05-19 07:41 pm (UTC)(link)
Хотя я не совсем прав. Вот такое точно безопасно
class A
{
private static A _instance = new A();
}

[identity profile] max630.livejournal.com 2014-05-19 07:41 pm (UTC)(link)
зачем конкретно вот это вообще виртуализовать?

[identity profile] max630.livejournal.com 2014-05-19 07:45 pm (UTC)(link)
А по теме - если, там есть именно public set {}, а не internal, с проковырянной дырочкой специально для юниттестов - подозреваю какую-то херню, которую можно было бы с трешем сделать

[identity profile] maxdz.livejournal.com 2014-05-19 08:01 pm (UTC)(link)
Не очень ясно, почему в коде по ссылке должен быть синглтон, если у него нет внутреннего состояния. Достаточно было сделать 1 статическую функцию "трансформ".

А так, лично я не фанат синглтонов, из-за их глобальной видимости и их "синглтоновости". :) Сколько ими не пользовался, всегда наступал момент, когда приходилось создавать несколько объектов, вместо 1 - после этого, приходилось переделывать их в нормальные классы и это лишь улучшало общий дезайн.

[identity profile] maxdz.livejournal.com 2014-05-19 08:05 pm (UTC)(link)
>почему в коде по ссылке должен быть синглтон, если у него нет внутреннего состояния

Хотя, если для полиморфного использования... - но это уже для продвинутых извращенцев. :)

[identity profile] permea-kra.livejournal.com 2014-05-20 02:41 pm (UTC)(link)
А за синглетоны как явление еще не принято сажать на кол?

[identity profile] metaclass.livejournal.com 2014-05-20 03:24 pm (UTC)(link)
Принято сажать на кол за втаскивание IoC контейнеров туда, где хватит одного класса и одной статик переменной :)

[identity profile] vp.livejournal.com 2014-05-20 05:10 pm (UTC)(link)
Обоснуете почему?

[identity profile] metaclass.livejournal.com 2014-05-20 06:07 pm (UTC)(link)
Синглетон один на весь процесс, а внезапно может оказаться что нужно несколько экземпляров такого класса, при этом переделать полсистемы, которая уже ссылается на него и протащить нужный экземпляр явно - это печаль.
Я вспомнил несколько мест, где у нас такое может боком вылезти - например, если мы более одного веб-сервиса возжелаем сунуть в один процесс - у них окажутся общие ссылки на некоторые внутренние сервисы и это будет плохо.

[identity profile] vp.livejournal.com 2014-05-20 06:29 pm (UTC)(link)
Не, енто понятно. Но он же потому так и называется. Его использование быть оправдано, может быть нет. Например, логгер, он может быть архитектурно один на все приложение.

[identity profile] permea-kra.livejournal.com 2014-05-20 08:04 pm (UTC)(link)
>Например, логгер, он может быть архитектурно один на все приложение.

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

В целом, единственной причиной для существования синглтонов мне видится неготовность народа таскать состояние явно. В то же время сам факт допущения использования синглтонов неизбежно создает риск ситуаций, описанных ребе Метаклассом.
Edited 2014-05-20 20:28 (UTC)

[identity profile] vp.livejournal.com 2014-05-20 08:35 pm (UTC)(link)
При нормальной архитектуре нет никаких проблем, допустим, через параметры конструкторов классов передавать нужные экземпляры классов. Но с другой стороны это может загромождать инициализацию, когда тебе нужно передать n+1 разных контекстов, без которых никак. :)

[identity profile] permea-kra.livejournal.com 2014-05-20 08:42 pm (UTC)(link)
В указанной ситуации вполне можно использовать фабрики классов, в которые можно положить n+m контекстов заранее.

[identity profile] metaclass.livejournal.com 2014-05-20 08:49 pm (UTC)(link)
Ад паттернов. :)

[identity profile] permea-kra.livejournal.com 2014-05-20 08:53 pm (UTC)(link)
Переходите на хаскель =).

[identity profile] vp.livejournal.com 2014-05-20 08:51 pm (UTC)(link)
Имхо наименее симпатичное из решений.

[identity profile] permea-kra.livejournal.com 2014-05-20 08:53 pm (UTC)(link)
Оно зато работает и не вызывает проблем. Если так уж не хочется таскать контексты явно.

[identity profile] vp.livejournal.com 2014-05-20 08:54 pm (UTC)(link)
А в какой момент вы предлагаете доставать мой контекст из общей фабрики? До вызова конструктора, затем передавая его в конструктор, или в самом конструкторе?
И что будет ключом в том и ином случае?

[identity profile] metaclass.livejournal.com 2014-05-20 08:59 pm (UTC)(link)
Причем тут ключ воще? Фабрика это условно говоря класс с десятком полей ссылающихся на куски контекста и одним методом типа "CreateЧегоНибудь" вызывающим конструктор с передачей в него контекстов.
Меня этот вариант тащемта напрягает адом паттернов, написанием классов ради того чтобы писать классы.

[identity profile] permea-kra.livejournal.com 2014-05-20 09:03 pm (UTC)(link)
Да мне самому не нравится. Я б предпочел пропихивать контексты явно, если лень писать полный список каждый раз - предоставить возможность завернуть их в какой-то обертке и пропихивать в конструктор получившийся кулек. Ну или еще лучше - использовать монадки.

[identity profile] permea-kra.livejournal.com 2014-05-20 09:00 pm (UTC)(link)
В описанной ситуации я бы таскал в объекте ссылку на фабрику, переданную в конструкторе.

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