Чтение онлайн

на главную - закладки

Жанры

Дефрагментация мозга. Софтостроение изнутри
Шрифт:

<! – Конфигурация слоя домена – >

<Layer name ="Domain">

<Param name ="BaseNamespace" value ="Company.Business.%PROJECT_NAME%" />

</Layer>

<! – Конфигурация слоя служб – >

<Layer name ="Services">

<Param name ="BaseNamespace" value ="Company.Business.%PROJECT_NAME%" />

</Layer>

<! – Шаблон "Реестр объектов" – >

<Pattern name ="Registry">

<Param name ="Schema" value ="Core" />

<Param name ="PersistentSchema" value ="CORE" />

<Param name ="RegistryEntity.Name" value ="EntityRegistry" />

<Param name ="TypesEntity.Name" value ="EntityType" />

<Param name ="TypesEntity.PrimaryId.Type" value ="smallint" />

<Param name ="PrimaryId.Type" value ="bigint" />

</Pattern>

<! – Шаблон "Версия состояния" для хранимых объектов – >

<Pattern name ="StateVersion">

<Param name ="Attribute.Name" value ="Version" />

<Param name ="Attribute.Type" value ="int" />

</Pattern>

<! – Шаблон "Аудит" для минимального отслеживания изменений – > <Pattern name ="Audit" />

<! – Шаблон "Локализация" – > <Pattern name ="Localization" />

<! – Шаблон "Безопасность" для веб-служб – >

<Pattern name ="Security" />

</Configuration>

В описании конфигурации джиннов видно, что его основу составляет сборка, один из классов которой, реализующий интерфейс IGenie, является точкой входа. Каждый джинн имеет как общие для всех параметры, например каталог для выходных файлов, так и специфичные, передаваемые через тег Param, описываемые в документации.

За джиннами следуют конфигурации слоёв. Если для домена и служб можно пока ограничиться спецификацией базового пространства имён, то для слоя хранения, особенно при поддержке более чем одной СУБД, необходимо указать дополнительные ограничения вроде максимальной длины имён.

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

• Например, шаблон «Реестр объектов» добавляет к системе возможность ведения централизованного реестра всех создаваемых объектов. Реализован он как соответствующий класс и таблица, ссылка на которые добавляется ко всем другим классам (некоторые классы можно исключить через параметры шаблона).

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

Шаблон «Аудит» в простейшем варианте является регистрацией для каждого хранимого объекта информации о времени его создания, последнем редактировании и авторе.

Шаблон «Локализация» добавляет в генерируемый код возможность перевода сообщений в рамках технологии GNU gettext.

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

Теперь, если запустить «заклинатель» с параметром файла конфигурации проекта и не будет обнаружено ошибок, на выходе мы получим инициализированные структуры баз данных и готовые к компиляции файлы. Рассмотрим их чуть подробнее.

Слой хранения (СУБД)

Джинны SQL Server и Oracle создадут нам в указанном каталоге подкаталоги, соответствующие целевой СУБД и её версии. В каждом подкаталоге находятся три SQL-скрипта, предназначенные, соответственно, для создания, обновления или удаления схемы БД.

Если посмотреть на созданные в СУБД структуры, то мы увидим, что из одной и той же модели логического уровня были созданы две реализации, различающиеся на физическом уровне. Например, используемые типы данных различаются. С другой стороны, необходимость поддержки слоем домена сразу двух СУБД приводит к тому, что вместо оптимального, но специфичного для SQL Server типа bit для поддержки булевых величин используется принятый в среде Oracle символьный тип.

Рис. 20. Результат работы джинна SQL Server

Рис. 21. Результат работы джинна Oracle

Слой домена (NHibernate)

Джинн NHibernate генерирует три C#-файла и один XML-файл проекции (маппинга) классов на структуры хранения.

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

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

Рис. 22. Перечисляемый тип слоя домена и его локализация

Рис. 23. Класс «Финансовый год» слоя домена

Для определяемых моделью сущностей генерируются классы, содержащие кроме соответствующих объявленным атрибутам свойств ещё и группу служебных методов для управления объектами, например, для сохранения или выборки по запросу на HQL или даже SQL. Такие методы часто используют служебные классы, объявленные в DomainSupport.cs.

Для объявленных в модели операций генерируется соответствующий метод интерфейса. Реализовать их нужно программисту в рамках расширения partial – класса.

Рис. 24. Класс «Учётный период» слоя домена

Отображение классов на структуры РСУБД соответствует стратегии «одна таблица на подкласс без дублирования атрибутов предка», достаточно хорошей в большинстве случаев, но и она может быть изменена.

Фрагмент файла проекции для класса «Финансовый год»

<!-Engine.FiscalYear->

<class name ="Domain.Engine.FiscalYear" table ="FISCAL_YEAR" schema ="MYAPP">

<id name ="Id" access ="property" column ="NIFISCAL_YEAR">

<generator class ="native">

<param name ="sequence">MYAPP.SEQ_FISCAL_YEAR</param>

</generator>

</id>

<version name ="Version" column ="VERSION" type ="int" access ="property" />

<set name ="Periods" table ="MYAPP.PERIOD" inverse ="true" lazy ="true" cascade ="none">

<key column ="NI_FISCAL_YEAR" />

<one-to-many class ="Domain.Engine.Period" />

</set>

<many-to-one name ="EntityRegistry" class ="Domain.Core.EntityRegistry" unique ="true">

<column name ="NI_ENTITY_REGISTRY" not-null ="false" />

</many-to-one>

<property name ="Name" access ="property">

<column name ="NAME" not-null ="false" />

</property>

<property name ="Granularity" access ="property">

<column name ="GRANULARITY" not-null ="true" />

</property>

<property name ="FromDate" access ="property">

