Showing posts with label проектирование. Show all posts
Showing posts with label проектирование. Show all posts

Monday, March 22, 2010

Список интересных подкастов: выпуск #4

Новая подборка интересных подкастов, которые я бы рекомендовал к прослушиванию. Сегодня разбиваем на категории:

.NET 4.0:

Jason Olson проходит по некоторым новым фичам CLR, C# и BCL. Concurrent GC, side-by-side CLR versions, Memory-Map files, co-variants и contra-variants, Parallel Extensions, немного об обновлениях в языках программирования и новых языках. И да, они наконец-то выкинули CAS и заменили его на более простой механизм. Хотя кто его вообще использовал :)

Небольшой обзор изменений в ASP.NET AJAX 4.0. От UpdatePanel до полностью кастомных AJAX-запросов и JavaScript-контролов. jQuery теперь "часть" ASP.NET AJAX, переработанный AJAX Control Toolkit - тоже, более того, AJAX Control Toolkit теперь работает не только с WebForms и MVC, но даже с PHP или любым другим back-end'ом. ASP.NET AJAX поддерживает dual data-binding на клиенте, который работает по аналогии с дата контекстом EF или L2S, на сервере его поддерживает WCF Data Services, которые раньше назывались ADO.NET Data Services. На закуску немного о ScriptLoader, history API, Microsoft CDN, Microsoft AJAX Minifier, Sea Dragon и Deep Zoom.

Честно говоря, еще сам не слушал этот подкаст, но судя по транскрипту - довольно любопытно. Foreign Keys, POCO и поддержка DDD разработки и модульного тестирования, Lazy/Deferred Loading, поддержка N-Tier сценариев при помощи Self-tracking entities, T4 templates, Code Only (в общем, все то, о чем я уже когда-то писал), немного о WCF Data Services, а также история о том, как Julie помогала Oren Eini (Ayende) создавать EFProf.

Обсуждение возможностей первого функционального языка программирования, включенного в .NET 4.0. Немного о том, что такое функциональные языки вообще, зачем нужен функциональный язык в .NET и какую пользу он может принести обычным разработчикам, привыкшим к императивным языкам вроде C#, VB.NET, Java или С++, некоторый ликбез по терминологии функциональных языков. Много интересного контента и шуток благодаря Теду.

Интервью с програм менеджером DLR team. Конечно же, обсуждение DLR, который релизится с .NET 4.0, и его двух основных языков: IronRuby и IronPython. Разговаривают об архитектуре DLR, истории развития, возможностях, отличиях Iron-версий языков Ruby и Python от своих оригиналов, IronRuby on Rails :)

Другое:

И снова непревзойденная Tess. О чем еще с ней можно поговорить, как не об отладке. Что такое Memory Dump, как его создавать и почему об этом важно знать, что такое Allocated и Committed memory, как пользоваться WinDbg и CDB для отладки "утечек памяти" в .NET и проблем с производительностью, а также некоторые улучшения с отладкой многопоточных приложений в VS2010 и в предыдущих версиях, о которых вы, возможно, не слышали.

Интервью с создателем WebFormsMVP - очень интересного MVP-движка для WebForms. Автор рассказывает, что такое MVC и MVP, зачем использовать паттерн MVP в WebForms приложениях, архитектуре движка, особенностях его использования и том, насколько полно он работает с остальной инфраструктурой ASP.NET. Надо будет обязательно попробовать его в боевом проекте - по идее, должен сберечь кучу времени и сил.

Приятно, что в нашем уголке мира появляются хорошие подкасты :) В гостях у питерской группы ALT.NET подкаста Александр Бындю и Виталий Стахов. Разговор идет о вполне понятных вещах: принципах ООП (SOLID), TDD, практиках XP, полезных инструментах, развитии программиста и различных вариантах построения и развития команд. Прикольно, что Александр Бындю точно так же понимает разницу между Scrum и XP, как и я.

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

Обсуждение Domain-Driven Design и CQRS (Command and Query Responsibility Segregation pattern) с Мишей Чалым и frozen_space. Если про DDD многие хотя бы краем уха слышали, то что такое CQRS для меня для самого тайна :) Где помогает DDD и зачем он нужен, что такое CQRS, его преимущества и недостатки. В общем, самое острие программной инженерии - не пропустите! Подкаст только записали, завтра буду слушать сам.

И напоследок, как всегда, тема попроще :)

