пятница, декабря 28, 2007

Entity Framework – шесть способов выполнить объектный запрос

Должен вам сказать, что Entity Framework (EF) представляет собой непаханое поле для блогописательства. И в следующем году я планирую целую серию постов на эту тему. Выход EF анонсирован на февраль 2008 года, и учитывая его сложную судьбу, нам всем стоит держать кулаки за то, чтобы это событие не сорвалось. Потому что, после довольно детального изучения сабжа, я вам должен сказать, что EF это не просто ORM, это большой удар по разгильдяйству и бездорожью в разработке на .Net.
А пока, в качестве иллюстрации возможностей EF рассмотрим различные способы выполнения объектного запроса. Во всех случаях мы будем выполнять запрос, который должен вернуть объект класса Person из корпоративной базы Orgchart по его персональному идентификатору (PIN).
Первый способ, назовем его «классический». Для работы с объектами EF используется контекст, который представляет собой экземпляр класса, унаследованного от System.Data.Objects.ObjectContext. Такой класс (как и все классы объектов домена) генерируется визардом по EDM описанию. Для выполнения объектных запросов используется класс System.Data.Objects.ObjectQuery:


static void Test()
{
// это значение для выборки
int pin = 1840;
// для работы с EF создаем ObjectContext
using (Orgchart dataContext = new Orgchart())
{
//создаем запрос
ObjectQuery<Person> query = new ObjectQuery<Person>(
"select value p from Orgchart.Persons as p where p.PIN=@pin",
dataContext);
// добавляем параметр
query.Parameters.Add(new ObjectParameter("pin", pin));
// выполняем запрос (здесь мог быть foreach)
Person p = query.First();
if (p != null) Console.WriteLine("Name:{0}", p.LastNameRus);
}
}


Все довольно очевидно. Сначала создаем контекст “dataContext”. Затем создаем запрос, передавая ему строку запроса на eSQL (entity SQL) и контекст, и передаем запросу параметр. Обратите внимание, что в запросе параметр казан с символом @, а в имени параметра этот символ не используется. Запрос исполняется при вызове метода First() (поскольку нам нужен только один экземпляр Person, а вообще тут мог быть foreach).

Второй способ аналогичен первому, но проще. Дело в том, что при создании класса контекста визард генерирует типизированные коллекции для каждого Entity Set в виде свойств этого контекста. Воспользуемся этим:


static void Test()
{
// это значение для выборки
int pin = 1840;
// для работы с EF создаем ObjectContext
using (Orgchart dataContext = new Orgchart())
{
// dataContext.Persons сгенерирован визардом
Person p = dataContext.Persons.Where("it.PIN=@pin", new ObjectParameter("pin", pin)).First();
if (p != null) Console.WriteLine("Name:{0}", p.LastNameRus);
}
}


Здесь мы воспользовались методом ObjectQuery.Where() поэтому нам не надо указыать весь объектный запрос а только условие выборки. Кстати, форма записи «it.PIN», где it отсылает нас к текущему объекту выборки, а PIN это имя свойства этого объекта, пока (beta 3) нигде не задокументирована :).

Третий способ практически аналогичен второму, но использует другую реализацию ObjectQuery.Where(), которая в качестве параметра принимает лямбду:


Person p = dataContext.Persons.Where<Person>(c => c.PIN == pin).First<Person>();
if (p != null) Console.WriteLine("Name:{0}", p.LastNameRus);


Несмотря на минимальные отличия от прошлого варианта, эффект колоссальный. Во первых нам не надо передавать параметр. Но главное, - наше условие выборки в виде лямбды проверяется компилятором, в частности правильно ли мы указали имя свойства и правильный ли у нас тип параметра. В первых двух способах было не возможно ничего подобного. Если бы мы ошиблись в тексте запроса, то узнали об этом только в результате ошибки runtime. Здесь же мы получим ошибку компиляции. И это хорошо.