<column name ="FROM_DATE" not-null ="true" />

</property>

<property name ="ToDate" access ="property">

<column name ="TO_DATE" not-null ="true" />

</property>

<property name ="Closed" access ="property" type ="YesNo">

<column name ="CLOSED" not-null ="true" />

</property>

<property name ="CreatedBy" access ="property">

<column name ="CREATED_BY" not-null ="false" />

</property>

<property name ="CreatedDate" access ="property" type ="timestamp">

<column name ="CREATED_DATE" not-null ="false" />

</property>

<property name ="LastModifiedBy" access ="property">

<column name ="LAST_MODIFIED_BY" not-null ="false" />

</property>

<property name ="LastModifiedDate" access ="property" type ="timestamp">

<column name ="LAST_MODIFIED_DATE" not-null ="false" />

</property>

</class>

Слой веб-служб и интерфейсов доступа (ServiceStack)

Генерируемые для слоя веб-служб C#-файлы предназначены для создания двух сборок: собственно служб и интерфейсов к ним, используемых клиентами.

Рис. 25. Классы, реализующие службы доступа к объектам домена

Рис. 26. Класс службы сохранения объектов

Интерфейсы доступа к службам также содержат описания перечислимых типов с локализацией, классы DTO для передачи состояния между программой-клиентом и доменом, классы для непосредственного доступа к вызовам служб.

Рис. 27. Перечисляемый тип слоя веб-служб

Рис. 28. Классы вызова специфицированных методов

Рис. 29. Классы вызова веб-служб, касающихся «финансового года»

Рис. 30. Класс адаптера для работы с объектом «Финансовый год»

Рис. 31. Класс адаптера для работы с коллекцией объектов «Финансовый год»

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

Пример работы с DTO

CurrencyDTO curr1 = new CurrencyDTO;

curr1.Code = "RUR";

curr1.Name = "Currency 1";

UnitOfWorkDTO uow = new UnitOfWorkDTO;

uow.Save(curr1);

PersistenceRequest prq1 = new PersistenceRequest;

prq1.UnitOfWork = uow;

PersistenceResponse prr1 = client.Post<PersistenceResponse>("/Persistence", prq1);

Assert.IsFalse(prr1.CommitResult.HasError, prr1.CommitResult.Message);

Пример работы с адаптерами

Currency curr1 = new Currency;

curr1.Code = "RUR";

curr1.Name = "Currency 1";

CommitResult cr1 = curr1.Save;

Assert.IsFalse(cr1.HasError, cr1.Message);

Программа-клиент

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

Извлечение списка финансовых годов, отфильтрованного по названию

FiscalYearCollection years = FiscalYearCollection.GetByQuery(

"from FiscalYear where Name like: name order by Name",

new ServicesQueryParams

AddParam("name", txtYearName.Text)

);

dgvYears.DataSource = years;

Извлечение списка учётных периодов заданного года

PeriodCollection periods = PeriodCollection.GetByQuery(

"from Period where FiscalYear.Id =:yearId order by FromDate",

new ServicesQueryParams

AddParam("yearId", CurrentYear.Id),

0, 1000);

dgvPeriods.DataSource = periods;

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

Рис. 32. Форма отображения финансовых годов и учётных периодов

Остановиться и оглянуться

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

Одним из способов обхода этой проблемы является описанная технология программной фабрики, несомненно далёкая от совершенства и ограниченная в наборе целевых платформ.

Какова же эффективность?

Если рассмотреть метрики относительно небольшого проекта, то 40 прикладных сущностей в модели, состоящей примерно из 600 строк XML-описаний, порождают:

• около 3 тысяч строк SQL-скриптов для каждой из целевых СУБД;

• порядка 10 тысяч строк домена;

• 1200 строк XML для проекций классов на реляционные структуры (таблицы);

• около 17 тысяч строк веб-служб и интерфейсов.

Популярные книги

Я – Стрела. Трилогия

Суббота Светлана
Я - Стрела
Любовные романы:
любовно-фантастические романы
эро литература
6.82
рейтинг книги
Я – Стрела. Трилогия

Камень. Книга 4

Минин Станислав
4. Камень
Фантастика:
боевая фантастика
7.77
рейтинг книги
Камень. Книга 4

Измена. Верни мне мою жизнь

Томченко Анна
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Верни мне мою жизнь

Возвышение Меркурия. Книга 2

Кронос Александр
2. Меркурий
Фантастика:
фэнтези
5.00
рейтинг книги
Возвышение Меркурия. Книга 2

Вечная Война. Книга VI

Винокуров Юрий
6. Вечная Война
Фантастика:
боевая фантастика
рпг
7.24
рейтинг книги
Вечная Война. Книга VI

Измена. Избранная для дракона

Солт Елена
Любовные романы:
любовно-фантастические романы
3.40
рейтинг книги
Измена. Избранная для дракона

Релокант. Вестник

Ascold Flow
2. Релокант в другой мир
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Релокант. Вестник

Игрок, забравшийся на вершину (цикл 7 книг)

Михалек Дмитрий Владимирович
Игрок, забравшийся на вершину
Фантастика:
фэнтези
6.10
рейтинг книги
Игрок, забравшийся на вершину (цикл 7 книг)

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Титан империи 7

Артемов Александр Александрович
7. Титан Империи
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Титан империи 7

Я – Орк. Том 5

Лисицин Евгений
5. Я — Орк
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Я – Орк. Том 5

Идеальный мир для Социопата 5

Сапфир Олег
5. Социопат
Фантастика:
боевая фантастика
рпг
5.50
рейтинг книги
Идеальный мир для Социопата 5

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Сумеречный стрелок 8

Карелин Сергей Витальевич
8. Сумеречный стрелок
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Сумеречный стрелок 8