среда, 29 сентября 2010 г.

Dependency injection Presentation

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

Dependency injection

P.S. В английской версии блога, я немного порассуждал на тему того, какие "умницы" и как я рад видеть их новые инструменты, но повторяться мне лень . =)

Удачи!

воскресенье, 29 августа 2010 г.

My two cents in OSS. Free VOIP .Net library!

Мои поздравления всем! Только что в сфере .Net стало одной бесплатной VoIP библиотекой больше. Эта библиотека - моя обертка над C-библиотекой pjsip, точнее над ее высокоуровнем API pjsua (user agent).

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

Прошу любить и жаловать: http://code.google.com/p/pjsip4net/

Введение можно почитать здесь:
http://bobbbloggg.blogspot.com/2009/04/designing-managed-api-over-flat-native.html

Частично я уже описывал решения, которыми я руководствовался при создании этой библиотеки, но я планирую более подробно описать здесь внутренности библиотеки, одновременно проводя ее рефакторинг (я, кажется уже упоминал, что работа над ней продолжается ;). Ниже можно почитать о некоторых решениях, примененных в коде:
http://bobbbloggg.blogspot.com/2009/10/detached-template-method-pattern.html
http://bobbbloggg.blogspot.com/2009/09/fluent-builder.html
http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html

Удачи!

понедельник, 9 августа 2010 г.

Windsor Castle BuildUp

Некоторое время назад я обнаружил, что в лучшем DI-контейнере в .Net сфере Windsor Castle (это мое мнение не подтвержденное никакими фактами, кроме моих высказываний) нет такой простой функциональности как BuildUp. Некоторые из существующих DI-контейнеров, имеют такой метод, а Castle нет. Это неспроста. Я считаю, что BuildUp - это костыль для ситуаций, имеющих более элегантное решение, но бывают случаи, когда он оправдывает себя. Например, когда скорость решения проблемы важна. Под более элегантным решением я понимаю интеграцию с DI-framework, как, например, Castle WCF facility, но понимаете сами, сколько времени и ресурсов нужно для создания полноценного решения.

Должен признаться, что решение оказалось настолько простым, что я в недоумении, почему раньше этого никто не сделал. Хотя чего там, уже написано выше - костыль. Никто не признается просто.

Итак, прежде всего нужно ознакомиться с возможностями расширения Castle. Лазейка для BuildUp - это ComponentActivator. Активаторы вызываются при необходимости создать объект LifetimeManager'ами. Отсюда ограничение решения - с SingletonLifetimeManager оно работать не будет, но и не должно, если подумать. Устанавливая время жизни Singleton вы таким образом явно декларируете, что объектом (коего будет только один экземпляр) владеет контейнер, и создает его он же. А потому BuildUp для такого объекта - вещь бессмысленная.



BuildUpComponentActivator наследуется от DefaultComponentActivator и переопределяет только один метод - Instantiate. В этом методе мы извлекаем уже существующий и созданный вне контейнера экземпляр из контекста. Если в контексте его нет, то мы делегируем работу по созданию объекта базовому классу.

В контекст он помещается в методе расширении контейнера BuildUp как дополнительный параметр в IDictionary:



Для того, чтобы объект мог быть пропущен через BuildUp, в компонентной модели для него следует установить ComponentActivator. CanBeBuiltUp оборачивает такой вызов для castle Fluent registration API.

Я говорил, что решение удивительно простое? Это результат работы коллектива очень талантливых людей, к коим я не принадлежу, если чо. =)

Удачи!

четверг, 24 июня 2010 г.

Trigger Caliburn action status update through Prism's IEventAggregator

И Caliburn и Prism, в принципе решают одни и те же задачи - создание композитных приложений на WPF. Но, вот Роб Эйзенберг (создатель Caliburn) не считает, что они друг друга взаимоисключают, а я и подавно с ним согласен.
Я использую следующие "фичи" Prism'a:

  • modularity;
  • region manager;
  • event aggregator;
, а из Caliburn следующие:
  • actions engine;
  • application & model framework, даже не смотря на то, что с первого взгляда model framework кажется "overarchitected";
  • convention over configuration;
Вот сейчас я вам расскажу как расширить actions в Caliburn, при помощи Event Aggregator из Prism.
Главный способ расширения - это написание фильтров, которые вставляются в последовательность выполнения action. С их помощью можно проверять предусловия или состояние данных (к примеру можно проверить обладает ли Principal достаточными правами для выполнения действия), дабы определить статус action и обновить эффекты, применяющиеся к UI элементам. Примером такого фильтра является поставляющийся с framework фильтр Dependencies, который вызывает исполнение всей последовательности фильтров, на основании изменения какого-либо свойства, имя которого передается в качестве параметра ему. Но что, если вам нужно просто обновлять статус action, не связанный ни с каким полем в объекте, на основании какого-либо события/условия. Вы можете завести специальное поле и передергивать его значение или даже еще лучше - не заводите никакого поля, а просто кидайте нотификацию с именем несуществующего поля, переданного фильтру. Не знаю как вам, а у меня от таких решений зудит в одном месте.

