Re[10]: Нужен ли DAO для Hibernate ORM
От: C0s Россия  
Дата: 07.05.07 15:10
Оценка:
Здравствуйте, IB, Вы писали:

C0s>>возможно, ты еще не видел, как при таком подходе делаются ошибки, приводящие к рассогласованности данных, о которой не идет правильной диагностики "наверх"


IB>Ага и вообще пороху не нюхал.. =)


да не измерений ради...

C0s>>где объявлены и как реализованы Method1 и Method2?

IB>Объявлены — хоть в интерфейсе. Реализованы в DAL.

C0s>> а не проигнорировано путём заглушек (на нижележащем уровне), имитирующих поддержку транзакции

IB>Имитируют они или нет — дело десятое.

итого твою картину ситуации я представляю так (если что — поправь):
DAL {
  Method1() throws SomeProblemException {
    Legacy();  // non-transactional
  }
  Method2() throws AnotherProblemException {
    Native();  // transactional, вовлекается в существующую транзакцию
  }
}


и вот здесь мы старательно закрываем глаза на то, как эти методы ведут себя в отношении транзакций:
BL {
  MyUseCaseImpl() throws BusinessException {
    transaction.start;
    try DAL.Method1(); on SomeProblemException transaction.rollback() and throw BusinessException("problem in legacy");
    try DAL.Method2(); on AnotherProblemException transaction.rollback() and throw BusinessException("problem in native");
    try transaction.commit(); on CommitFailed transaction.rollback and throw BusinessException("commit failed");
  }
}


IB>Как описанная схема мешает правильной диагностике?


в этом коде не обеспечена целостность данных при проблемах на уровне legacy только из-за того, что уровень BL закрывает глаза на разнородность сервисов нижележащего уровня
Re: Нужен ли DAO для Hibernate ORM
От: MaximVK Россия  
Дата: 07.05.07 15:33
Оценка: 1 (1) +1
Здравствуйте, C0s, Вы писали:

C0s>если можно, то я задам встречный: а зачем вообще DAO?

C0s>манипуляции данными обычно не так тривиальны, чтобы заморачиваться на dao, для простых операций типа получения по id достаточно возможностей, которые даёт hibernate-сессия, для сложных типа запросить сджойненные данные с хитрой фильтрацией — dao не помогает.
Вот это я не понял. Можно пояснить на примере? Если тебе встретилась сложная логика, то здравый смысл должен подсказать тебе изолировать эту логику от другого кода, а это, для твоего случая, прямой путь к написанию dao.

C0s>я в своих проектах dao не использую, сейчас для одного проекта попросили дописать фичу, я гляжу на тонну кода dao и мне становится плохо

Если тебе плохо от тонны кода dao, то это проблема не dao, а того кто его писал.

Первая и главная цель, для которой вводиться отдельный слой для работы с данными — это уменьшения сложности кода. Все остальные аргументы, то как: легко прикрутить новую базу, удобство тестирования, параллельная разработка и т.д. — вторичны и, как правило, являются дополнительным бонусом при стремлении к этой цели. Что значит уменьшение сложности? Упрощенно, чем меньшим количеством абстракций/сущностей мне нужно оперировать при вычитывании некоторого фрагмента кода, тем ниже сложность этого кода. Если читая метод бизнес логики для расчета заработной платы сотрудника я должен думать о базе данных — это плохо. Это значит, что программист, который написал этот метод не смог изолировать логику работы с базой в отдельном методе(классе, слое). Это значит, что этот код больше подвержен ошибкам, т.к. жонглировать тремя апельсинами сложнее, чем двумя.

Как изолировать логику работу с данными? Когда проект состоит из пары классов, достаточно логику работы с источниками данных вынести в отдельные методы. Когда проект состоит из пары десятков классов — имеет смысл вынести эту логику в отдельные классы. Когда проект состоит из сотен классов — вводите отдельный слой для работы с базой, даже если вы используете hibernate. Несмотря на все прелести hibernate-а и иже с ними, он не достаточно хорошо изолирует логику работы с базой данных и является, скорее, помощником в написании dao, чем полноценным его заменителем.
Re[11]: Нужен ли DAO для Hibernate ORM
От: MaximVK Россия  
Дата: 07.05.07 16:08
Оценка:
Здравствуйте, C0s, Вы писали:

C0s>в этом коде не обеспечена целостность данных при проблемах на уровне legacy только из-за того, что уровень BL закрывает глаза на разнородность сервисов нижележащего уровня


