Модульное программирование

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

Оценка программного модуля осуществляется на основании следующих конструктивных характеристик: размер модуля, прочность модуля, сцепление с другими модулями, рутинность модуля.

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

Прочность модуля - это мера его внутренних связей. Чем выше прочность модуля, тем больше связей он может спрятать от внешней по отношению к нему части программы и, следовательно, тем больший вклад в упрощение программы он может внести. Самой слабой степенью прочности обладает модуль, прочный по совпадению. Это такой модуль, между элементами которого нет осмысленных связей. Такой модуль может быть выделен, например, при обнаружении в разных местах программы повторения одной и той же последовательности операторов, которая и оформляется в отдельный модуль. Функционально прочный модуль - это модуль, выполняющий (реализующий) одну какую-либо определенную функцию. Информационно прочный модуль - это модуль, выполняющий (реализующий) несколько операций (функций) над одной и той же структурой данных (информационным объектом), которая считается неизвестной вне этого модуля. Для каждой из этих операций в таком модуле имеется свой вход со своей формой обращения к нему.

Сцепление модуля - это мера его зависимости по данным от других модулей. Характеризуется способом передачи данных. Чем слабее сцепление модуля с другими модулями, тем сильнее его независимость от других модулей. Для оценки степени сцепления используется упорядоченный набор из шести видов сцепления модулей. Худшим видом сцепления модулей является сцепление по содержимому. Таким является сцепление двух модулей, когда один из них имеет прямые ссылки на содержимое другого модуля (например, на константу, содержащуюся в другом модуле). Не рекомендуется использовать также сцепление по общей области - это такое сцепление модулей, когда несколько модулей используют одну и ту же область памяти. Единственным видом сцепления модулей, который рекомендуется для использования современной технологией программирования, является параметрическое сцепление - это случай, когда данные передаются модулю либо при обращении к нему как значения его параметров, либо как результат его обращения к другому модулю для вычисления некоторой функции. Такой вид сцепления модулей реализуется на языках программирования при использовании обращений к процедурам (функциям).

Рутинность модуля - это его независимость от предыстории обращений к нему. Модуль будем называть рутинным, если результат (эффект) обращения к нему зависит только от значений его параметров (и не зависит от предыстории обращений к нему). Модуль будем называть зависящим от предыстории, если результат (эффект) обращения к нему зависит от внутреннего состояния этого модуля, изменяемого в результате предыдущих обращений к нему.

Насколько возможно, все модули:

1) должны быть связаны друг с другом иерархическим образом, причем структура связей, по возможности, должна представлять собой дерево;

2) должны иметь небольшие размеры (не более 100 операторов языка программирования высокого уровня);

3) должны быть функционально простыми (чем меньше число получаемых модулем управляющих признаков, которые им анализируются, тем он более функционально прост);

4) должны иметь четко выраженное функциональное назначение;

5) по возможности не должны использовать общие блоки данных (глобальные переменные), т. е. должны получать входные данные в форме параметров вызова и возвращать выходные данные вызывающему модулю в явном виде.

Сложность разработки модулей для программиста состоит в отсутствии возможности использовать модули (классы, процедуры), которые еще не созданы. При этом отсутствие модулей нижележащего уровня иерархии приводит к проблеме невозможности их вызова. Отсутствие модулей вышележащего уровня иерархии, из которых должен вызываться данный модуль (с передачей ему входной информации), не позволяет вести его отладку. Таким образом, создается парадоксальная ситуация: все модули должны создаваться одновременно, что, разумеется, невозможно. В случае, если разработка ведется коллективно, ситуация еще больше усложняется.

Для решения указанной проблемы предложен метод «драйверов» и «заглушек». Суть его состоит в следующем.

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

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

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

По мере продвижения процесса разработки, заглушки и драйверы заменяются реальными модулями.