Предотвращение волнового эффекта
Волновым эффектом модификации называется необходимость внесения изменений в модули, которые напрямую с ней не связаны. К примеру, если для проведения модификации какие-то коррективы вносятся в модуль А, то необходимость внесения изменений в модуль В обусловливается только тем, что они внесены в модуль А. Модуль В приходится модифицировать вследствие его зависимости от А. Анализ волнового эффекта имеет смысл начать с обзора возможных типов зависимостей между модулями. Таких типов всего восемь: 1. Синтаксис - данных. Для того чтобы обеспечить правильность компиляции (или исполнения) В, тип (формат) данных, производимых А и потребляемых В, должен согласовываться с типом (или форматом) данных, принятым В. - служб. Для того чтобы обеспечить правильность компиляции или исполнения В, сигнатура служб, предоставляемых А и вызываемых В, должна согласовываться с допущениями, принятыми В. 2. Семантика ♦ данных. Для того чтобы обеспечить правильность исполнения В, семантика данных, производимых А и потребляемых В, должна согласовываться с допущениями, принятыми В. - служб. Для того чтобы обеспечить правильность исполнения В, семантика служб, предоставляемых А и применяемых В, должна согласовываться с допущениями, принятыми В. 3. Последовательность - данных. Для того чтобы обеспечить правильность исполнения В, прием этим модулем данных, произведенных А, должен проводиться в установленной последовательности. К примеру, заголовок пакета данных должен приниматься раньше, чем тело пакета (в отличие от протоколов, которые встраивают порядковые номера в данные). - управления. Для того чтобы обеспечить правильность исполнения В, требуется предшествующее (в рамках определенных временных ограничений) исполнение А. Скажем, между исполнением А и исполнением В должно пройти не более 5 мс. 4. Индивидуальность интерфейса Л. У А может быть несколько интерфейсов. Для того чтобы обеспечить правильность компиляции и исполнения В, индивидуальность (имя или дескриптор) соответствующего интерфейса А должна согласовываться с допущениями, принятыми В. 5. Локализация А (в периоду прогона). Для того чтобы обеспечить правильность исполнения В, местоположение А в период прогона должно согласовываться с допущениями, принятыми В. К примеру, В может предположить, что А находится в другом процессе того же процессора. 6. Качество услуг/данных, предоставляемых А. Для того чтобы обеспечить правильность исполнения В, некое свойство, связанное с качеством предоставляемых А данных и услуг, должно согласовываться с допущениями, принятыми В. К примеру, для того чтобы алгоритмы В вычисляли правильные результаты, показания точности некоего датчика должны характеризоваться определенной степенью точности. 7. Существование А. Для того чтобы обеспечить правильность исполнения В, А должен существовать. К примеру, если В отправляет объекту А запрос на обслуживание, в то время как А не существует и его нельзя создать динамическим способом, В не сможет корректно функционировать. 8. Ресурсное поведение А. Для того чтобы обеспечить правильность исполнения В, ресурсное поведение А должно согласовываться с допущениями, принятыми В. Вариантов всего два — это либо использование ресурса (А использует ту же память, что и В), либо принадлежность ресурса (В резервирует ресурс, который принадлежит А). Обрисовав отличительные черты различных типов зависимостей, мы можем смело переходить к обзору тактик предотвращения волнового эффекта для каждого из этих типов. Следует иметь в виду, что ни одна из нижеприведенных тактик не гарантирует предотвращения волны семантических изменений. Начнем с перечисления тактик, ориентированных на интерфейсы конкретных модулей (информационная закрытость и обслуживание существующих интерфейсов), а затем поговорим о тактике, способной разрывать цепочки зависимостей, — применении посредника. ♦ Информационная закрытость. Информационной закрытостью называется декомпозиция обязанностей по отношению к сущности (системе или ее произвольной декомпозиции) на мелкие элементы и разделение информации на приватную и публичную. Публичные обязанности осуществляются через указанные интерфейсы. Задача состоит в том, чтобы изолировать изменения в рамках одного модуля и не допустить их распространения на другие модули. Это старейшая методика такого рода. Она напрямую связана с «прогнозированием ожидаемых изменений», поскольку эти изменения в ней закладываются в основу декомпозиции. ♦ Обслуживание существующих интерфейсов. Если В зависит от имени или сигнатуры интерфейса А, то за счет обслуживания этого интерфейса и его синтаксиса В остается без изменений. Результативность применения этой тактики при наличии семантической зависимости В от А гарантировать нельзя, поскольку замаскировать изменения данных и служб довольно сложно. Не менее сложно замаскировать зависимости от качества данных и услуг, использования и принадлежности ресурсов. Для стабилизации интерфейса имеет смысл отделить его от реализации. В результате появляется возможность создания абстрактных интерфейсов, маскирующих вариации. Вариации можно заключить в рамки существующих обязанностей или заменить одну реализацию модуля другой. Среди образцов, реализующих эту тактику, необходимо упомянуть следующие. - Введение новых интерфейсов. Большинство языков программирования позволяют создавать несколько интерфейсов. Новые видимые службы и данные можно открывать через новые интерфейсы — в таком случае существующие интерфейсы обходятся без изменений и сохраняют за собой старые сигнатуры. - Введение нового адаптера. При дополнении А новым адаптером он помещает А в оболочку, сохраняя для нее сигнатуру оригинала. - Введение заглушки А. Если для выполнения модификации А требуется удалить и при этом В зависит исключительно от сигнатуры А, тогда путем создания заглушки А внесение изменений в В можно предотвратить. ♦ Ограничение каналов связи. Предполагает ограничение числа модулей, совместно с которыми данный модуль пользуется данными — другими словами, сокращение тех модулей, которые потребляют данные, производимые рассматриваемым модулем, а также тех, которые производят потребляемые им данные. Поскольку зависимости производства/потребления сопряжены с волной, действия такого характера способны уменьшить волновой эффект. Образец, в котором реализована эта тактика, представлен в главе 8 («Моделирование условий полета»). ♦ Введение посредника. Если модуль В характеризуется какой-либо зависимостью от модуля А, за исключением семантической, то между ними можно поместить посредника, ответственного за выполнение действий, связанных с этой зависимостью. Существует множество посредников с разными именами, и мы намерены разобрать их в соответствии с перечисленными типами зависимостей. Как и прежде, при наличии семантических связей посредник не может гарантировать результативность. Типы посредников таковы: - Данные (синтаксис). Репозитарии (как пассивные, так и «доски объявлений») играют роль посредников между производителем и потребителем данных. Они способны проводить преобразования синтаксиса производства А в форму, применение которой допускает В. Некоторые образцы публикации/подписки (предполагающие поток данных через центральный компонент) могут проводить аналогичные операции. Образцы «модель-представление-контроллер» (Model-View-Conroller, MVC) и «представление-абстракция-управление» (Presentation- Abstraction- Control, РАС) преобразуют данные из одного формализма (устройства ввода или вывода) в другой (применяемый моделью для MVC или абстракцией для РАС). - Службы (синтаксис). Образцы «фасад», «мост», «посредник», «стратегия», «агент» и «фабрика» — все они предлагают посредничество при выполнении задачи по преобразованию синтаксиса служб из одной формы в другую. Следовательно, они все предотвращают распространение изменений из модуля А в модуль В. - Индивидуальность интерфейса А. Для маскировки изменений индивидуальности интерфейса применяется образец «брокер». Если В зависит от индивидуальности интерфейса А и эта идентичность подвергается изменениям, ее следует передать брокеру — он установит связь с новой индивидуальностью А, вследствие чего В сможет избежать модификации. - Местоположение А (в период прогона). Сервер имен позволяет изменять местоположение А без корректировки В. При этом А обязан регистрировать на сервере имен свое текущее местоположение, а В — получать с этого сервера соответствующие сведения. - Ресурсное поведение А или ресурса, управляемого А. Посредник, ответственный за распределение ресурсов, называется диспетчером ресурсов. Некоторые из них (например, диспетчеры, существующие в системах реального времени и основанные на монотонном анализе интенсивности) способны в пределах определенных рамок гарантировать выполнение любых запросов. При этом А, естественно, должен передать управление ресурсами диспетчеру. - Существование А. Образец «фабрика» при необходимости может создавать экземпляры, и именно его действиями удовлетворяется зависимость В от существования А.
|