Четвертый способ по своей сути является всего лишь альтернативной формой записи предыдущего, но это уже LINQ:


p = (from c in dataContext.Persons where c.PIN == pin select c).First<Person>();
if (p != null) Console.WriteLine("Name:{0}", p.GetFullName());


Чисто декларативный синтаксис. Указываем откуда выбрать, как и что. Красота.

Пятый способ. Иногда нас интересует не весь объект, а всего несколько его свойств. Тут на помощь приходят анонимные типы:


var x = (from c in dataContext.Persons where c.PIN == pin select new { Name = c.LastNameRus, Pin=c.PIN }).First();
if (x != null) Console.WriteLine("Name:{0}", x.Name);


Вместо переменной типа Person мы получаем переменную var x, которая имеет свойства LastNameRus и Pin и ничего более.

Ну и наконец, последний, шестой способ. Он кардинально отличается от предыдущих пяти тем, что использует классы из пространства System.Data.EntityClient. В частности, EntityCommand и EntityDataReader. Я бы назвал это режимом обратной совместимости, потому что он возвращает нас в классический ADO.NET.
EntityConnection - это наследник DBConnection, EntityCommand – наследник DBCommand, а EntityDataReader – наследник DBDataReader. Схема работы классическая для ADO.NET: открываем соединение, создаем команду, передаем ей запрос, исполняем команду – получаем DataReader, читаем данные из ридера:


static void Test()
{
// это значение для выборки
int pin = 1840;
// создаем соединение
using (EntityConnection connection = new EntityConnection(@"metadata=.\Model1.csdl|.\Model1.ssdl|.\Model1.msl;provider=System.Data.SqlClient;provider connection string='Data Source=(local);Initial Catalog=Orgchart;Integrated Security=True'"))
{
// открываем соединение
connection.Open();
// создаем комманду
EntityCommand command = new EntityCommand("select value p from Orgchart.Persons as p where p.PIN=@pin", connection);
// добавляем параметр
command.Parameters.Add(new EntityParameter("pin", System.Data.DbType.Int32)).Value = pin;
// получаем reader, используя комманду
using (EntityDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SequentialAccess))
{
if (reader.Read())
{
Console.WriteLine("Name:{0}", reader["LastNameRus"]);
}
}
}
}


Однако при всем при этом, заметьте, мы работаем не с БД и SQL, а с объектной моделью EF и eSQL. Но прямо скажем, не самый удобный способ из рассмотренных. Зачем это надо? Ну, наверно кому-то надо.

Ну а выводы?
По русской традиции, каждый делает выводы для себя сам.
По американской традиции, не каждый может сделать правильные выводы :), и поэтому summary:
- Entity Framework это ORM от Microsoft который мы ждем уже много лет;
- От прочих ORM его отличают по крайней мере две вещи: здесь есть LINQ, и он обратно совместим с ADO.NET

P.S. Мне был бы интересен ваш фидбэк, поскольку я собираюсь сделать еще несколько постов на тему практических вопросов использования Entity Framework. Интересна ли тема? Если да, то какие вопросы интересуют в первую очередь?

среда, декабря 26, 2007

Антикарьера?

Дауншифтинг (англ. downshifting) - отказ от карьеры, жизнь для себя. А может это путь к настоящему успеху? Интересный взгляд на проблему в блоге "Профессия IT".
Рекомендую.

вторник, декабря 25, 2007

Это вам не небоскребы строить…

Программная инженерия, с самого начала сталкивалась с проблемами вовсе не характерными для других видов инженерной деятельности. Некоторые считают, что программирование вообще не имеет права называться инженерной дисциплиной потому, что тут царит непроходимый бардак.
Программирование любят сравнивать со строительством (в негативном плане – если бы дома строили так, как пишут программы…). Но дело в том, что в строительство описается на четкие математические основы таких дисциплин как сопротивление материалов, термо- и гидро-динамика и т.д. Вплоть до того, что будущий проект можно и нужно математически просчитать на реализуемость, надежность и устойчивость. Такой же прочный математический фундамент лежит и под другими видами инженерной деятельности. Однако он же является фатальным ограничителем для них. Мы не можем построить здание только из стекла, потому что стекло не обладает необходимыми характеристиками, и мы не умеем надежно соединять стекло со стеклом.

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

