Code Interface Driven Design

Работая над уменьшением связанности и размышляя о SOA пришел к идее построения типов путем композиции интерфейсов.

В классическом DDD нужно выделить домен – совокупность объектов и их связей. Но когда я применял этот принцип в жизни, встретился с двумя трудностями:

  1. Если есть большой домен и кучка сервисов вокруг него, то становится сложным управление доступом к членам класса. Выглядит это так: есть объект User со свойством CreatedAt, которое я хочу разрешить редактировать только сервису MembershipService. Чтож, пишем InternalsVisibleTo с указанием MembershipService. Дальше нам нужно сделать объект, например Car, у которого есть свойство PassedDistance, которое я хочу открыть только для CarService. Опять повторяем манипуляции с InternalsVisibleTo, но тут появляется проблема: теперь Membersip может изменять километраж автомобиля, а  CarService – дату регистрации пользователя.
  2. DDD всё еще не дает возможности строить приложение “по кирпичикам” – просто подключая нужные модули. Говорят, что в Ruby можно, поэтому хочется такой же легкости в .Net =). А не получается всё по той же причине – домен выделен в отдельную сборку, и, подключая сервис, приходится вручную тянуть из домена все зависимые сущности, перебирая их свойства, т.к. большинство из них в новом проекте не понадобятся. Т.е. проблему связанности сервисов DDD решает, а вот связанность домена  всё еще не решена.

Выход один – объединить сервис и его сущности в один модуль. Будут это две сборки ( домен и сервис) или одна единая сборка – не  важно. Цель – подключить всю функциональность модуля просто добавив reference к сборке, в которой выполняется композиция приложения (AppCore, например).

Сделав это, нужно как-то оставить возможность коммуникации между доменами разных модулей. Вполне вероятно, в нашем примере нужно будет реализовать свойство Car.Owner типа User, а потом House.Owner, CableTv.User и т.д. Добавить reference на Membership  – не вариант, это уже противоречит главной идее – не допускать связанности модулей.

Идеи о решении

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

Таким образом каждый модуль дополняет интерфейс IUser своими полями. Потом нужно реализовать фабрику, которая на основе перечня интерфейсов будет создавать единый тип User, который будет закэширован в AppCore.

Плюсы и минусы:

+ Каждый модуль знает только только о тех полях, которые ему нужны

+ За исключением базовых интерфейсов модули будут абсолютно независимы.

+ При добавлении нового модуля необходимые для персистенции свойства добавятся автоматически. Т.е. при добавлении модуля Sql-схема  автоматически пополнится нужными таблицами, колонками и  другими объектами.

- Идея еще не реализована =). Но для того, кто захочет реализовать этот подход, это будет плюсом – он первым воплотит её в жизнь.

Рубрика: Архитектура | Комментарии (20)

Унификация

В 1851 году принц Альберт, супруг королевы Виктории, организовал в Лондоне «Великую выставку» (Great Exhibition), которая должна была продемонстрировать всему миру технические достижения Британской империи. Миллионы посетителей бродили по фантастическому хрустальному дворцу, который был воздвигнут в Гайд-парке специально для этого мероприятия. В американском отделе толпы зевак окружали шумного, темпераментного джентльмена, который расхваливал революционную новинку – пистолет, из которого можно было выстрелить не один и не два раза подряд, а целых шесть! Но публику гораздо больше поражало не это. В те времена, когда любое изделие точной механики производилось вручную, а все детали подгонялись индивидуально, сборка работоспособного пистолета прямо на глазах публики из деталей, наугад вынимаемых из нескольких стоящих на столе коробок (детали в каждой были абсолютно взаимозаменяемы благодаря очень точной обработке на металлорежущих станках), выглядела настоящим чудом. Имя развлекавшего публику американца сейчас известно практически каждому. Это был Сэмюэл Кольт.

(с)

Благодаря этому револьверу Кольт стал одним из ивестнейших оружейных промышленников. Позже, применив этот же принцип стандартизации и взаимозаменяемости Генри Форд открыл золотой век автомобилей. Сегодня в машиностроении коэффициент унификации деталей является важным показателем эффективности конструкторского отдела.

А теперь вернемся к разработке ПО. В большинстве случаев мы не можем заменить компоненты программы без того, чтобы не начать исправлять код тех слоев, которые с ними взаимодействуют. Каждая система логирования использует собственные интерфейсы и атрибуты для описания собственного API. Тоже самое с ORM, IoC контейнерами, пакетами для разработки GUI и т.д. Т.е. во всех слоях создаваемого приложения. Единственные подвижки были сделаны в Web-сервисах с введением SOAP, REST, а теперь и OData. Также хорошим шагом было создание CommonServiceLocator - обертки над IoC-контейнерами.

Такая же проблема несовместимости была частично решена в браузерах после создания W3C. Есть хорошо описанная публичная спецификация, есть тесты, есть сообщество, которое работает над этим вопросом.

Как вы думаете, насколько полезным было бы создание такого же сообщества, направленного на описание общих интерфейсов для их нормального взаимодействия и взаимозаменяемости?

Рубрика: Без рубрики | Комментарии (9)

Архитектура

Последние три месяца отдал усиленной работе над изучением архитектур. Всё это проходило с одновременными пробами в личном проекте. 

Что уяснил:

TDD – использую в контексте FeatureDrivenDevelopment. Т.е. одна фича – один тест. Для меня слишком накладно проверять один метод на многочисленные условия условия, такие как передача null аргументов и т.д. Считаю, что такие “низкоуровневые” тесты нужно отдать системам автоматического тестирования. Pex по описанию хорош, но использовать его у меня так и не получилось.