Из этого только следует, что не надо скрывать от уровня бизнес логики, что Method1 не поддерживает транзакцию. Вытаскивать всю логику работы с легаси системой и базой только с целью сообщить вызывающему коду о поддержке или неподдержке транзакций — как минимум очень странно. Самое простое решение для данного примера — сделать передачу транзакции явной.
DAL {
  Method1() throws SomeProblemException {
    Legacy();  // non-transactional
  }
  Method2() throws AnotherProblemException {
    Native(Transaction tran);  // transactional, вовлекается в существующую транзакцию
  }
}
Re[12]: Нужен ли DAO для Hibernate ORM
От: MaximVK Россия  
Дата: 07.05.07 16:10
Оценка:
Здравствуйте, MaximVK, Вы писали:

Опечатался...
DAL {
...
Method2(Transaction tran) throws AnotherProblemException {

[/code]
Re[4]: Нужен ли DAO для Hibernate ORM
От: IT Россия linq2db.com
Дата: 08.05.07 04:03
Оценка:
Здравствуйте, IB, Вы писали:

IB>Проблема в том, что при таком подходе весь код оказывается гвоздями прибит к Гибернейту.


Это как раз не проблема. Люди сознательно выбирают хибернейт и привязываются к нему. Вот выйдет link2sql люди сознательно будут выбирать его.

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


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

IB>Вынесение же работы с БД в отдельный класс позволяет держать подобный код в резервации, что положительно сказывается на поддержке и понятности.


Этот подход тоже имеет проблемы. Надеюсь, подход линка окажется более совершенным.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 08:26
Оценка:
Здравствуйте, C0s, Вы писали:

C0s>что значит "трогать"?!

Трогать — это значит урезать и городить на их основе другие — более простые/сложные объекты

C0s> я пишу про DTO, ты же утверждаешь, что их вообще использовать не надо

Не, я утверждаю что в идеале то что ты называешь DTO это эквивалент BizEntity.

C0s>если это ORM-pojo, то он создаётся в большинстве случаев в недрах ORM и является модифицируемым (mutable)

Модифицируемым — не в смысле Mutable, а в смысле урезать/добавить при переходе из слоя в слой.
Хотя и сделать большинство из них immutable тоже не помешало бы.

C0s>именно поэтому я и пишу про DTO, которые у меня создаются мной там, где надо, оторваны от ORM и объектов, жизненным циклом котороых управляет ORM,

C0s> и я являются настолько простыми, насколько это позволяет задача уровня презентации или что там еще бывает при работе с извлекаемыми данными.
Во. А я пишу про то, что объекты изначально должны быть простыми и никакая ORM не имеет право управлять их жизненным циклом или еще что-то с ними делать. (За что собственно и не люблю ORM)
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[5]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 08:26
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>То что ты ORMофоб мы уже и так знаем

Не лишним будет в очередной раз напомнить.. )

C>Зачем ее выносить в слое, который непосредственно с данными работает?

Чтобы слой который работает со слоем, который работает непосредственно с данными ничего об интимных подробностях конкретной ORM не знал.

C>Обычно у нас все равно появляются неявные связи с используемой системой ORM/DAL.

Где?

C>Вот в интерфейсе слоя бизнес-логики и клиентского кода — деталей DALа не должно быть.

Это само собой. Речь о том что в интерфейсе BL-DAL не должно быть подробностей конкретной реализации DAL.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[11]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 08:26
Оценка:
Здравствуйте, C0s, Вы писали:

C0s>да не измерений ради...

Ну надеюсь..

C0s>в этом коде не обеспечена целостность данных при проблемах на уровне legacy только из-за того, что уровень BL закрывает глаза на разнородность сервисов нижележащего уровня

Внимание вопрос. Что мешает сделать поддержку транзакций в Method1, поверх вызова Legacy? Хотя бы тем способом, что предложил MaximVK?
И зачем эту, явно низкоуровневую логику тащить наверх?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[5]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 08:26
Оценка:
Здравствуйте, IT, Вы писали:

IT>Это как раз не проблема. Люди сознательно выбирают хибернейт и привязываются к нему.

Ну собственно в этом-то и проблема.. =)

IT>Вот выйдет link2sql люди сознательно будут выбирать его.

Ну, у линка подход другой, он не должен так жестко руки связывать.

IT>Этот подход тоже имеет проблемы. Надеюсь, подход линка окажется более совершенным.

Посмотрим..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[6]: Нужен ли DAO для Hibernate ORM
От: Cyberax Марс  
Дата: 08.05.07 10:42
Оценка: 10 (3)
Здравствуйте, IB, Вы писали:

C>>Зачем ее выносить в слое, который непосредственно с данными работает?

IB>Чтобы слой который работает со слоем, который работает непосредственно с данными ничего об интимных подробностях конкретной ORM не знал.
Нереально. Точнее, непрактично.

Детали ORM могут косвенно влиять на использование объектов. Например, есть ORM в которых не поддерживается identity mapping — значит многие алгоритмы с такой ORM, рассчитаные на правильную идентичность, будут падать.

Другой пример, Hibernate автоматически генерирует методы equals и hashCode для проксиков (заменяя их на сравнение и взятие хэшкода главного ключа объекта), так что неинициализированые проксики можно быстро класть в hash-коллекции. Таким образом, если мы в наших классах добавим equals+hashCode, то можем вдруг получить неприятные сюрпризы по скорости из-за того, что при попытке положить такие объекты в HashSet у нас они будут загружаться из базы.

Да, с ленивой загрузкой тоже могут быть оооочень интересные сюрпризы.

C>>Обычно у нас все равно появляются неявные связи с используемой системой ORM/DAL.

IB>Где?
См. предидущий параграф

C>>Вот в интерфейсе слоя бизнес-логики и клиентского кода — деталей DALа не должно быть.

IB>Это само собой. Речь о том что в интерфейсе BL-DAL не должно быть подробностей конкретной реализации DAL.
Не согласен. Детали доступа к данным могут сильно влиять на BL.
Sapienti sat!
Re[12]: Нужен ли DAO для Hibernate ORM
От: Cyberax Марс  
Дата: 08.05.07 10:48
Оценка:
Здравствуйте, IB, Вы писали:

C0s>>в этом коде не обеспечена целостность данных при проблемах на уровне legacy только из-за того, что уровень BL закрывает глаза на разнородность сервисов нижележащего уровня

IB>Внимание вопрос. Что мешает сделать поддержку транзакций в Method1, поверх вызова Legacy? Хотя бы тем способом, что предложил MaximVK?
Кстати, я у себя примерно так и делаю — все нужные параметры передаю явно.

Кроме того, такой метод все равно не подходит для обобщенного DAL, который по легенде можно одной строчкой в конфиге поменять с БД на использование файловой системы на марсоходе Spirit через систему космической связи NASA.

IB>И зачем эту, явно низкоуровневую логику тащить наверх?

Так передача транзакции — это уже низкоуровневая логика.
Sapienti sat!
Re[6]: Нужен ли DAO для Hibernate ORM
От: IT Россия linq2db.com
Дата: 08.05.07 10:57
Оценка: 4 (2)
Здравствуйте, IB, Вы писали:

IT>>Это как раз не проблема. Люди сознательно выбирают хибернейт и привязываются к нему.

IB>Ну собственно в этом-то и проблема.. =)

Не проблема это. Иначе так можно договориться до того, что использование любой библиотеки — это проблема. Даже .NET FW.

IT>>Вот выйдет link2sql люди сознательно будут выбирать его.

IB>Ну, у линка подход другой, он не должен так жестко руки связывать.

Вот с руками действительно проблема. А прибото приложение гвоздями к линку или хибернейту — это не важно. Любое решение всегда к чему-нибудь прибивается.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 12:44
Оценка:
Здравствуйте, IT, Вы писали:

IT>Не проблема это. Иначе так можно договориться до того, что использование любой библиотеки — это проблема. Даже .NET FW.

Смотря какая библиотека... Мне не нравится идея программировать на библиотеке, не для этого их пишут.

IT> Любое решение всегда к чему-нибудь прибивается.

Вопрос в какой степени и какой частью. Если по уму, то шурупчики можно аккуратно вывернуть и что-нибудь другое прикрутить, и изменение в одном кусочке не вылиывается в перелопачивание всего кода.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[7]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 12:44
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Нереально.

Реально.

C> Точнее, непрактично.

Очень практично, на практике проверено.

C>Детали ORM могут косвенно влиять на использование объектов.

А не надо чтобы влияли. Точнее надо чтобы не влияли.

C> Например, есть ORM в которых не поддерживается identity mapping — значит многие алгоритмы с такой ORM, рассчитаные на правильную идентичность, будут падать.

На кой байт, слою реализующиму логику знать об identity mapping? если нужна правильная идентичность — пусть DAL ее обеспечивает, а уж с помощю ORM он это сделает или нет — дело десятое.