Безграничные возможности имеют обратную строну. Очень малую часть программ можно формализовать при помощи математического аппарата, а значит и автоматически генерировать, автоматически верифицировать, отыскивать ошибки и т.д. Как следствие этого проблема неопределенности. О программе нельзя сказать ничего определенного до тех пор, пока она не будет реализована! Программирование, это не детерминированный и эвристический процесс. Программу, обладающую фиксированным набором выходных характеристик всегда можно реализовать множеством различных способов. И это вносит своего рода piece of art в труд программиста и роднит его, если не с художником, то с исследователем.

Безграничные возможности и многовариантность путей реализации, это сама по себе проблема, когда программист – перфекционист начинает устраивать бесконечный рефакторинг своего кода. Или когда случается «недержание креатива» в дизайне, которое мы обсуждали здесь.

Безграничные возможности это большой соблазн. Программу легко модифицировать. Она никогда не закрыта для изменений. Никому не придет в голову переделывать квадратный дом в круглый, после того как, построен третий этаж. В программировании такое считается нормой. Переделали базовый класс фундамента, и все классы этажей унаследовали его круглую форму :). Если дизайн программы позволяет делать такое - это удачный дизайн. Это все понимают и никто не стесняется попросить переделать форму фундамента за два дня до сдачи проекта.

Безграничные возможности – это нарастающая как снежный ком сложность программных систем и весь ворох проблем с этим связанных.

В общем, как обычно, то что делает программирование таким привлекательным для использования, порождает и большинство проблем.
Бороться с этими трудностями пробовали разными способами. Один из них состоит в четкой регламентации всех аспектов деятельности, связанных с созданием программ. Это путь Unified Process. Четко определить все требования, четко их зафиксировать, четко проследить их реализацию и четко протестировать готовый продукт на соответствие требованиям. Что бы не говорили о UP, но несомненное и, наверное, главное его достоинство в том, что именно в его рамках удалось более менее четко описать подходы к проектированию программных систем, особенно, в части превращения требований в проектные решения. Но UP не мог решить всех проблем, даже после того, как из водопадного его превратили в итеративный. Вернее, мог, но за очень большие деньги. Печально, но факт – с повышением уровня зрелости UP проектные затраты начинают расти с катастрофической скоростью.

Со временем появился и другой путь для решения проблем разработки программ. Первоначально появился он в виде откровения XP, и за его шокирующей по началу атрибутикой смысл угадывался с трудом. А идея оказалась очень продуктивной. Суть в том, чтобы превратить проблемы в преимущества. Проблема в том, что требования меняются? - отлично, давайте будем менять их постоянно. Готовый продукт не соответствует потребностям? – хорошо, посадим заказчика рядом с программистами, пусть участвует в процессе. Сроки постоянно срываются? – не будем определять сроков, продукт всегда будет готов к использованию. Это кажется странным, но XP использует все характерные особенности программирования, которые отличают его от других видов инженерии. Ведь, правда, мы же не в бетоне кодируем, мы всегда можем вносить изменения в код. И программа начинает работать не перед самой сдачей. Написали функцию – компилируем, запускаем, проверяем - работает. Так почему это не показать заказчику. Методика называется «экстремальной» потому, что доводит до крайности вполне очевидные вещи. И это работает.

