пятница, декабря 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:

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

потом таким:

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

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


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

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