Программная инженерия. Часть 3.

Модульное программирование. Концепция модульного программирования, выдвинутая еще в середине 50-х годов (ассемблеры, ФОРТРАН), подверглась сильным изменениям в 70-е годы. Первоначально ставилась задача выделения относительно независимых фрагментов программ с целью организации разделения работ, повторного использования ПО, уменьшения затрат на повторную компиляцию и преодоления ограничений на размеры компилируемых программ. Связь модульности с независимой компиляцией привела к разделению всех объектов программы на множество внешних объектов, используемых для межмодульных связей, и множества внутренних объектов каждого модуля с распределением по этим множествам общей сложности программы.

Межмодульные связи гораздо сложнее внутримодульных (модули реализуют понятия весьма высокого уровня), но почти не поддерживаются инструментальными средствами. Поэтому при оптимальном по общей сложности программы разбиении на модули количество внешних объектов должно быть значительно меньше среднего количества внутренних объектов в каждом модуле. Без дополнительной структуризации множества внешних объектов для больших программ абсолютно нереально ограничивать модули, например, размером в 100 строк исходного текста. На практике типичный размер модуля составлял около тысячи строк, несмотря на использование административных методов структуризации внешних объектов по крупным компонентам. Ситуация осложнялась отсутствием дисциплины деления объектов на внешние и внутренние, из-за чего любое изменение модуля могло потребовать коррекции других модулей, а также невозможностью отладки межмодульных связей параллельно с разработкой модулей.

Современная концепция модульного программирования включает в себя следующие положения:

  • программа разбивается на модули, занимающие как правило (но не обязательно), одну- две страницы распечатки. Модули могут определять доступные для использования данные, операции обработки данных (подпрограммы, сопрограммы и т.д.), общие схемы структур данных и операций их обработки, а также структуры из перечисленных объектов;
  • каждый модуль состоит из спецификаций и тела. Спецификации определяют правила использования модуля, т. е. набор предоставляемых им услуг, а тело определяет способ их реализации. Не противоречащее спецификациям изменение тела не должно требовать модификации (более сильный вариант — перетрансляции) других модулей, использующих данный. Определенные в теле понятия недоступны за пределами модуля (принцип скрытия информации);
  • должны иметься средства управления видимостью имен, обеспечивающие построение многоуровневых структур модулей и ограничивающие множества доступных в каждом модуле внешних объектов так, чтобы сложность программы по возможности линейно зависела от ее размеров (на практике это означает, что структуры должны быть похожи на древовидные);
  • средства инструментальной поддержки должны обеспечивать возможность компиляции модулей до разработки тел используемых ими модулей, осуществлять проверку соответствия тел и спецификаций модулей, соответствия способов использования модулей описанным в спецификациях правилам, а также проверку выполнения ограничений, связанных со структуризацией модулей.

Перечисленные положения не исчерпывают всех желательных свойств модулей и средств поддержки. Например, было бы полезно допустить для модулей несколько вариантов тела с соответствующими средствами компоновки версий ПО. Но и без этого приведенная формулировка намеренно выходит за рамки всех имеющихся реализаций, что позволяет оценивать не только их достоинства, но и недостатки. Например, на практике либо не обеспечивается полнота спецификаций, либо не гарантируется соответствие спецификаций модулей их телам и способам использования. Не все благополучно и со структуризацией внешних объектов — для решения проблемы недостаточно простых списков импорта и экспорта объектов. Должно быть, такое, групповое управление видимостью имен, может как в языке АДА. Ведь модули аналогичны операциям специализированного языка, а если в обычной программе, например, вместо блочного управления видимостью имен перед каждым оператором поставить списки импортируемых и экспортируемых переменных, то ее сложность от этого только увеличится.