Скотт общается с Warren Sande и его 10-летним сыном об их опыте написания книги по обучению программированию для детей и других начинающих программистов. Вроде бы ничего особенного, но удивляет этот 10-летний малыш. Мало того, что он помогал отцу в написании книги и примеров для нее на Питоне, но он еще и рассуждает обо всем по-взрослому. Интересно, он просто настолько умен или изучение программирования действительно ускоряет развитие у детей?

Приятного прослушивания!

Thursday, March 11, 2010

Слайдкаст по принципам проектирования

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

Должен сказать, я надеялся, что это будет легче. Лепил я его в течении нескольких дней, сначала более-менее приведя в порядок звук (хотя некоторые мои мэканья, неверные стилистические обороты и дыхание кое-где пооставались, извините), потом вдоволь навоевавшись с конвертором презентаций Slideshare (было несколько проблем с нежеланием конвертировать и неверным отображением), и в заключение победив их не самый безбажный редактор слайдкастов. Но все-таки приятно, что на Slideshare есть возможность создавать слайдкасты - это действительно здорово.

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

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

Если вдруг слайдкаст не открывается из блога - вот прямая ссылка.

Принимаются любые пожелания по улучшению.

PS. И спасибо Вове Лещинскому за микрофон!

Tuesday, March 2, 2010

Доклад о принципах проектирования

Готовлю еще один доклад для харьковской Uneta по принципам проектирования.

Основные цели:

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

Доклад будет частично построен на заметке о качественном коде и проектировании. Частично, потому что этот материал пойдет лишь в начало доклада, а в основной его части я планирую все-таки рассказать про популярные на данный момент принципы проектирования (как общие, так и ООП): SoC, DRY, KISS, YAGNI, Low Coupling, High Cohesion, а также пятерку SOLID. Принципов много, и каждый из них, конечно, достоин отдельного небольшого доклада, поэтому придется рассматривать их достаточно поверхностно. Также очень хочется успеть дать какие-то взаимосвязи между ними, чтобы они лучше запоминались, и хотя бы пару примеров. Таким образом, доклад будет больше посвящен теории, а не практике.

Вторым докладчиком будет мой бывший одногруппник Денис Резник. Тема его доклада: “Защита данных в SQL Server 2008 при помощи Transparent Data Encryption”.

Встреча будет проходить в Харьковском национальном университете радиоэлектроники (ХНУРЭ), пр. Ленина 14, ауд. 329 (м. Научная), 5 марта 2010 в 18:25, то есть в эту пятницу вечером.

Если что-то изменится с местом, временем или форматом встречи – я сообщу дополнительно в комментариях.

Жду всех, кто захочет послушать и пообщаться на эту тему :)

Wednesday, February 3, 2010

Архитектура по Фаулеру

Пару дней назад наткнулся на статью Фаулера "Кому нужен архитектор?" ("Who Needs an Architect?"). Ей уже сто лет в обед, но я ее первый раз вижу.

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

"Whether something is part of the architecture is entirely based on whether the developers think it is important. People who build “enterprise applications” tend to think that persistence is crucial. When they start to draw their architecture, they start with three layers. They will mention “and we use Oracle for our database and have our own persistence layer to map objects onto it.” But a medical imaging application might include Oracle without it being considered part of the architecture. That is because most of the complication is in analyzing the images, not in storing them. Fetching and storing images is done by one little part of the application and most of the developers ignore it."

А вот еще кусочек:

"There is no theoretical reason that anything is hard to change about software. If you pick any one aspect of software then you can make it easy to change, but we don’t know how to make everything easy to change. Making something easy to change makes the overall system a little more complex, and making everything easy to change makes the entire system very complex. Complexity is what makes software hard to change. That, and duplication."

Это волшебно. Рекомендую почитать.

Если понравится, можно почитать еще пару интересных статей на тему архитектуры и проектирования:

Gaperton on Software Architecture - статья Gaperton о похожем с примерами и заодно с пояснениями, как согласуется архитектура с дизайном
The Difference between Marketecture and Tarchitecture - статья о компонентах архитектуры: Market-oriented и Technical-oriented
Is Design Dead? - статья об эволюционном проектировании, много разговоров на тему того, что ХР - это супер-пупер, но в целом есть что полезного почерпнуть

Что думаете?

PS. Поделитесь чем-нибудь интересным на эту тему.

Sunday, January 17, 2010

Качественный код и проектирование

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

Под внутренним качеством подразумевается не качество самого приложения (внешнее качество), то есть отсутствие ошибок, соответствие требованиям, простоту использования и т.д., а качество кода этого самого приложения.