Хорошо. Но почему тогда XP не появилась раньше? Почему столько лет тысячи проектов успешно заваливались водопадным методом?
Говоря об XP мы часто забываем о том, что она базируется на самых передовых инженерных практиках в разработке софта, которые были созданы за предыдущие десятилетия. Я говорю о непрерывной интеграции, об автоматическом тестировании, рефакторинге и прочих вещах. Сами средства разработки сделали огромный шаг вперед. Почему Брукс в IBM не мог применять XP во время эпопеи разработки OS/390? Да просто инструменты не позволяли. Компиляция шла прогонами, прогон занимал несколько часов, а код предварительно вычитывали на наличие ошибок.

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

Вторая сторона процесса это образование бессчетного множества т.н. Agile методик разработки. Все они разнятся в деталях, но большинство из них полный отстой. И я объясню почему. Гибкость, привнесенная XP, является исключительно важным достижением. Гибкость, это возможность вносить изменения по ходу разработки, гибкость – это очень короткая обратная связь между заказчиком и продуктом, это возможность постоянно видеть, как выглядит создаваемый продукт. Но цена этой гибкости необычайно высока. Гибкость достигается комбинацией всех практик XP, которые дополняют и поддерживают друг друга. Кент Бек говорит о практиках XP:
«Чтобы обеспечить их эффективное применение на практике вы должны использовать их все одновременно».

Кроме того, XP требует от программистов высочайшей дисциплины, высочайшей квалификации, и высочайшего напряжения. В общем это такая весьма потогонная система. И те, кто ее пробовал ее на практике, это поняли. В результате стали появляться различные гибкие Agile методики, которые обещают те же результаты, но без экстремальных нагрузок XP. Но, увы, чудес не бывает. XP и сама по себе имеет ряд недостатков, а когда из нее выдергивают куски и пытаются использовать по отдельности, то недостатки множатся а достоинства тают. В результате большинство Agile методик за громкой терминологией скрывают свою методологическую импотенцию, а проекты выезжают на энтузиазме евангелистов от agile и новообращенных.

Недавно прокатилась волна публикаций про Post Agile. Но правда без существенных последствий, как прокатилась, так и стихла. А серебряной пули как не было так и нет. Как нет и золотой методики. Ни CMMi, ни PMBook, ни RUP ни XP пока не могут гарантировать успешного исхода нового программного проекта просто самим фактом своего использования. Все в наших руках.

Итоги опроса "Какую методику разработки ПО вы используете"

Завершаю свой опрос несколько раньше срока, поскольку поток голосующих практически иссяк. Данные не претендуют на большую репрезентативность и объективность, но некоторую пищу для размышлений дают.
Всего в опросе приняло участие 86 человек, и поскольку в опросе была возможность давать несколько ответов, общее число ответов 105. Часто один человек одновременно участвует в нескольких проектах и эти проекты могут использовать разные методологии.
Таким образом у нас есть 105 проектов, и в среднем на одного человека приходится 1,2 проекта.

Традиционные, "тяжелые" методики используются в 15% проектов. Из них на долю MSF (Microsoft Solution Framework) приходится лишь 3%, а на долю RUP (Rational Unified Process) - 12%.
Гибкие методологии используются в 43% проектов. Extrime Programming используют 14%, и 29% предпочитают всевозможные менее экстремальные Agile методики.
Как ни печально, но 41% всех проектов не используют никакой методологии.

Признаюсь честно, последняя цифра оказалась для меня весьма неожиданной. Если учесть тот факт, что на части проектов вывеска Agile прикрывает полное отсутствие проектного управления, то получается, что около половины всей разработки находится в состоянии дремучего бардака.
Для микро-проектов, с числом программистов не более одного, можно сказать что организация процесса не имеет особого значения. Хотя и в этом случае без применения нормальных инженерных практик, таких как тестирование или анализ требований, вероятность получения результата будет стремится к нулю.
Я то думал, что времена, когда программистов усаживали писать софт не определив ни целей, ни требований, ни сроков, уже давно канули в лету. Ан нет.
Раз все так плохо, может мне стоит открыть консалтинговый бизнес по постановке процесса разработки. Не по аутсорсингу разработки, а именно по выстраиванию нормальной модели проектной команды и проектного процесса. Когда в команду приходит инструктор, и по ходу реального проекта помогает решать рабочие вопросы: требования, взаимодействие с заказчиком, коммуникаций внутри команды, интеграция, тесты, и т.д. и т.п., параллельно выстраивая Процесс в соответствии со спецификой проекта и потребностями клиента. То, что обозначается модным сейчас словом коучинг (от coach - тренер). Многочисленные agile евангелисты сейчас вплотную подбираются к такой модели бизнеса. Но почему только agile?

