суббота, 31 декабря 2011 г.

Новогодний привет

Здравствуйте, уважаемые читатели!

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

пятница, 22 апреля 2011 г.

Управление сессиями NHibernate в приложениях ASP.NET MVC

Progg it

Здравствуйте, уважаемые читатели!

В этой статье я хочу ответить на типичный вопрос разработчика, начинающего использовать NHibernate в web-приложениях, разрабатываемых на основе ASP.NET MVC - как управлять сессиями и конфигурацией NHibernate в рамках веб-приложения. Это первая проблема, которая встречается разработчику, и для того, чтобы не потерять производительность, и не получить странных трудновоспроизводимых ошибок необходимо корретно реализовать этот механизм. В сети я находил несколько разных версий, и в этой статье я приведу ту, которая показалась мне наиболее удобной.

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

Таким образом, самое подходящее место для конфигурирования и создания фабрики сессий - это обработчик Application_Start. Я использую DI-контейнер LinFu, но он может быть с легкостью заменен любым другим. Я думаю семантика выполняемых действий будет ясна из приведенного кода.

protected void Application_Start()
{
 AreaRegistration.RegisterAllAreas();

 var serviceContainer = new ServiceContainer();
 serviceContainer.AddService(CreateNhSessionFactory());
 ServiceContainerProvider.Init(serviceContainer);
 
 RegisterGlobalFilters(GlobalFilters.Filters);
 RegisterRoutes(RouteTable.Routes);
}

protected ISessionFactory CreateNhSessionFactory()
{
 var sessionFactory = Fluently.Configure()
  .Database(
   MsSqlConfiguration.MsSql2008.ConnectionString(
    x => x.FromConnectionStringWithKey("ApplicationServices"))
  )
  .Mappings(x => x.FluentMappings.AddFromAssemblyOf<Issue>())
  .BuildSessionFactory();
 return sessionFactory;
}

Думаю из кода видно, что в Application_Start конфигурируется NHibernate, создается фабрика сессий и помещается в DI контейнер. По умолчанию LinFu использует поведение типа Singleton (единственный объект на все приложение), если при регистрации сервиса передается конкретный объект. Итак, я добился того, что у меня будет одна фабрика сессий для всего ASP.NET MVC приложения. Замечу, что приложение ASP.NET - это отдельная тема для обсуждения, но как минимум следует знать, что в одном приложении могут обрабатываться тысячи запросов, создает и уничтожает приложение IIS в соответствии с настройками. Теперь нужно сделать так, чтобы у нас на один запрос была только одна сессия, которая будет использоваться всеми классами слоя доступа к данным.

На самом деле нет ничего проще. Достаточно вспомнить, что есть структура данных привязанная к конктретному запросу - HttpContext. Ей и воспользуемся, для хранения сессии в рамках обработки одного HTTP запроса:

protected const string NH_SESSION_KEY = "NH_REQUEST_SESSION";

protected ISession GetSession()
{
 if (HttpContext.Current.Items.Contains(NH_SESSION_KEY))
  return HttpContext.Current.Items[NH_SESSION_KEY] as ISession;
 var session = ServiceContainerProvider.Container
  .GetService<ISessionFactory>()
  .OpenSession();
 HttpContext.Current.Items.Add(NH_SESSION_KEY, session);
 return session;
}

protected void CloseSession()
{
 if (!HttpContext.Current.Items.Contains(NH_SESSION_KEY)) return;

 var session = HttpContext.Current.Items[NH_SESSION_KEY] as ISession;
 session.Flush();
 session.Close();
 session.Dispose();
}

Итак, мы реализовали метод, который возвращает мне объект сессии привязанный к текущему потоку обработки HTTP запроса. При этом создание сессии ленивое, она не будет создаваться и открываться когда этого не требуется. Осталось только зарегистрировать способ получения сессии в DI-контейнере. Нет ничего проще:

protected void Application_Start()
{
 AreaRegistration.RegisterAllAreas();

 RegisterServices();
 RegisterGlobalFilters(GlobalFilters.Filters);
 RegisterRoutes(RouteTable.Routes);
}

protected void RegisterServices()
{
 var serviceContainer = new ServiceContainer();

 serviceContainer.AddService(CreateNhSessionFactory());
 serviceContainer.AddService(x => GetSession(), LifecycleType.OncePerRequest);

 ServiceContainerProvider.Init(serviceContainer);
}

Параметр определяющий время жизни объекта в данном случае не имеет особого значения, так как требуемый нам способ контроля за временем жизни реализован в методе GetSession(). Остался последний штрих, добавить закрытие сессии после окончания обработки HTTP-запроса:

protected void Application_EndRequest()
{
 CloseSession();
}

Все. Приведенные фрагменты легко адаптируются для другого DI контейнера, для ASP.NET WebForms приложения.

Возможно в посте содержатся неточности и даже ошибки, в связи с чем я буду благодарен, если вы мне на них укажете.

четверг, 10 февраля 2011 г.

Рассуждения о стоимости заказной разработки программного обеспечения

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

Я работаю в фирме которая занимается разработкой программного обеспечения, в том числе и разработкой на заказ. Я не буду раскрывать всех тонкостей нашего внутреннего формирования стоимости, но опишу главную идею и алгоритм прикидки цены, который мы используем каждый раз, когда к нам приходит заказчик и у нас начинаются с ним переговоры. Сначала расскажу пару небольших историй, которые произошли совсем недавно. Итак, история первая:

Деньгами не обижу, даю 20 тысяч!

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

Так вот, нам предлагалось разработать программу, которая бы собирала эти данные, сохраняла их в виде логов, и контролировала аварийные режимы работы системы. В программе предполагалось два рабочих места - одно место для рабочего на конкретном резервуаре, которое бы отображало текущее состояние в графическом виде, контролировала бы динамику процесса и аварийные режимы, ну и собственно сигнализировала бы об аварийных режимах. Второе рабочее место - это место главного инженера, на котором собирается информация со всех "одиночных" рабочих мест, и соответственно отображается информация и выполняются те же функции контроля. Нам показали другие программы, которые делают примерно тоже самое. Ах, да, еще важным требованием было, чтобы программа была "красивая".

Когда речь зашла о бюджете, нам сказали что проект срочный, что сделать надо за 2 недели (как раз с этого дня), и поэтому с деньгами нас не обидят. Правда из документации, требующейся программисту, у них на всю систему была только тонюсенькая методичка по протоколу взаимодейтсвия, и ничего больше у них не было. Заказчик упорно пытался увильнуть от ответа, сколько же он денег предполагает потратить, но все таки раскололся, и огласил гигантскую сумму в 20 тысяч рублей! Я чуть не рассмеялся прямо там же, но совладал с собой

Когда прошла первая волна эмоций, мы попробовали объяснить, что такие проекты нереально сделать за 20 тысяч, и также нереально сделать за 2 недели. Заказчик говорил, что вот, посмотрите, мы вам программы показывали! Они вообще бесплатные! Правда он забыл упомянуть что они идут в комплекте к серийной системе сбора информации, которая сама стоит приличных денег. В целом закончилось все хорошо - посмеялись и разошлись :)

Система лицензирования и оплаты за 6000!

Буквально сегодня зашел на weblancer.net и увидел, что некто хочет получить систему лицензирования и оплаты по СМС и пластиковым картам за 6000 рублей и в срок 1 неделя. Мне очень интересно было бы поговорить с заказчиком, что именно он хочет получить? Готов ли он доверить свои деньги и свой софт (который он по всей видимости собрался защищать) разработке неизвестного студента который будет это делать за пожрат. Может проще не защищать? Ведь это по всей видимости дешевле будет! А если уж защищать, то почему не заплатить $400-$600 за более-менее нормальную систему, которая конечно ничего не гаратирует, но от ручонок школьников вполне может помочь.