Свойства качественного кода

Какими же свойствами обладает качественный код:

  • расширяемость, гибкость (extensibility, agility)
  • сопровождаемость (maintainability)
  • простота (simplicity)
  • читабельность, понятность (readability, clarity)
  • тестируемость (testability)

Конечно, это не все полезные свойства, которыми может обладать код, но мы пока остановимся на этих. Эти свойства без преувеличения можно назвать ценностями кода, потому что код, ими обладающий, является по-настоящему ценным :)

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

Итак, теперь мы лучше понимаем, что означают абстрактные слова "хороший код", "правильный код" и т.д. Это код, который обладает полезными внутренними качествами (ценностями).

Как же достичь хорошего кода?

Существует довольно много способов, и их можно условно разделить на внешние и внутренние. Внешние способы - это различные программистские практики, например, парное программирование, статический анализ кода, code review и т.д. В какой-то степени сюда можно отнести и модульное тестирование с TDD/BDD, так как они улучшают качество кода: написать модульные тесты на существующий плохой код довольно сложно, поэтому его приходится рефакторить, а при использовании TDD/BDD написать плохой код с самого начала довольно сложно, хотя и вполне реально.

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

Внешние способы достаточно результативны, однако они всегда являются лишь дополнением внутренних. Если программист не обладает навыками правильного написания кода и проектирования, парное программирование с более сильным товарищем или code review ему поможет. Но что делать, если они оба не обладают этими навыками? Поэтому для каждого программиста, кроме знания инструмента (языка программирования, технологий) важно также и умение ими пользоваться (я уже когда-то об этом писал). Это 2 разных, ортогональных друг другу направления развития.

Итак, рассмотрим один из внутренних навыков, а именно навык проектирования (design).

Зачем каждому программисту иметь навыки проектирования

Многие программисты думают, что проектирование - это какая-то специальная фаза при разработке ПО, считают ее сложной и не всегда нужной. Строят там какие-то заумные дяди какие-то UML-диаграмки и прочую чушь. Все равно ведь когда будем писать код - будем половину менять и переписывать. Но ведь на самом деле, проектирование - это не только формальная фаза процесса создания ПО (практически любого), а очень важный (я бы сказал даже необходимый) шаг в программировании. А если выкинуть название "проектирование", то это необходимый шаг в любой человеческой активности. Сейчас объясню на примере, почему. Представим себе, что перед нами стоит какая-то задача. Что мы должны сделать перед тем, как начать ее выполнять? По идее, сначала мы должны понять что нам нужно сделать. Вторым шагом нужно разобраться, как мы будем это делать. И только потом - уже собственно делать! Так и в создании ПО. Сначала мы пытаемся понять, что нужно сделать (анализируем требования, или иногда даже анализируем желания клиента и создаем требования по ним). Затем мы пытаемся разобраться как мы будем это делать (по сути, проектируем, как будет выглядеть результат, чтобы не переделывать десять раз). И только потом берем клавиатуру в зубы и идем программировать. Однако здесь важно понимать одну очень важную деталь: результат проектирования (проект) не обязательно должен быть вырезан в камне диаграммах UML и документах, а вполне может быть сделан на доске, куске бумажки или даже просто в голове, если этого достаточно. Так что отсутствие конкретной формальной фазы еще не значит, что программисты не занимаются проектированием какого-то куска кода, базы данных, UI прототипов или даже микро-архитектуры. Занимаются. Это и есть проектирование, просто менее формальное.

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

Технический долг

С вопросом важности проектирования тесно связана концепция технического долга или задолженности (Technical debt). Технический долг - это очень хорошая метафора, иллюстрирующая то, что быстрая и бездумная разработка кода приводит к появлению т.н. технического долга, похожего на финансовый долг, когда мы берем кредит. Как и финансовый, технический долг (кредит) имеет свои проценты, которые накапливаются с течением времени, и которые мы постоянно вынуждены выплачивать при добавлении новой функциональности, если мы не хотим выплачивать тело этого кредита. Со временем проценты становятся настолько велики, что мы вынуждены остановить добавление функционала и выплатить часть тела нашего кредита - зарефакторить быстрый и кривой дизайн приложения и сделать его более качественным. Несмотря на то, что этот процесс занимает время, таким образом мы уменьшаем будущие проценты.