понедельник, декабря 24, 2007

Google готовится к празднику...

Забавно наблюдать, как за последние двое суток менялся логотип Google:

сначала он стал таким:

потом таким:

затем вот таким:

и сейчас он выглядит вот так:


Похоже это еще не конец. Не зря же они стакан выкатили :)) Место для пятого логотипа пока свободно.

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

четверг, декабря 13, 2007

Программисты и рационализаторы погубили советскую марсианскую программу

В начале 70-х годов прошлого столетия между СССР и США разгорелась очередная космическая гонка, кто первым совершит мягкую посадку на Марс. Советскую марсианскую программу преследовали хронические неудачи. Из целой армады межпланетных станций только одной удалось совершить мягкую посадку, однако ни одной фотографии аппарат так и не передал.
Оказывается на аппараты марсианской серии впервые были установлены бортовые цифровые ЭВМ. И тут началось. Первая станция так и не смогла покинуть околоземную орбиту:
"...Однако на траекторию полета к Марсу станция не перешла, так как не произошло повторного запуска двигателя разгонного блока 11С824 (блок Д). Как выяснилось при разборе неудачи, в бортовую вычислительную машину было введено ошибочное значение времени запуска двигателя блока Д. Из-за ошибки в разряде двигатель должен был запуститься не через несколько десятков минут, как предусматривала программа полета, а через полторы сотни часов. Аппарат с так и не сработавшим блоком Д остался на низкой околоземной орбите. В сообщении ТАСС АМС была названа очередным спутником "Космос 419". Через два дня после запуска, 12 мая 1971 года аппарат вошел в плотные слои земной атмосферы и сгорел."


Вторая станция погибла тоже из-за программной ошибки:

"Официально она получила обозначение "Марс-2". Полет этой станции проходил вполне нормально, блок 11С824 отработал успешно и перевел аппарат на траекторию полета к "Красной планете". В ходе полета 17 июня, 20 и 27 ноября проводились коррекции траектории полета АМС. 27 ноября 1971 г. после проведения третьей коррекции перед отделением СА начала работу бортовая ЦВМ с целью выработать уставки на вход спускаемого аппарата в атмосферу Марса. Однако сработала БЦВМ неправильно, в СА были введены ошибочные уставки. Виной тому была программная ошибка в БЦВМ. Как выяснилось потом при разборе неудачи, "Марс-2" шел к "Красной планете" очень точно. Ориентация до отделения СА от орбитального блока практически не отличалась от расчетной ориентации СА для перевода на траекторию попадания. В этом случае до отделения спускаемого аппарата и его закрутки вокруг продольной оси работа системы ориентации станции не требовалась. Однако из-за ошибки в программе БЦВМ восприняла ситуацию неправильно и сформировала уставки, предусматривающие нерасчетную ориентацию АМС перед отделением. Через 15 мин после отделения на СА включилась твердотопливная двигательная установка. Она все-таки обеспечила перевод спускаемого аппарата на траекторию попадания на Марс. Однако угол входа в атмосферу оказался больше расчетного. Спускаемый аппарат слишком круто "зарылся" в марсианскую атмосферу, из-за чего не успел затормозить на этапе аэродинамического спуска. Парашютная система уже ничего не смогла сделать. 27 ноября 1971 г. СА, "прошив" атмосферу "Красной планеты", разбился о поверхность Марса в точке с координатами 4° с.ш. и 47° з.д. (Долина Нанеди в Земле Ксанфа). В сообщении ТАСС, посвященном "Марсу-2", говорилось, что на Марс впервые доставлен "вымпел с изображением Герба СССР". И это - правда: на борту СА действительно был закреплен вымпел. В делах космоса ТАСС тогда не врал. Вымпел вместе с "обеспечивающими доставку средствами", или как их назвал ТАСС - "капсулой", весил несколько сот килограммов. Никакой научной ценности жесткая посадка "вымпела" не имела."