C>Другой пример, Hibernate автоматически генерирует методы equals и hashCode для проксиков (заменяя их на сравнение и взятие хэшкода главного ключа объекта), так что неинициализированые проксики можно быстро класть в hash-коллекции. Таким образом, если мы в наших классах добавим equals+hashCode, то можем вдруг получить неприятные сюрпризы по скорости из-за того, что при попытке положить такие объекты в HashSet у нас они будут загружаться из базы.

Угу. Это к вопросу о том, что не надо использовать ORM типа гибернейта, которые пытаются все решить за нас.
Эти нюансы не должны заботить слой занимающийся логикой — его задача обслуживание use-case'ов и ничего более, а тут получается, что этот слой еще и обслуживанием ORM занимается.

C>Да, с ленивой загрузкой тоже могут быть оооочень интересные сюрпризы.

Какие?

C>См. предидущий параграф

Во-во. Вот не надо нам неявных связей, проще надо быть.

C>Не согласен. Детали доступа к данным могут сильно влиять на BL.

Ну как писать. Могут-то конечно могут, но надо писать чтобы не влияли.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[13]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 12:44
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Кроме того, такой метод все равно не подходит для обобщенного DAL,

Что мешает?

C>Так передача транзакции — это уже низкоуровневая логика.

Это смотря какой транзакции. Если БД транзакции, то низкоуровневая, но здесь речь идет о бизнес-транзакции, а это уровень повыше будет.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Нужен ли DAO для Hibernate ORM
От: IT Россия linq2db.com
Дата: 08.05.07 13:22
Оценка: 12 (2)
Здравствуйте, IB, Вы писали:

IT>>Не проблема это. Иначе так можно договориться до того, что использование любой библиотеки — это проблема. Даже .NET FW.

IB>Смотря какая библиотека... Мне не нравится идея программировать на библиотеке, не для этого их пишут.

Ваня, это теория. Красивая сказка. Реализация напрямую зависит от выбранных средств. И чем сложнее средства, тем большими гвоздями к ней прибивается реализация. Единственное что ты можешь сделать — это написать всё сам, но, надеюсь ты понимаешь, что при текущем состоянии дел в индустрии для более менее сложных задач это не реально.

IT>> Любое решение всегда к чему-нибудь прибивается.

IB>Вопрос в какой степени и какой частью. Если по уму, то шурупчики можно аккуратно вывернуть и что-нибудь другое прикрутить, и изменение в одном кусочке не вылиывается в перелопачивание всего кода.

Давай для примера возьмём не DAL, а UI. Как ты думаешь насколько реально выбрать в качестве UI библиотеки сначала Syncfusion, а потом передумать, открутить шурупчики и прикрутить Infragistic? Если у тебя есть сомнения, что абсолютно весь код, касающийся логики UI будет переписан, то можешь сам попробовать на досуге.

Так что проблема не в том, используются какие-либо библиотеки или нет. Проблема в том, как они влияют на архитектуру приложения. В частности, хибернейт не просто влияет, он её диктует, а это значит, что отход от предложенного подхода будет немедленно караться. Проблема именно в этом.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: Нужен ли DAO для Hibernate ORM
От: Cyberax Марс  
Дата: 08.05.07 13:50
Оценка:
Здравствуйте, IB, Вы писали:

C>> Точнее, непрактично.

IB>Очень практично, на практике проверено.
Можно список проектов, желательно OpenSource?

Я утверждаю, что если DAL заранее не проектировался для работы с несколькими видами источников данных, то DAO фиг чем помогут. Могу привести пример, когда источник RDF-данных пытались (очень плохоуспешно) синтегрировать с реляционными данными.

C>> Например, есть ORM в которых не поддерживается identity mapping — значит многие алгоритмы с такой ORM, рассчитаные на правильную идентичность, будут падать.

IB>На кой байт, слою реализующиму логику знать об identity mapping? если нужна правильная идентичность — пусть DAL ее обеспечивает, а уж с помощю ORM он это сделает или нет — дело десятое.

А безопасность тоже он обеспечивать будет? И транзакционные уровни изоляции?

C>>Другой пример, Hibernate автоматически генерирует методы equals и hashCode для проксиков (заменяя их на сравнение и взятие хэшкода главного ключа объекта), так что неинициализированые проксики можно быстро класть в hash-коллекции. Таким образом, если мы в наших классах добавим equals+hashCode, то можем вдруг получить неприятные сюрпризы по скорости из-за того, что при попытке положить такие объекты в HashSet у нас они будут загружаться из базы.