Также эта метафора объясняет, почему иногда приходится писать код быстро, не тратя времени на правильное проектирование. Как и с точки зрения финансов мы берем деньги в кредит/долг для более быстрого достижения поставленной цели, здесь мы это также делаем для более быстрого получения результата. Однако мораль сей басни такова, что не нужно забывать, что за подобные действия мы будем расплачиваться в дальнейшем.
Более подробно о техническом долге можно почитать у
Фаулера и Jeff Atwood.

Рецепты правильного проектирования

Хорошо, теперь мы знаем, что есть свойства хорошего кода (ценности), и что проектирование может нам помочь достичь их. Но как это сделать? Какие есть рецепты?

Индустрия создания программного обеспечения очень молода. Создание ПО часто сравнивают со строительством, архитектурой, мол, там все четко и понятно - есть требования к зданию, по ним делается дизайн, проект, потом этот проект просчитывается, конструируется, подбираются материалы, все планируется и лишь только затем начинается постройка. Кроме того, на данный момент существует уже куча стандартных подходов для строительства различных типичных зданий, существуют различные инженерные решения, позволяющий построить как гигантский небоскреб, так и тоннель под Ла-Маншем или какой-нибудь супер-мост. Однако, почти все забывают одно существенное различие: архитектуре уже как минимум 10,000 лет и человечество накопило очень много знаний и опыта за это время, а вот индустрии создания ПО - меньше века. И если в сфере языков программирования и технологий наша индустрия проделала очень внушительный путь, то по проектированию накопленных знаний не так и много. Многие подходы еще только нарабатываются и внедряются, поэтому и готовых рецептов-то не так уж и много.

Из того, что связано непосредственно с проектированием, можно назвать паттерны и принципы проектирования.

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

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

Мне кажется, что ценности, принципы и паттерны можно выразить следующей иерархией (с удовольствием жду комментариев по ее улучшению):
image

На вершине пирамидки располаются наши ценности (свойства), которых мы хотим достичь. Чуть ниже располагаются принципы - в какой-то степени они описывают правила, используя которые мы можем достичь наших ценностей. Еще ниже - паттерны, как более низкоуровневые рецепты. И в самом низу - обыкновенный код.

Однако данная пирамидка совсем не обозначает, что нельзя достичь вершины, не зная те же паттерны или принципы. Очень даже можно, вот только не факт, что в полученном результате их не будет :) Да и зачем изобретать велосипед, если можно использовать наработки таких умных и известных инженеров, как Бек, Гамма, Фаулер, Лисков, и множество других. Понимание и разумное использование принципов и паттернов помогает достигнуть вершины быстрее и с меньшими трудозатратами.

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

Sunday, April 12, 2009

Список интересных подкастов: выпуск #1

Недавно прослушал несколько интересных подкастов. Хотел бы поделиться некоторыми наиболее интересными на мой взгляд:

Carl, Richard и Ward Bell обсуждают вопросы использования ORM в целом и Entity Framework в частности. Послушав этот подкаст, вы узнаете какие проблемы есть у Entity Framework v1.0 (дизайнер, POCO, etc.), еще раз про ситуацию с LINQ to SQL и Entity Framework, о которой я уже писал, почему NHibernate, несмотря на свои функциональные преимущества, не очень популярен в широких кругах программистов, когда стоит использовать ORM, когда не стоит, а также какие есть проблемы разработки RIA приложений, в частности проблема единственности модели данных, когда и на сервере, и на клиенте приходится делать одинаковую модель, чем тут может быть полезен DevForce .NET Silverlight-разработчикам (хотя после выхода RIA Services часть проблемы с моделью вроде бы как уходит).

Гость программы, Doug Crockford рассказывает про свой профессиональный опыт, а также про создание формата данных JSON, автором которого он является (!). Также довольно много обсуждений того, почему DOM - ахиллесова пята клиентских скриптов, различных стандартов, на которых строится JavaScript, а также его будущего. Весьма познавательно.

Robert C. Martin (Uncle Bob) в гостях у Скотта рассказывает последнему, что такое Single Responsibility Principle, Open Closed Principle, Liskov Substitution Principle, Interface Segregation и Dependency Inversion Principle (SOLID). Очень детально и на примерах. Рекомендую всем, кто начинает понимать, что кроме внешнего качества продукта, есть еще его внутреннее качество - качество кода.

Просто отличный подкаст о людях, которые разрабатывают софт не только для крупных организаций, и не только за деньги. Приложение, которое вносит свою лепту в дело борьбы с раком, разработанное в Scripps Institute, в котором поучаствовало много программистов со всего мира, объединенных одной целью. WPF, Sharepoint, Scrum, и многое другое. Если вы хотите изменить мир к лучшему, то послушайте как это делают другие люди: возможно, у вас появится руководство к действию.

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