Так вот зуд мой унялся только когда я написал фильтр, запускающий всю цепочку обработки статуса события по получению уведомления от EventAggregator сервиса Prism.

DependsOnEvent




Фильтр применяется как атрибут, которому передается тип события. Тут есть одно ограничение - событие должно быть унаследовано от generic типа CompositePresentationEvent закрытого типом object, т.е. CompositePresentationEvent_Of_Object. В методе Initialize происходит магия с помощью reflection. Дело в том, что IEventAggregator Prism имеет исключительно generic интерфейс, за что можно разработчиков его только поругать. Мы получаем событие переданного типа и
подписываемся на него. Вот именно для этого и приходится колдовать с волшебным зеркальцем, т.к. заранее тип события не известен. Часть, относящуюся к запуску обработки action, я содрал из кода упомянутого выше Dependencies фильтра.


Здесь мы создаем Observer, который будет следить за изменениями зависимых свойств. Т.к. реально никакие свойства не меняются я просто использую трюк с несуществующим свойством - в Initialize при подписке на событие я передаю делегат, который кидает событие обновления свойства Update, которого-то как раз и нет. Observer, поймав это событие запускает всю цепочку обновления статуса action.




PublishEventAfter
Ну и напоследок, фильтр, выполняющий все ровно наоборот, после выполнения action он кидает событие, которое обрабатывает EventAggregator.




Удачи!

пятница, 7 мая 2010 г.

Plant your Redis into Windows.

Redis - это OSC проект, представляющий собой высокопроизводительное key-value хранилище данных. Это вполне зрелый проект, используемый в реальных проектах в production. Написан он на Си, и основные целевые платформы - Linux, *BSD, Mac OS X, Solaris. Казалось бы такой хороший и такой недоступный (для Windows)? Ан нет, мало того что ServiceStack собрали и распространяют дистрибутив под Windows (работает через cygwin), так они еще и клиентскую .Net библиотеку написали! Но опять есть одно но - сервер работает в виде консольного приложения, что не очень-то подходит для сервера баз данных. Нужно захостить его в Win32 сервисе, но как?

Очень просто:


Берем OSC проект TopShelf - легкий framework для создания Win32 сервисов, берущий все сложности на себя, и пишем хост-сервис, который будет запускать и останавливать наш сервер.

Посмотрите, win32 сервис буквально в 10 строк кода.


Но, а как же насчет консольного окна? А просто - обратите внимание на аргумент передаваемый процессу сервера Redis (redis.conf). Это имя конфигурационного файла. В нем можно изменять любые настройки сервера. В частности там есть пункт daemonize, который на Linux запускает сервер в виде демона, на Windows же запуск с этим параметром приводит к созданию процесса без окна. И еще одно - x.RunAsLocalSystem();

Вот и все. Теперь запускаем собранный проект из командной строки с аргументами: {project.exe} service install, - и смотрим как все по волшебству происходит само. Теперь это полноценный Win32 сервис, можно запускать.

Удачи!

пятница, 25 декабря 2009 г.

ORM-style IdentityGenerator or impossible is nothing

То, что я сейчас собираюсь описать, иначе как грязный хак назвать нельзя. Но жизнь сложная штука, и иногда приходится изворачиваться как уж, чтобы добиться своего. А добиться я пытаюсь вот чего: чтобы NHibernate не ломал семантику Unit of Work при работе с классами, Id которых генерится Identity счетчиком в SQL Server.

Прежде всего, советую ознакомиться с историей вопроса:
о вреде Identity генераторов, еще о вреде и мнение в законе. Проблема Identyity генератора в том, что он не может получить Id, не вставив запись в таблицу, а без Id сущность нельза ассоциировать с NHibernate сессией, поэтому как только мы пытаемся связать объект с сессией, он тут же попадает в базу. Отсюда вырастают огромные проблемы в длинных бизнес транзакциях, когда все действия с БД атомарны и выполняются в отдельных БД транзакциях, а сама бизнес операция растянута по времени. Так вот откат бизнес транзакции будет невозможен в случае использования Identity генератора. А это как раз мой случай. Но, как я уже написал выше решение есть, но это грязный хак.

Итак. Прекратив ныть, про хак, перехожу к сути. Мне надо:

  • вставлять свои значения в поля Identity;
  • получать адекватные значения для Identity поля;
В SQL Server можно отключить автоинкрементацию Identity поля и вставить свое значение, например, пропущенное в последовательности (при удалении). А получить его можно, вставив в таблицу запись и удалив ее. Это возможно, потому что при откате транзакции значение счетчика Identity назад не откатывается, таким образом, изменив таблицу, мы перекидываем счетчик, а затем откатив транзакцию, убираем изменения.

Вооружившись этим знанием я нарисовал следующую схему:

Решение, как следует из картинки состоит из 3х частей:
  • Custom Id generator, который я назвал ORMIdentityGenerator;
  • PreInsert listener, для отключения автоинкрементного поля;
  • PostInsert listener, для его включения назад;
ORMIdentityGenerator

Следуя agile принципу KISS - keep it simple, stupid! я в
сего лишь конфигурирую его минимальным INSERT выражением, которое можно исполнить, не повредив базу и не вызвав нарушений целостности.

PreInsert


PostInsert


Вот и все. Теперь я могу спокойно редактировать объект в длинной сессии и откатывать изменения, когда потребуется. PS Простите ребята, гаджетом для вставки кода пока не обзавелся. Удачи!

пятница, 2 октября 2009 г.

Detached Template Method pattern

Идея не нова, ее я встретил впервые в Spring framework, в части интеграции с ORM framework’ами. Так для упрощения написания своих Repository или DAO (Как назвать дело вкуса. Я предпочитаю термин Repository, т.к. с точки зрения DDD он более точно описывает свое назначение.) Spring предлагает 2 опции:

  • передать своему DAO XXXTemplate и пользоваться предоставляемыми им методами, инкапсулирующими последовательность работы с конкретным ORM;
  • Унаследоваться от XXXDaoSupport, в котором XXXTemplate будет подставлен без вашего участия IoC контейнером;
Так что же это такое? Давайте обратимся к классикам [GoF]:

    «Template Method – паттерн поведения [классов]. Template Method определяет основу алгоритма и позволяет подклассам переопределить некоторые шаги алгоритма, не изменяя его структуру в целом.»

Почему Detached? Ну, вот так я придумал. Потому что это не предполагающая наследования реализация идеи Template Method в отдельном классе. Методы класса определяют последовательность действий, которые должны быть выполнены, скрывая детали реализации алгоритма и нижележащих ресурсов. Переопределение же некоторых шагов возможно при помощи callback’ов.

К примеру, под капотом у всех XXXTemplate в Spring происходит следующее (упрощенно):

  1. выделение ресурсов (создание connection и т.д.); (фиксированная часть алгоритма)
  2. начало транзакции; (фиксированная часть алгоритма)
  3. вызов callback executeInTransaction; (изменяемая часть алгоритма)
  4. возврат данных; (изменяемая часть алгоритма)
  5. подтверждение/откат транзакции; (фиксированная часть алгоритма)
  6. освобождение ресурсов; (фиксированная часть алгоритма)

Все эти шаги вам пришлось бы реализовывать самим в каждом месте, где предполагался бы код доступа к данным. Кроме того XXXTemplate скрывают детали реализации и отвязывают от лишних зависимостей. Например, HibernateTemplate конвертирует hibernate-специфичные exception’ы в Spring DataAccessException.

Я использовал этот прием для обхода ограничения языка C# - запрета множественного наследования. Представьте иерархию классов, в которой некоторые классы наследники базового класса должны обладать еще и дополнительными данными/поведением. А чтобы усложнить ситуацию, представьте, что в системе есть еще классы, не принадлежащие этой иерархии, но которые тоже должны обладать теми же данными/поведением. Интерфейс тут единственное возможное решение. Теперь более конкретно, чтобы обосновать применимость.

У меня есть базовый класс Resource, реализующий disposable pattern. Многие из его наследников – объекты системы, хранящие данные о состоянии системы и идентифицирующие конкретные экземпляры по Id.

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

Как видите, IIdentifiable наследует интерфейс IEquatable, т.е. объекты должны сами определять является ли переданным им экземпляр идентичным. И, наконец, тождественность объектов должна определяться не только на основании Id, но и на основании других полей данных. Чувствуете к чему это идет? Мне придется реализовывать логику сравнения по Id и по значимым полям в каждом классе, многократно дублируя код! Я такую личную неприязнь к дублированию чувствую, что аж кушать не могу.

Поэтому давайте разберемся а что же я должен сделать? Я должен реализовать алгоритм установления тождественности, который содержит фиксированную часть (сравнение ссылок

объектов, сравнение Id) и переменную часть (сравнение значимых данных, которые в каждом классе, вообще говоря, свои).

Потому в IIdentifiable я ввел метод DataEquals – это изменяемая часть алгоритма и, как мне кажется наименьшее из зол (но все-таки зло, потому что он публичный и засоряет интерфейс (один из способов уменьшения этого зла - explicit implementation)), а в каждом реализуемом методе Equals интерфейса IEquatable я делегирую выполнение алгоритма моей реализации Detached Template Metod – EqualsTemplate.

Я знаю, знаю, что в .Net есть IEqualityComparer, но мне мое решение нравится больше по 3м причинам:

  1. мне не придется «заставлять» пользователей моих классов использовать IEqualityComparer;
  2. мне кажется, что реализовать один метод проще, чем написать новый класс;
  3. оно мое;
Посмотрите как просто реализуется теперь этот алгоритм:



Удачи!