Определение связности модуля
Приведем алгоритм определения уровня связности модуля.
1. Если модуль — единичная проблемно-ориентированная функция, то уровень связности — функциональный; конец алгоритма. В противном случае перейти к пункту 2.
2. Если действия внутри модуля связаны, то перейти к пункту 3. Если действия внутри модуля никак не связаны, то перейти к пункту 6.
3. Если действия внутри модуля связаны данными, то перейти к пункту 4. Если действия внутри модуля связаны потоком управления, перейти к пункту 5.
4. Если порядок действий внутри модуля важен, то уровень связности — информационный. В противном случае уровень связности — коммуникативный. Конец алгоритма.
5. Если порядок действий внутри модуля важен, то уровень связности — процедурный. В противном случае уровень связности — временной. Конец алгоритма.
6. Если действия внутри модуля принадлежат к одной категории, то уровень связности — логический. Если действия внутри модуля не принадлежат к одной категории, то уровень связности — по совпадению. Конец алгоритма.
Возможны более сложные случаи, когда с модулем ассоциируются несколько уровней связности. В этих случаях следует применять одно из двух правил:
правило параллельной цепи. Если все действия модуля имеют несколько уровней связности, то модулю присваивают самый сильный уровень связности;
правило последовательной цепи. Если действия в модуле имеют разные уровни связности, то модулю присваивают самый слабый уровень связности.
Например, модуль может содержать некоторые действия, которые связаны процедурно, а также другие действия, связные по совпадению. В этом случае применяют правило последовательной цепи и в целом модуль считают связным по совпадению.
Сцепление модулей
Сцепление (Coupling) — мера взаимозависимости модулей поданным [58], [70], [77]. Сцепление — внешняя характеристика модуля, которую желательно уменьшать.
Количественно сцепление измеряется степенью сцепления (СЦ). Выделяют 6 типов сцепления.
1. Сцепление по данным (СЦ=1). Модуль А вызывает модуль В.
Все входные и выходные параметры вызываемого модуля — простые элементы данных (рис. 4.13).
Рис. 4.13. Сцепление поданным
2. Сцепление по образцу (СЦ=3). В качестве параметров используются структуры данных (рис. 4.14).
Рис. 4.14. Сцепление по образцу
3. Сцепление по управлению (СЦ=4). Модуль А явно управляет функционированием модуля В (с помощью флагов или переключателей), посылая ему управляющие данные (рис. 4.15).
Рис. 4.15. Сцепление по управлению
4. Сцепление по внешним ссылкам (СЦ=5). Модули А и В ссылаются на один и тот же глобальный элемент данных.
5. Сцепление по общей области (СЦ=7). Модули разделяют одну и ту же глобальную структуру данных (рис. 4.16).
6. Сцепление по содержанию (СЦ=9). Один модуль прямо ссылается на содержание другого модуля (не через его точку входа). Например, коды их команд перемежаются друг с другом (рис. 4.16).
Рис. 4.16. Сцепление по общей области и содержанию
На рис. 4.16 видим, что модули В и D сцеплены по содержанию, а модули С, Е и N сцеплены по общей области.
СЦЕНАРИЙ ТРАНЗАКЦИИ
Аннотация:
Это способ организации бизнес-логики по процедурам, каждая из которых обслуживает один запрос, инициируемый слоем представления.
Эскиз:
Проблемы:
Многие бизнес-приложения могут восприниматься как последовательности транзакций. Одна транзакция способна модифицировать данные, другая – воспринимать их в структурированном виде и т.д. Каждый акт взаимодействия клиента с сервером описывается определённым фрагментом логики. В одних случаях задача оказывается настолько же простой, как отображение части содержимого базы данных. В других могут предусматриваться многочисленные вычислительные и контрольные операции.
Сценарий транзакций организует логику вычислительного процесса преимущественно в виде единой процедуры, которая обращается к базе данных напрямую или при посредничестве кода тонкой оболочки. Каждой транзакции ставится в соответствие собственный сценарий транзакций (общие подзадачи могут быть вынесены в подчинённые процедуры).
Принцип действия:
При использовании типового решения сценарий транзакции логика предметной области распределяется по транзакциям, выполняемым в системе. Если, например, пользователю необходимо заказать номер в гостинице, соответствующая процедура должна предусматривать действия по проверке наличия подходящего номера, вычислению суммы оплаты и фиксации заказа в базе данных.
Простые случаи не требуют особых объяснений. Разумеется, как и при написании иных программ, структурировать код по модулям следует осмысленно. Это не должно вызвать затруднений, если только транзакция не оказывается слишком сложной. Одно из основных преимуществ сценария транзакций заключается в том, что не приходится беспокоиться о наличии и вариантах функционирования других параллельных транзакций. Задача – получить входную информацию, опросить базу данных, сделать выводы и сохранить результаты.
Где расположить сценарий транзакций, зависит от организации слоёв системы. Этим местом может быть страница сервера, сценарий CGI или объект распределённого сеанса. Предпочтительнее обособлять сценарии транзакцийнастолько строго, насколько это возможно. В самом крайнем случае можно размещать их в различных подпрограммах, а лучше – в классах, отличных от тех, которые относятся к слоям представления и источника данных. Помимо того, следует избегать вызовов, направленных из сценариев транзакций к коду логики представления; это облегчит тестирование сценариев транзакций и их возможную модификацию.
Существует два способа разнесения кода сценариев транзакций по классам. Наиболее общий, прямолинейный и удобный во многих ситуациях – использование одного класса для реализации нескольких сценариев транзакций. Второй, связан с разработкой собственного класса для каждого сценария транзакций: определяется тип, базовый по отношению ко всем командам, в котором предусматривается некий метод выполнения, удовлетворяющий логике сценария транзакций. Преимущества каждого подхода – возможность манипулировать экземплярами сценариев как объектами в период выполнения, хотя в системах, где бизнес-логика организована с помощьюсценариев транзакций, подобная потребность возникает сравнительно редко. Разумеется, во многих языках модель классов можно полностью игнорировать, полагаясь, скажем, только на глобальные функции. Однако вполне очевидно, что аппарат создания объектов помогает преодолевать проблемы потоков вычислений и облегчает изоляцию данных.
Термин сценарий транзакций выбран потому, что в большинстве случаев приходится иметь дело с одним сценарием для каждой транзакции уровня системы базы данных. Пусть такой исход нельзя гарантировать на все сто процентов, но в первом приближении это верно.
Назначение:
Главным достоинством типового решения сценарий транзакции является простота. Именно такой вид организации логики, эффективный с точки зрения восприятия и производительности, весьма характерен и естественен для небольших приложений.
По мере усложнения бизнес-логики становится все труднее содержать ее в хорошо структурированном виде. Одна из достойных внимания проблем связана с повторением фрагментов кода. Поскольку каждый сценарий транзакции призван обслуживать одну транзакцию, все общие порции кода неизбежно приходится воспроизводить вновь и вновь.
Проблема может быть частично решена за счет тщательного анализа кода, но наличие более сложной бизнес-логики требует применять модель предметной области (Domain Model). Последняя предлагает гораздо больше возможностей структурирования кода, повышения степени его удобочитаемости и уменьшения повторяемости.
Определить количественные критерии выбора конкретного типового решения довольно сложно, особенно если одни решения знакомы вам в большей степени, нежели другие.
МОДЕЛЬ ПРЕДМЕТНОЙ ОБЛАСТИ
Аннотация:
Это объектная модель домена, охватывающая поведение (функции) и свойства (данные).
Эскиз:
Проблемы:
В своих наихудших проявлениях бизнес-логика бывает чрезвычайно сложной, с множеством правил и условий, оговаривающих различные варианты использования и особенности поведения системы. Для облегчения именно таких трудностей и предназначены объекты. Типовое решение модель предметной области предусматривает создание сети взаимосвязанных объектов, каждый из которых представляет некую осмысленную сущность – либо такую крупную, как промышленная корпорация, либо настолько маленькую, как строка формы заказа.
Принцип действия:
Реализация модели предметной области означает пополнение приложения целым слоем объектов, описывающих различные стороны определённой области бизнеса. Одни объекты призваны имитировать элементы данных, которыми оперируют в этой области, а другие должны формализовать те или иные бизнес-правила. Функции тесно сочетаются с данными, которыми они манипулируют.
Объектно-ориентированная модель предметной области часто напоминает схему соответствующей базы данных, хотя между ними всё ещё остаётся множество различий. В модели предметной области смешиваются данные и функции, допускаются многозначные атрибуты, создаются сложные сети ассоциаций и используются связи наследования.
В сфере корпоративных программных приложений можно выделить две разновидности модели предметной области. «Простая» во многом походит на схему базы данных и содержит, как правило, по одному объекту домена в расчёте на каждую таблицу. "Сложная" модель может отличаться от структуры базы данных и содержать иерархии наследования, а так же сложные сети мелких взаимосвязных объектов. Сложная модель более адекватно представляет запутанную бизнес-логику, но труднее поддаётся отображению в реляционную схему базы данных. В простых моделях подчас достаточно применять варианты тривиального типового решения активная запись (Active Record) , в то время как в сложных без замысловатых преобразователей данных (Data Mapper) порой просто не обойтись.
Бизнес-логика обычно подвержена частым изменениям, поэтому весьма важна возможность простой модификации и тестирования этого слоя кода. Отсюда следует настоятельная необходимость снижать степень зависимостимодели предметной области от других слоёв системы. Более того, как сможете убедиться, именно это требование является основополагающим аспектом многих типовых решений, имеющих отношение к "расслоению" системы.
С моделью предметной области связано большое количество различных контекстов. Простейший вариант – однопользовательское приложение, где единый граф объектов считывается из дискового файла и располагается в оперативной памяти. Такой стиль работы присущ настольным программам, но не менее характерен для многоуровневых приложений, поскольку в них намного больше объектов. Размещение каждого объекта в памяти сопряжено с чрезмерными затратами ресурсов памяти и времени. Прелесть объектно-ориентированных систем баз данных заключается в том, они создают впечатление, будто объекты пребывают в памяти постоянно.
Без такой системы заботится о создании объектов придётся самому. Обычно в ходе выполнения сеанса в память загружается полный граф объектов, хотя речь вовсе не идёт обо всех объектах и, может быть, классах. Если, например, ведётся поиск множества контрактов, достаточно считать информацию только о таких продуктах, которые упоминаются в этих контрактах. Если же в вычислениях участвуют объекты контрактов и зачетных доходов, объекты продуктов, возможно, создавать вовсе не нужно. Точный перечень данных, загружаемых в память, определяется параметрами объектно-реляционного отображения.
Одна из типичных проблем бизнес-логики связана с чрезмерным увеличением объектов. Занимаясь конструированием интерфейсного экрана, позволяющего манипулировать заказами, вы наверняка заметите, что только некоторые функции отличаются сугубо специфическим характером и узким назначением. Возлагая на единственный класс заказа всю полноту ответственности существует риск раздуть его до непомерной величины. Чтобы избежать подобного, можно выделить общие характеристики «заказов» и сосредоточить их в одноимённом классе, а все остальные функции вынести во вспомогательные классы сценариев транзакции (Transaction Script) или даже слоя представления.
При этом, однако, возникает опасность повторения фрагментов кода. Функции, не относящиеся к категории общих, отыскать довольно трудно, и многие предпочитают этим просто не заниматься, соглашаясь с дублированием кода. Повторение часто приводит к усложнению и несогласованности, хотя возможно эффекты излишнего увеличения размеров классов наблюдаются значительно реже, чем было ожидать.
Если такое действительно происходит, результаты вполне очевидны и легко поправимы. Поэтому советуется размещать весь родственный код в пределах одного класса и заниматься его разделением по нескольким классам только тогда, когда это в самом деле целесообразно.
Назначение:
Если вопросы как, касающиеся модели предметной области, трудны потому, что предмет чересчур велик, вопрос когда сложен ввиду неопределенности ситуации. Все зависит от степени сложности поведения системы. Если вам приходится иметь дело с изощренными и часто меняющимися бизнес-правилами, включающими проверки, вычисления и ветвления, вполне вероятно, что для их описания вы предпочтете объектную модель. Если, напротив, речь идет о паре сравнений значения с нулем и нескольких операциях сложения, проще прибегнуть к сценарию транзакции (Transaction Script).
Существует еще один фактор, который нельзя обойти вниманием: насколько комфортно чувствует себя команда разработчиков, манипулируя объектами домена. Изучение способов проектирования и применения модели предметной области – урок крайне сложный, пробудивший к жизни целый информационный пласт о «смене парадигмы». Чтобы привыкнуть к модели, нужны практика и советы профессионала, но зато среди тех, кто дошел до цели, мне почти не встречались такие, кто хотел бы вновь вернуться к сценарию транзакции разве только в самых простых случаях.
При необходимости взаимодействия с базой данных в контексте модели предметной области, прежде всего я обратился бы к преобразователю данных. Это типовое решение поможет сохранить независимость бизнес-модели от схемы базы данных и обеспечить наилучшие возможности изменения их в будущем.
Встречаются ситуации, когда модель предметной области целесообразно снабдить более отчетливым интерфейсом API, и для этого можно порекомендовать типовое решение слой служб (Service Layer).
МОДУЛЬ ТАБЛИЦЫ