То же самое с оплатой по смс и картам, ведь это же деньги. Как можно доверять системе за 6000 которая будет это делать? Человек уверен что он сможет верифицировать код на наличие дырок, которые переводят деньги тому самому фрилансеру? Кто потом будет поддерживать код, если потребуется его куда-то перенести? Как вообще это можно сделать за одну неделю? Да, оплата через пластик это несложно, достаточно заключить договор с агрегатором и написать небольшой кусок для обертки его API, и да, какую-то версию можно сделать за неделю. Но стоит ли неделя разработки 6000? А офис? А интернет? А налоги?

Даже не глядя на результат, который заказчик возможно получит, я могу сказать, что это будет говнокод в лучшем случае, который дешевле выкинуть и написать заново. У меня такое представление, что наши "бизнес-владельцы" не умеют считать свои собственные деньги. Ведь в данном случае следовало бы один раз вложить деньги, и получить нормальный результат, который принесет ощутимую экономию в будущем. А если реальная экономия порядка 6000 рублей, то может не стоит инвестировать в проект?

Откуда берется стоимость часа работы

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

Итак начнем. Из чего же складывается стоимость разработки:

  1. Зарплата. Примем зарплату разработчика равную 25000 рублей в месяц. На руки.
  2. Начисления на зарплату и налоги. Если это организация на упрощенной схеме налогообложения, то это примерно 50% от чистой зарплаты (подоходный, пенсионные, ФСС)
  3. Отпускные. Нужно же отдыхать? Пусть будет 10% от зарплатных затрат.
  4. Непроизводительные расходы. Сюда входит ожидание ответов от заказчиков, выяснение требований, время на сдачу проекта, разборки с глюками сторонних библиотек и интерфейсов. Это примерно 10% от затрат. И это очень низкая оценка.
  5. Офис, интернет, мебель, железо и софт. По реальным оценкам - это где то 5000 в месяц. Опять же, очень низкая оценка, но жить, в принципе, можно.
  6. Риски. Всегда есть шанс недооценить проект, просчитаться по срокам, или вляпаться в неадекватного заказчика, у которого "хотелки" будут составлять столько же, сколько основной проект. Ну пусть тоже 10%.
  7. Прибыль. Нужно же еще и развиваться, что то делать для себя, покупать компоненты и т.д. ну пусть будет 10%. Так сказать по европейски скромно (сейчас это процент по рублевому банковскому депозиту).

Давайте просто арифметически прикинем во что это выливается. Я прикинул в экселе, и получается что необходимо иметь входящих 55500 рублей в месяц. Чтобы все получилось так, как я описывал выше. То есть от чистой зарплаты это больше чем в 2 раза! И это я взял еще маленькую зарплату, за которую в провинции можно найти человека, с более-менее адекватной квалификацией. Но в городах с развитым IT сектором на такую зарплату к вам пойдут только умственные инвалиды. Если посчитать стоимость часа (в среднем в месяц рабочих часов 164) то получается примерно 340 рублей. То есть уже больше $10. И это я оценил по минимальной планке!

Именно поэтому во всем цивилизованном мире уже известно, что лучше заплатить за готовый, серийный продукт чем написать свой такой же. Разница в стоимости будет минимум в десятки раз! Думаю теперь становится понятно, почему нельзя сделать систему защиты за $200, и систему контроля нефтехранилища за $700. Стоит ли говорить сколько подобных неадекватных заказчиков мы уже повстречали? Я уже не знаю как объяснить людям, что работа, котороая требует привлечения высококвалифицированных сотрудников не может стоить столько же сколько работа уборщицы или грузчика. Что странно доверять людям, которые просят за свою работу существенно меньше чем она того стоит. Что нужно учиться считать деньги, и считать их. Когда у вас болит зуб, и вам его выдергивают, и берут 700-1000 рублей фактически за 30 минут, вас это не смущает!