А какие подкасты нравятся вам?

Sunday, February 22, 2009

Немного о проектировании: паттерны из мира ORM

Наверняка, каждый программист слышал о паттернах (шаблонах) проектирования, читал классику, и с той или иной периодичностью использует паттерны в повседневной работе для того, чтобы сделать дизайн своего приложения более понятным и масштабируемым. Если вы когда-нибудь пробовали использовать Linq to SQL, Entity Framework, NHibernate или другие ORM, то вы, конечно же, заметили, что у них есть много общего. L2S и EF с некоторого расстояния вообще выглядят, как близнецы-братья, да и остальные ORM тоже недалеко ушли. Вы думаете, это совпадение? Вовсе нет. Просто все они строятся с использованием одних и тех же паттернов проектирования.

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

Начнем с того, что каждый ORM имеет в своем составе некий "менеджер" (например, контекст в L2S и EF, или сессию в NH), который является неким логическим фасадом (Facade) к базе данных. Этот фасад, как правило, "понимает" определенный маппинг объектов приложения на таблицы базы данных, "умеет" принимать на вход простые и сложные запросы на получение объектов, знает, "какие" изменения объектов и "как" сохранить в базе данных, и многое другое. Рассмотрим, какие паттерны работают внутри и рядом с ним.

Unit of Work

Unit of Work - наверно, самый популярный паттерн модификации данных. Он описывает следующую стратегию работы с данными:

  1. Получили объекты из ORM
  2. Изменили какое угодно их количество
  3. Сказали ORM сохранить данные в базу (или откатиться)
  4. ORM сохранил все изменения одним махом (или откатился)

Даже если вы никогда в жизни в глаза не видели ORM, то знакомо, не правда, ли? Конечно, именно по такому же принципу работает старая-добрая пара DataAdapter - DataSet в plain ADO.NET. И точно так же работают как контексты L2S и EF, так и сессия NH. Unit of Work работает благодаря тому, что он хранит в себе ссылки на все объекты, которые были созданы/получены через него. Именно поэтому без дополнительных телодвижений вам не удастся заставить контекст EF сохранить объект, который был изменен в рамках другого контекста, а потом приаттачен к текущему. Контекст просто не знает, какие изменения были сделаны в объекте, т.к. это не забота объекта "знать" о своих изменениях, а забота окружения, коим и является для объекта контекст/сессия.

Паттерн Unit of Work полезно использовать и в других случаях. Например, когда вам необходимо дать пользователю возможность изменить определенные данные приложения в памяти, а потом нажатием на одну кнопку сохранить их в базу данных. Или не сохранить.

Active Record

В противовес предыдущему паттерну, паттерн Active Record определяет, что объект сам знает, как себя извлечь из базы данных и сохранить изменения туда же. То есть объекту больше не нужны внешние "менеджеры", он сам в состоянии за себя постоять.

В целом, использование этого паттерна остается достаточно спорным, т.к. объект в таком случае "знает" о способе сохранения себя в базе, и поэтому крепко связан с ней, нарушая при этом Persistence Ignorance. Кроме того, если подобный объект содержит бизнес-логику, то он еще и нарушает Single Responsibility Principle. С другой стороны, у Active Record есть свои преимущества и сторонники. Из широко распространенных ORM паттерн ActiveRecord используется как минимум в Castle ActiveRecord (кто бы мог подумать :)). Да и Ruby-on-Rails, насколько я слышал, его уважает.

Identity Map

Identity Map - это паттерн, который дает возможность загрузить лишь один экземпляр объекта в память. То есть, если при первом обращении к определенному объекту ORM "поднимает" экземпляр этого объекта из базы, но все последующие запросы, которые будут приводить к получению этого объекта (даже если этот объект будет частью списка других объектов), будут всего лишь получать ссылку на уже созданный объект, а не его копию. Работает это благодаря тому, что внутри ядра ORM есть реализация этого паттерна. Контекст/сессия, перед тем, как материализовать (создать) объект с определенным Id, сначала просматривают это хранилище на предмет существования объекта, и если он не найден, регистрируют новый материализованный объект в хранилище.