SOLID – по-моему, просто Must Have… т.е. Must Know. Базовые принципы, которые должен знать любой middle programer.

DDD – концепция хороша. Особенно нравится тем, что проектируя домен мы можем ограничить программиста, который будет его использовать, тем самым указывая как правильно пользоваться доменной моделью, к тому же получая при этом очень красивый код.
Минус – чудовищные сложности с использованием ORM.
Из ORM-ок BLToolkit оказался наиболее удобным для использования в DDD. Но BLToolkit очень легковесная ORM. Для моих задач оказалась слишком легковесной. С кэшированием, контролем состояния, вложенными запросами нужно разбираться самому.
Есть проект по использованию EntityFramework для DDD (N-Layer App), но посмотрев на исходники сразу становится ясным, что накладные расходы на такую связку слишком высоки.
Еще одним минусом ORM в DDD является требование полностью открывать свои модели для них. Т.е. либо ORM и домен находятся в одной сборке, либо в домене нужно указывать InternalsVisibleToAttribute. Эта же проблема возникает при использовании IoC-контейнеров, которые, располагаясь в другой сборке, также требуют чтобы сущности были открыты для них.
Проект EF CodeFirst практически кричит о том, что он создан для DDD. На деле всё те же требования – полная открытость домена для изменений из вне.
DataObjects.Net в своей документации указывает, что это наиболее удобная ORM для DDD. Особенно впечатляет полная независимость от используемой БД – можно использовать MsSql, Oracle, PostgreSql и другие базы данных. ORM сама создаст для БД полную схему вашей модели. В т.ч. есть возможность использовать фейковую СУБД – хранение в оперативной памяти, что очень помогло бы для интеграционного тестирования. Минусы – публичное статичное хранение подключения к БД и паттерн ActiveRecord, на котором построена вся ORM. Что практически обязывает использовать DTO для взаимодействия с инфраструктурой.

CQRS – замечательная идея о том, как привнести реактивное программирование в императивные языки программирования. Рекомендую посмотреть на Nsqrs. На практике опробовать не успел, поэтому деталей рассказать не могу.

Выводы:

TDD использовать нужно, но умеренно и вместе с средствами автоматического тестирования.

SOLID – знать и применять.

Dipendency Injection и DDD – при использовании обязательно встретится противоречие: лучшая контролируемость кода или его открытость. Противоречие возникает просто исходя из того, что сейчас есть довольно слабые инструменты для контроля доступности объектов. Простое internal и InternalVisibleTo тут явно недостаточно.
ORM-кам нужно идти к CodeFirst. В идеале модель должна быть полностью независима от ORM, а её замена (orm) должна происходить просто заменой строчки в конфиге IoC контейнера.

Сейчас у меня основные вопросы:
1. как обеспечить динамически управляемый доступ к закрытым сущностям.
2. как авторизовывать сервисы.
3. как обеспечить адекватный IntelliSense для объектов с разным уровнем доступа.

ЗЫ
Главное не забывать что всё это нужно использовать для того, чтобы соблюдать основной принцип – keep it simple, stupid.

Рубрика: Без рубрики | Комментарии (13)

RDP

Очень привык работать по rdp.

С собой по дому переношу легкий малошумный ноутбук, а в другой комнате стоит гудящий сервер.
Причем wifi позволяет даже просматривать видео по rdp практически без тормозов.

А как приятно, когда нужно перегрузить сервер, rdp закрывается, а вместо него появляется экран ноутбука с играющим плеером и открытым браузером. Non stop.

Думаю, что такое развитие – медиа-сервер и переносные клиенты – отличное решение для организации домашнего it-парка.

Рубрика: Без рубрики | 1 комментарий

Bing Maps!

 
Рубрика: Без рубрики | 1 комментарий

Обучение по подписке

Первыми электронными рассылками были e-mail группы.
Позже появились сайты типа Subscribe.ru, которые всё так же продолжают рассылать материал на е-меил.
Я сам несколько лет был подписан на несколько рассылок subscribe, но заметил, что читать обучающий материал из почтовика меня совсем не тянет. Всё-таки почтовик – это для переписки.

Позже, на замену e-mail рассылкам пришли стандарты Rss и Atom.
Но, что удивительно, используя эти стандарты, авторы рассылок всё еще продолжают мыслить в формате e-mail уведомлений.
А именно – после публикации нового материала всем подписчикам по rss фиду приходит уведомление о появлении нового контента.

Но ведь подписчики бывают разные: часть читает рассылку с момента появления, другая часть присоединилась позже, третьи – буквально только подписались.
И что странно, нигде еще не видел, чтобы кто-то предоставлял rss-feed индивидуально и динамично.

Скажем я подписался на обучающие статьи по электронике.
Мой уровень, предположим, 3 из 10. Мне будет не инетерсно получать рассылку начиная с самого начала, но и последние статьи, которые предполагают, что весь предыдущий материал был прочитан, мне читать рано.

Было бы оптимально найти статью, начиная с которой мне было бы интересно получать rss, а затем позже, уже в ридере, читать этот материал в том темпе, в котором мне будет удобно.
Т.е. нужно подгружать фид по мере его прочтения читателем.

В итоге ридер превращается в подобие книжной полки, где в любой момент можно открыть интересный раздел (папку) или книгу (rss feed) и продолжить чтение с того момента, на котором я остановился в прошлый раз.

Это было бы действительно очень удобно.

Рубрика: Без рубрики | Оставить комментарий

Интересно говорит =)

Рубрика: Без рубрики | Оставить комментарий