Прочность модулей

 

Прочность модуля – это мера его внутренних связей. Чтобы опреде­лить прочность модуля, необходимо проанализировать выполняемую им функцию (или функции), с тем, чтобы решить, к какому из семи классов он относится. Классы эти специально определены для того, чтобы ввести ко­личественную характеристику «доброкачественности» конкретных типов модулей.

В первую очередь необходимо определить, что понима­ется под функцией модуля. Модуль имеет три основных атрибута: он вы­полняет одну или несколько функций, обладает некоторой логикой и ис­пользуется в одном или нескольких контекстах. Функция – это внешнее описание мо­дуля; описывается, что делает модуль, когда он вызван, но не как это дела­ется. Логика описывает внутренний алгоритм модуля, другими словами, как он выполняет свою функцию. Контекст описывает конкрет­ное приме­нение модуля. Например, модуль с функцией «удалить пробелы из литер­ной строки» может использоваться в контексте «сжать сообщение для те­леобработки». Чтобы увидеть разницу между функцией и логикой, рас­смотрим модуль, функция которого – зашифровать введенную инфор­ма­цию по заданному ключу. Он может быть головным модулем 15-мо­дуль­ной программы либо единственным модулем программы. В обоих случаях функция этих двух модулей одинакова, но логика – совершенно разная. Мы видим, что функция модуля может рассматриваться как компо­зиция его логики и функций всех подчиненных (вызываемых им) модулей. Это определение рекурсивно и применимо к любому модулю в иерархии.

Цель проектирования – так определить модули, чтобы каждый из них выполнял одну функцию (говорят, что такие модули обладают функ­циональной прочностью). Чтобы понять важность этой цели, ниже рас­смотрим семь классов прочности модулей [11], начиная с самого слабого типа прочности.

Модуль, прочный по совпадению, – модуль, между элементами кото­рого нет осмысленных связей. Трудно привести пример такого модуля, по­скольку он не выполняет никаких разумных функций. Описание логики – единственный возможный способ описания модулей этого типа. Одна из причин, по которым такие модули могут возникнуть, – это «модуляриза­ция» программы post factum, когда мы обнаруживаем одинаковые после­довательности команд в нескольких модулях и решаем сгруппировать их в отдельный модуль. Если эти последовательности (хотя они и кажутся идентичными) имеют разный смысл в тех модулях, в которые они перво­начально входили, то наш новый модуль является прочным по совпаде­нию. Модуль этого типа тесно связан с вызывающими его модулями, по­этому почти любая его модификация в интересах одного из этих модулей приводит к тому, что для всех остальных он станет работать неправильно.

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

Модуль, прочный по классу, последовательно выполняет набор свя­занных с ним функций. Самые распространенные примеры – «начальный» и «заключительный» модули. Главная проблема с модулями этого типа со­стоит в том, что обычно они неявно связаны с другими модулями про­граммы, что делает программу трудной для понимания и ведет к ошибкам, когда ее приходится изменять.

Процедурно прочный модуль последовательно выполняет набор тех связанных с ним функций, которые непосредственно относятся к проце­дуре решения задачи. Вот пример задачи для подсистемы «интеллектуаль­ный дом»: написать программу регулирования температуры простого па­рового котла. В определенной степени подобная задача может определять действия программы. Например, в постановке задачи может быть сказано, что при получении сигнала х следует закрыть клапан у и прочитать и заре­гистрировать значение температуры. Модуль с функцией «закрыть клапан у, прочитать значение температуры парового котла и занести его в жур­нал» обладает процедурной прочностью. В этом случае единственная про­блема, связанная с надежностью, состоит в том, что фрагменты про­граммы, относящиеся к различным функциям, могут быть переплетены. Отметим, что для модулей этого типа, так же как и для большинства дру­гих типов, имеются и другие, не связанные с надежностью проблемы, как показано в [11].

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

Функционально прочный модуль – это модуль, выполняющий одну определенную функцию, такую как «посчитать вероятность правильной передачи сообщения», «закрыть клапан у» или «подвести итог по расходу горячей воды за месяц». Функциональная прочность – это высшая (луч­шая) форма прочности модуля.

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

Оставшийся тип прочности – информационная прочность. Инфор­мационно прочный модуль выполняет несколько функций, причем все они работают с одной и той же структурой данных и каждая представляется собственным входом. Модуль с двумя входами, один из которых соответ­ствует функции «включить элемент в базу данных», а другой – функции «искать в базе данных», обладает информационной прочностью. Модуль этого типа может также рассматриваться как физическое объединение не­скольких функционально прочных модулей с целью «упрятывания инфор­мации» [12], например, для того, чтобы укрыть внутри одного модуля все сведения о конкретной структуре данных, ресурсах или устройстве. В упо­мянутом выше примере вся информация о структуре и расположении таб­лицы символов скрыта внутри одного модуля. Это имеет то преимущество, что всякий раз, когда удается скрыть некоторый аспект программы внутри одного модуля, независимость ее модулей увеличивается. Упоминавшуюся ранее цель проектирования нужно теперь подправить, чтобы наряду с функционально прочными модулями стремиться к информационно проч­ным.

Хотя выше мы сконцентрировали внимание только на связи между прочностью модуля и защищенностью от ошибок, прочность модуля влияет также на адаптируемость программы, трудность тестирования от­дельных модулей и степень применимости модуля в других контекстах и других программах [11]. Шкала прочности упорядочена с учетом всех этих атрибутов.

Отметим, что модуль может соответствовать описанию нескольких типов прочности. Например, коммуникационно прочный модуль удовле­творяет также определению процедурной прочности и прочности по классу. Будем всегда относить модуль к высшему типу прочности, опреде­лению которого он удовлетворяет.