Что это нам дает, как программистам. Прежде всего, если мы работаем с одним и тем же контекстом/сессией, то мы можем легко сравнивать объекты по ссылке (==). Кроме того, и что более важно, если мы уже начали изменять объект, а потом вдруг он появился в результате какой-то вспомогательной выборки, то мы можем быть уверены, что это один и тот же измененный объект (конечно, если вы напрямую не сказали при выборке, что вам необходим "чистый" объект). Ну, и напоследок, как side effect, мы получаем небольшое кеширование в рамках контекста/сессии, что позволяет уменьшить затраты на повторную материализацию объекта (весьма немаленькие). Естесственно, объекты, полученные из разных конекстов/сессий, не обладают подобными свойствами, что также необходимо понимать и учитывать.

Identity Field

Упомянув Identity Map, нельзя обойти стороной Identity Field. Этот небольшой паттерн, по сути, всего лишь говорит о том, что каждый объект содержит в себе уникальный ключ, который позволяет ORM правильно идентифицировать объекты у себя внутри. В частности, в EF такую функцию выполняет класс EntityKey, который состоит из названия сущности и значений первичного ключа.

Как вы уже догадались, Identity Field интенсивно используется для решения задач, описанных предыдущими паттернами.

Query Object

Паттерн Query Object реализует в себе запрос к данным. У Фаулера написано, что этот объект должен сам знать, как превратить себя в SQL-запрос, но очень часто паттерн рассматривается более широко, описывая прежде всего способ составления сложных запросов к ORM.

В NH есть механизм запросов Criteria, который можно отнести к реализации этого паттерна. В L2S и EF эту функцию выполняет язык запросов LINQ, который также можно назвать его реализацией (хотя и с большой натяжкой).

Lazy Load

Этот паттерн известен далеко за пределами работы с базой данных, т.к. его очень часто используют и в других областях. Lazy Load описывает объект, который может в определенный момент времени не содержать всех данных, которые нужны ему или другим объектам, но "знает", как и откуда эти данные получить. При этом после первого обращения и загрузки данных в объект, они кешируются в нем и уже следующие операции проходят быстрее.

Lazy Load в том или ином виде реализован практически во всех известных мне ORM для улучшения производительности. Ведь не всегда ваш объект Заказ должен загружать сразу и список Продуктов - они могут просто не понадобится в данной транзакции, так зачем тратить на это время и ресурсы?

Repository

Я не мог пройти мимо этого паттерна, хотя на самом деле он не реализован ни в L2S, ни в EF, ни в NH, ни в AR. (Возможно, реализован в других ORM, подскажите, если знаете.) Не мог пройти, потому что паттерн Repository очень часто используется при работе с NH (1 и 2), да и примеры для других ORM уже подоспели, например, для L2S (1 и 2).

С простой точки зрения, этот паттерн определяет фасад, который предназначен для того, чтобы быть промежуточным слоем между доменной моделью (бизнес-логикой) и источником данных. Весь код приложения за пределами репозитория работает с базой данных (или другим источником данных) через репозиторий. Однако, если смотреть на него с точки зрения пуристов DDD, то репозиторий - это уже нечто другое. Всех желающих погрузиться в нирвану DDD отправляю к следующему источнику, который достаточно неплохо описывает Repository с точки зрения DDD. Не заблудитесь только там :)

Заключение

Предлагаю пока что ограничится данными паттернами, т.к. они являются основными паттернами поведения ORM. Тех же, кто хочет узнать больше, отправляю к Фаулеру, в каталоге которого описаны еще с десяток других паттернов, связанных с другими аспектами работы Data Access в целом, и ORM в частности.

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

Sunday, February 15, 2009

Отзыв о книжках: DDD Нильссона и Scrum из окопов Книберга

Последние несколько недель были плодотворными в плане чтения книжек. Дочитал "Применение DDD и шаблонов проектирования: проблемно-ориентированное проектирование приложений с примерами на C# и .NET" Джимми Нильссона и прочитал "Scrum и XP: заметки с передовой" Хенрика Книберга. Спешу поделиться отзывами, так как уже давно ничего толкового не читал.

ddd 