IB>Угу. Это к вопросу о том, что не надо использовать ORM типа гибернейта, которые пытаются все решить за нас.
А без разницы. Самодельный ORM точно так же может [не] страдать этим.

IB>Эти нюансы не должны заботить слой занимающийся логикой — его задача обслуживание use-case'ов и ничего более, а тут получается, что этот слой еще и обслуживанием ORM занимается.

Хочешь расскажу тайну? Нету такой вещи в природе как слой чистой бизнес-логики (достаточно развитой, естественно, о "hello, world!" не говорим), незамутненной деталями реализации нижележащих слоев.

C>>Да, с ленивой загрузкой тоже могут быть оооочень интересные сюрпризы.

IB>Какие?
Ооооо... Тут ТАКОЙ список...

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

C>>См. предидущий параграф

IB>Во-во. Вот не надо нам неявных связей, проще надо быть.
Так эти неявные связи все равно будут. Если ты сегодня напишешь простой рабоче-крестьянский CRUDовый DAL, а завтра решишь использовать Hinernate — то скорее всего возникнут сюрпризы. Могу рассказать по своему опыту, если интересно.

C>>Не согласен. Детали доступа к данным могут сильно влиять на BL.

IB>Ну как писать. Могут-то конечно могут, но надо писать чтобы не влияли.
Например, мы делаем так:
List<User> users=UserDAO.getInstance().getUsersByPattern("Vasja*"); //В списке всего 10 объектов.
Collections.sort(users); //Но объекты достаются через CORBA...


В результате, для сортировки этого списка тебе может потребоваться примерно 30 удаленных вызовов. Так как для сравнения на равенство CORBA-объектов потребуется удаленный вызов.

В то же время, если объекты передаются по значению — то сортировка будет мгновенной. Вместо сортировки можно, например, взять валидацию email.
Sapienti sat!
Re[14]: Нужен ли DAO для Hibernate ORM
От: Cyberax Марс  
Дата: 08.05.07 13:52
Оценка:
Здравствуйте, IB, Вы писали:

C>>Кроме того, такой метод все равно не подходит для обобщенного DAL,

IB>Что мешает?
Отсутствие у него параметра с транзакцией

C>>Так передача транзакции — это уже низкоуровневая логика.

IB>Это смотря какой транзакции. Если БД транзакции, то низкоуровневая, но здесь речь идет о бизнес-транзакции, а это уровень повыше будет.
А чем тебе объект с бизнес-транзакцией поможет в DAO, если через него нельзя получить DB-транзакцию?
Sapienti sat!
Re[9]: Нужен ли DAO для Hibernate ORM
От: Cyberax Марс  
Дата: 08.05.07 13:54
Оценка:
Здравствуйте, IT, Вы писали:

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

Насчет "диктует" — абсолютно не согласен. Hibernate может быть адаптирован почти под любую архитектуру в своих рамках применимости (т.е. не совсем brain-damaged-схемы, не OLAP и т.п.), хотя он при этом, естественно, будет влиять на конкретные решения в коде.
Sapienti sat!
Re[9]: Нужен ли DAO для Hibernate ORM
От: IB Австрия http://rsdn.ru
Дата: 08.05.07 14:01
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ваня, это теория. Красивая сказка.

Угу, мне она нравится...

IT> Единственное что ты можешь сделать — это написать всё сам, но, надеюсь ты понимаешь, что при текущем состоянии дел в индустрии для более менее сложных задач это не реально.

Тут есть тонкий момент. Как раз для действительно сложных задачь это может быть и оправдано и реально. Не все конечно, но вещи типа ORM уж точно.

IT>Давай для примера возьмём не DAL, а UI. Как ты думаешь насколько реально выбрать в качестве UI библиотеки сначала Syncfusion, а потом передумать, открутить шурупчики и прикрутить Infragistic?

В принципе реально.

IT>Если у тебя есть сомнения, что абсолютно весь код, касающийся логики UI будет переписан, то можешь сам попробовать на досуге.

Логики UI — да, байндинг там всякий непосредственно к UI объектам и прочую муть.. Но вот всю остальную логику, в частности BL, можно попробовать оставить в непркосновенности, собственно об этом и речь. С Syncfusion и Infragistic не игрался, а вот WebForms и WinForms для одного приложения реализовать удалось.

IT>Так что проблема не в том, используются какие-либо библиотеки или нет. Проблема в том, как они влияют на архитектуру приложения.

Именно.

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

Я об этом и говорю...
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.