Надо полагать, тестировщиков у них не было вообще. Но заметьте, менеджеры проекта оказались на высоте. Размазанный в лепешку спускаемый аппарат оказался "вымпелом с Гербом СССР". Кто нибудь что нибудь имеет против Герба СССР?
В общем, первые экспедиции тестировали программное обеспечение БЦВМ. Дальше казалось, все пойдет нормально. Но не тут то было. В дело вмешались народные рационализаторы.
"Во время комплексных электрических испытаний на космодроме на станции 3МП №51 произошел отказ в согласующем устройстве БЦВМ. При анализе неисправности выяснилось, что причиной отказа стало изменение технологии производства микросхем, изготавливаемых в Воронеже. С целью увеличения выпуска этого типа радиодеталей было предложено рационализаторское предложение. Оно заключалось в замене напыляемого в микросхемах золотого слоя на алюминиевый. Казалось, при этом характеристики изделия не ухудшались Однако через полгода-год в результате старения на алюминиевом слое образовывались раковины, что служило причиной выхода элемента из строя. Эти микросхемы использовались на всех аппаратах М-73. Анализ ситуации показал, что велика вероятность отказа БЦВМ по вине микросхем и вследствие этого - выход станций М-73 из-под контроля еще на трассе перелета к Марсу."

Я просто в ауте. И что вы думаете, они остановили программу и поменяли бракованные микросхемы? Ничего подобного. Они отправили их так как есть.
"В ходе полета станции отказали два из трех каналов БЦВМ. Причина была в той самой микросхеме. В связи с этим вторую коррекцию при подлете к "Красной планете" провести уже не удалось. 10 февраля 1974 г. станция подошла к Марсу. Однако бортовая вычислительная машина не выработала уставок на торможение и переход на орбиту ИСМ, корректирующая двигательная установка АМС не включилась. Поэтому в 18:34 ДМВ аппарат пролетел на высоте 1844 км над средним радиусом Красной планеты (5238 км от центра). Единственное, что он успел сделать, это по команде с Земли в 18:32:41 ДМВ включить свою фототелевизионную установку с короткофокусным объективом "Вега-3МСА"."

И так далее. Одна за другой на станциях отказывали БЦВМ, радиокомплексы и прочая аппаратура. Все цитаты взяты из материала в журнале "Марсианское время".
А в США, тем временем, миллиарды тратились на создание стандартов разработки софта (MIL-STD-498) и управления качеством (MIL-Q-9858). Результаты, как говорится, на лице. Американские марсоходы никак не хотят ломаться и продолжают ползать по марсианским пустыням, а у нас с 1971 года ни одна марсианская миссия так и не достигла успеха.

воскресенье, декабря 09, 2007

Их надо знать в лицо

Кто не слыхал фамилий Страуструпа, Дейкстры или Кнута? А как выглядят столпы програмирования? Можно посмотреть здесь.
Алан Кей, Джеймс Гослинг, Гвидо Ван Россум, Грэди Буч, Мартин Фаулер (особенно Мартин) личности не только не заурядные в профессиональном плане, но и оказывается весьма колоритные :).

P.S. Отпустить бороду. чтоль? Боюсь, только, не поможет уже...