Про первую книгу я уже писал относительно недавно. Рекомендую всем, кто чувствует, что ему стало тесно в рамках стандартных технологий и подходов, а архитектура и дизайн его приложений хромают на обе ноги. Domain Driven Design - это радикально другой подход к разработке ПО, поэтому книжка отлично освежает голову, дает совершенно другую перспективу и точку зрения на привычные вещи. Нильссон дает общее представление о DDD, а также на примерах показывает, как можно разрабатывать реальные приложения с использованием DDD, TDD, и различных паттернов проектирования. Автор начинает с простых вещей, вводит рабочий пример и потихоньку продвигается по пути его реализации, задевая вопросы архитектуры, модели предметной области, инфраструктуры для сохраняемости, архитектурных паттернов, unit-тестов, правил, аспектно-ориентированного программирования, пользовательского интерфейса, а также немного проходится по NHibernate. В общем и целом, после прочтения книжки в голове появляется намного более серьезное понимание всех вышеперечисленных вопросов, и даже если DDD вам не подходит, вы вынесете из книги много новых знаний. Сразу хочу предупредить, что это не Эванс, здесь нет серьезной теоретической базы, лишь практика, практика, и еще раз практика. Ну, и ложка дегтя: русский перевод этой книги просто ужасен. Не понимаю, как можно было перевести кучу названий паттернов (чего стоят только прецеденты использования и неведение сохраняемости), а также стандартных терминов (DDD - ППО, проектирование предметной области, TDD - РПТ, разработка посредством тестирования). Да и ладно бы, но там не только это перевели, поэтому постоянно приходится думать, как эта фраза звучит по-английски и что это за очередной термин такой. По всей видимости, после перевода книжку не проверил эксперт в данной предметной области. Поэтому читайте оригинал :)

scrum

Вторая книжка была переведена сообществом Agile Ukraine, за что ребятам огромное человеческое спасибо! Причем, больше спасибо за то, что они разрекламировали ее, потому что в реальности, как и предыдущая книга, эта читается на английском легко и непринужденно. Книжка переведена просто замечательно, в отличие от перевода того же Нильссона. Сама же книга повествует об опыте Хенрика Книберга в постановке и использовании Scrum'а в нескольких командах. Хенрик последовательно проходится по вопросам планирования спринта, работы с product backlog'ом, ролям команды, ведения burndown-диаграммы, проведения scrum-митингов, демо, ретроспектив, а также, что более важно, объясняет, как работать по Scrum-у в условиях fixed-cost проектов, показывает родство Scrum и XP, и делится опытом постановки процесса QA и работы с несколькими командами. В общем и целом, для человека, который знаком с другими процессами разработки ПО, и который имеет не только положительный, но и отрицательный опыт, эта книга может стать хорошим стимулом попробовать поднять Scrum у себя на проекте. Тем более, если у вас ничего другого нет :) В общем, рекомендую не только PM'ам.

Sunday, January 4, 2009

Domain Driven Design: введение

Пару месяцев назад мне в руки попала книжка по Domain Driven Design (DDD). Отдельную рецензию на нее я напишу позже, когда дочитаю до конца. А пока что хотелось бы поделиться мыслями, которые у меня возникли в процессе прочтения.

Для начала я бы сказал, что DDD переворачивает взгляд на архитектуру приложения. Слабее, чем это делает MVC, но все же. Как нас учили проектировать в университетах, какие были наши первые проекты в реальной жизни, как программируют в 80-90% случаев в программистких конторах? Очень просто и прямолинейно. Есть у нас требования, анализируем предметную область (domain), находим сущности, анилизируем их поведение, действия, создаем высокоуровневую архитектуру, выбираем технологии, если нужно, строим UML-диаграммы. А дальше проектируем базу данных и от нее уже пляшем: слой доступа к данных (data access layer), слой бизнес-логики (business logic layer), слой представления (presentation layer), сервисы, etc. Т.е. снизу вверх. Все создаваемые таблицы в базе данных, как правило, мапятся на объекты предметной области как один-к-одному (с небольшими исключениями). Далее создаются сущности приложения, которые, как правило, подчиняются структуре сущностей в базе данных для удобства дальнейшей работы (опять же, могут быть исключения). Даже если мы используем какой-нибудь ORM (тот же Entity Framework или NHibernate), но генерируем сущности по базе данных, то мы все равно выходим на т.н. Data Driven Design, когда структура данных диктует нашу объектную модель. Да, это работает для решения многих задач, но не всех.

Domain Driven Design - совершенно другой зверь. Как следует из названия, это просто еще один способ проектирования, который фокусируется прежде всего на предметной области, на объектах реального мира, их поведении и взаимодействии, то есть фокусируется на модели и бизнес-логике, а не на структуре данных. Результатом подобного смещения приоритетов становится то, что мы стараемся перевести объекты предметной области и их поведение сразу в сущности приложения, пытаясь передать в них не только свойства и атрибуты этих объектов, но и поведение. Например, сущность "автомобиль" в DDD будет обладать не только атрибутами марка, цвет, цена, скорость и др., но и, по-возможности, каким-то поведением, связями с другими объектами. При этом проблема сохраняемости этих объектов куда-либо (например, в базу данных) отходит на второй план. Мы об этом не думаем, таким образом достигая сразу нескольких целей:

  1. Откладывание реализации слоя сохранения (persistence layer или data access layer) позволяет реализовать его тогда, когда доменная модель уже спроектирована и реализована, то есть когда она устаканилась. Сколько раз в начале разработки приложения вы добавляете или убираете колонки в таблицах или даже целые таблицы? Сколько при этом приходится переписывать кода слоя доступа к данным? Хорошо еще, если вы используете ORM.
  2. Слой сохранения реализуется как всего лишь один из инфраструктурных инструментов, а не как жизненно важный слой приложения. Акцент смещается на модель, а не на базу данных (или что у вас там) и слой доступа к ней. Это дает намного более сильный уровень независимости ваших классов от слоя сохранения (т.н. persistence ignorance), который дает возможность быстро поменять базу данных или перейти с нее на XML или вообще какие-нибудь внешние сервисы. По сути, это снижение связанности (decoupling).
  3. Persistence ignorance дает еще одну полезную возможность. За счет того, что ваш код может жить и без слоя сохранения, его можно намного проще протестировать. Более того, в начале разработки вообще можно забить как на слой сохранения, так и на слой представления и написать сначала модель (по сути, слой бизнес логики), которую покрыть модульными тестами. Причем тесты здесь выполняют уже не столько роль парашюта на будущее, сколько роль клиентского кода более верхнего или того же слоя, при помощи которого вы можете отточить API классов модели, а также быстро поправить дизайн классов при необходимости. Слой же сохранения в таком случае можно для начала просто закрыть мок-объектами. Если пойти дальше, то в случае необходимости можно написать даже слой представления над моделью, еще даже не начав писать слой сохранения.
  4. Из предыдущего пункта вытекает то, что если вы апологет TDD, то DDD - это точно ваше. Более подходящий для TDD способ проектирования и разработки приложений сложно себе представить.

Кроме всего прочего, Domain Driven Design стимулирует проектировать Rich Domain Model, то есть сущности, которые обладают не только состоянием, но и поведением. В результате разработки посредством Data Driven Design, мы очень часто получаем приложение, разработанное с использованием т.н. анемичной модели (Anemic Domain Model), в которой наши "бизнес" объекты на самом деле являются всего лишь сущностями для передачи данных из базы данных клиенту (UI, сервисы) и назад, т.е. обладают состоянием, но не поведением. Причем получаем мы это не потому что по-другому в Data Driven Design нельзя, а просто потому что в голове у нас это все те же записи из базы данных, просто переведенные на уровень кода. И как записи в базе данных не обладают никаким поведением, так и наши сущности, полученные оттуда, тоже сложно научить этому постфактум. Можно долго спорить о том, хороша ли анемичная модель или нет - это глупо. Просто как и у любого другого инструмента или подхода, у этого также есть свои положительные и отрицательные стороны и своя сфера применения. В приложениях, ориентированных лишь на CRUD операции, анемичная модель работает отлично. В приложениях, где много бизнес логики - уже не так хорошо. Бизнес логику приходится выносить в отдельные классы, которые будут оперировать объектами, хотя очень часто она по сути своей она принадлежит объектам.

Однако это еще не все. DDD - это не просто какая-то очередная методология разработки или догма проектирования. Скорее, это просто набор принципов, шаблонов, на которые можно опираться при проектировании. DDD очень активно оперирует ООП, паттернами, принципами (SOLID и пр.). Это вектор, направляющий разработку в несколько иное русло и помогающий решать задачи по-другому.

А что вы используете при проектировании приложений?

Дополнительно почитать о DDD можно в умных книжках:

  1. Eric Evans. Domain-Driven Design: Tackling Complexity in the Heart of Software
  2. Jimmy Nilsson. Applying Domain-Driven Design and Patterns: With Examples in C# and .NET
  3. Tim McCarthy. .NET Domain-Driven Design with C#: Problem - Design - Solution (Programmer to Programmer)

И в онлайне:

  1. http://domaindrivendesign.org/
  2. http://hinchcliffe.org/archive/2005/03/20/189.aspx
  3. http://www.emxsoftware.com/Domain+Driven+Design/
  4. http://www.infoq.com/articles/ddd-in-practice
  5. http://www.udidahan.com/2007/03/06/better-domain-driven-design-implementation/