Назад Оглавление Вперед
На головную страницу М.М.Горбунов-Посадов
 
РАСШИРЯЕМЫЕ ПРОГРАММЫ
 

 Г л а в а  2
МОДУЛЯРИЗАЦИЯ
 
2.2. Вторичные объекты программного фонда
 

 

2.2. Вторичные объекты программного фонда

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

      2.2.1. Объектный модуль. Рассмотрим, например, некоторые характерные манипуляции с объектными модулями. Пусть, скажем, разработчик программы решил отредактировать или уничтожить некоторый первичный текстовый объект, в результате трансляции которого ранее был порожден объектный модуль. Сразу же вслед за редактированием или уничтожением он обязан позаботиться об удалении из программного фонда данного объектного модуля. Если этого не сделать, неизбежны неприятности. В лучшем случае неудаленные объектные модули будут просто засорять внешнюю память, а в худшем — в очередную строящуюся выполняемую программу будет включен объектный код, не соответствующий новому состоянию исходного текста.
      Уничтожение утратившего силу объектного модуля можно автоматизировать, избавив разработчика от столь скучных хлопот. В равной мере поддаются автоматизации и все остальные рутинные манипуляции с объектными модулями, по сей день нередко выполняемые разработчиком вручную. Такая автоматизация позволила бы вытеснить непосредственные обращения к объектным модулям из повседневного обихода, сохранив их лишь для немногочисленных любителей всевозможных системных изысков.
      Почему же до сих пор во многих операционных средах объектные модули не «спрятаны» от программиста? Несообразность сложившегося положения настолько очевидна, что ее трудно отнести лишь на счет заурядного недосмотра разработчиков операционной среды.
      Истинная причина кроется, по-видимому, в отсутствии или слабости существующих средств задания конфигураций программ. Ведь объектный модуль является производным от целого ряда первичных объектов. Различные сочетания первичных объектов порождают различные объектные модули. Поэтому, отказываясь от явного манипулирования объектными модулями, на смену ему необходимо предусмотреть средства строгого задания всей совокупности первичных объектов, служащих исходным материалом для строящейся программы.
      Среди таких первичных объектов центральное место занимает исходный текст на алгоритмическом языке. Если бы можно было установить в операционной среде жесткое взаимно однозначное соответствие «исходный текст — объектный модуль», то задача исключения рутинных манипуляций с объектными модулями решалась бы сравнительно легко. Столь прямолинейное решение на самом деле встречается время от времени в отдельных разработках.
      В частности, к нему нередко прибегают в проектах реализации развитых одноязыковых сред, включающих, помимо компилятора, языково-ориентированные редактор и отладчик. В такой среде программист чувствует себя чрезвычайно вольготно до тех пор, пока ему не требуется состыковывать накопленные там материалы с программами, написанными на других языках или для других трансляторов, а также пока не требуется поддерживать одновременно несколько версий своей программы. Как только возникает потребность в применении других трансляторов или в многоверсионности, сразу же начинают проявляться слабые стороны жесткой фиксации соответствия «исходный текст — объектный модуль», из-за которых данному решению не суждено, по-видимому, дождаться массового признания.
      Дело в том, что в порождении объектного модуля, помимо исходного текста, участвуют транслятор, а также, возможно, текстовые вставки, макробиблиотеки, вариантные фрагменты и т. д. Если жестко зафиксирована связь «исходный текст — объектный модуль», то к исходному тексту придется жестко привязать конкретную комбинацию упомянутых первичных объектов.
      Даже привязка к исходному тексту определенного транслятора вызывает серьезные возражения. И уж вовсе лишена смысла жесткая привязка одного из вариантных фрагментов. В то же время, как видно из разобранных в гл. 1 примеров, потребность в использовании вариантных фрагментов возникает довольно часто. Все это не позволяет применять жесткую фиксацию связи «исходный текст — объектный модуль» в операционной среде общего назначения.
      Итак, объектный модуль надлежит связать не с одним, а с группой первичных объектов. Каждый из этих объектов вносит определенную лепту в процесс окончательного формирования и трансляции исходного текста. Изменение любого из них, вообще говоря, должно повлечь за собой удаление порожденного ранее объектного модуля.
      Разумеется, в любой операционной среде все необходимые для порождения объектного модуля первичные объекты должны быть так или иначе указаны программистом. Однако такие указания зачастую не собраны воедино, а задаются с привлечением нескольких совершенно разнородных средств. Именно отсутствие компактного единообразного описания исходного материала трансляции не позволяет четко зафиксировать связь между объектным модулем и породившими его первичными объектами.
      Связь здесь устанавливается неявно и лишь на время выполнения трансляции, вслед за чем и первичные объекты, и объектный модуль начинают жить самостоятельной, не зависящей друг от друга жизнью. Но, не располагая постоянной связью, нельзя автоматизировать учет последствий изменений первичных объектов, т. е. при такой организации среды нельзя скрыть от пользователя объектный модуль.
      Напротив, если операционная среда позволяет компактно записать и оформить в виде самостоятельного первичного объекта всю информацию о первичных объектах, относящуюся к порождению объектного модуля, то необходимые связи не исчезают при завершении трансляции, а становятся постоянными и легко доступными. Тем самым появляется возможность избавить программиста от непосредственных манипуляций с объектными модулями.

      2.2.2. Загрузочный модуль. Проблемы, возникающие при порождении загрузочного модуля (выполняемой программы, exe-файла), во многом напоминают рассмотренные выше проблемы объектных модулей. Однако здесь завязываются более сложные связи между первичными и вторичными объектами и требуются несколько более мощные средства описания конфигурации программы. Поэтому, несмотря на некоторые неизбежные повторы, в особенностях использования загрузочных модулей следует разобраться поподробнее.
      Схема получения загрузочного модуля обычно имеет следующий вид. На вход специальной штатной программы операционной среды — компоновщика — подается совокупность объектных модулей (и, возможно, библиотек объектных модулей). На выходе компоновщика мы имеем искомый загрузочный модуль. Таким образом, компоновщик оперирует исключительно вторичными объектами.
      Но компоновка является лишь заключительной фазой серии манипуляций над первичными объектами. Как было показано в предыдущем разделе, за каждым объектным модулем стоит совокупность первичных объектов (исходных текстов, макробиблиотек и т. д.), послуживших исходным материалом для его порождения. Поэтому, если заглянуть чуть глубже, становятся видны первичные объекты компоновки: наверху — описание состава включаемых объектных модулей, а внизу — первичные материалы, породившие эти объектные модули. Совокупность первичных материалов, так или иначе участвующих в порождении загрузочного модуля, будем называть версией или, точнее, конкретной конфигурацией программы.
      К сожалению, в некоторых из ныне существующих операционных сред конкретная конфигурация программы присутствует лишь неявно. Дело в том, что часто единственным конструктивным объектом программного фонда, представляющим конкретную конфигурацию, является порожденный ею вторичный объект — загрузочный модуль. Другими словами, тут также как и в случае с объектным модулем обрывается связь между первичным материалом и порожденным на его основе вторичным объектом, что влечет за собой множество неприятностей.
      Так, затрудняется, а нередко и становится невозможным анализ первичного материала, включенного в конкретную конфигурацию. При отсутствии связей с первичными объектами загрузочный модуль представляет собой «вещь в себе», в программном фонде не хранится практически никакой информации о его происхождении. В результате по прошествии некоторого времени разработчик забудет и не сможет выяснить не только какие-либо алгоритмические детали, но и для чего вообще была сформирована породившая данный загрузочный модуль конкретная конфигурация программы.
      Если потребуется видоизменить структуру или состав сформированной ранее конкретной конфигурации, то всю работу по порождению загрузочного модуля придется начинать заново. Многократное повторение этой работы особенно болезненно воспринимается в случае, когда нужно провести серию расчетов для ряда слегка различающихся версий программы.
      Наконец, исчезновение связи между загрузочным модулем и породившими его первичными объектами не позволяет автоматизировать исключение из программного фонда загрузочного модуля при изменении первичных объектов. Так же, как и в рассмотренной выше ситуации с объектными модулями, это может привести не только к засорению фонда отслужившими загрузочными модулями, но и к рассогласованию между исходными текстами программ и производным от них объектным кодом загрузочного модуля.
      Причина перечисленных трудностей — в отсутствии конструктивного первичного объекта, описывающего конкретную конфигурацию. Как только появляется объект-описание конфигурации, положение решительно изменяется к лучшему. Описание хранится в программном фонде и может содержать, в частности, перечень имен первичных объектов, составляющих конкретную конфигурацию программы. Оттолкнувшись от такого перечня, можно уже не только эффективно решить упомянутые выше проблемы, но и организовать, например, автоматическое обновление загрузочного модуля при внесении изменений в тексты содержащихся в перечне объектов.
      Эффективное решение ряда технических проблем — не единственное преимущество появления объекта-описания конфигурации. Он заполняет пустующую нишу в лексиконе разработчика. Термины «описание конкретной конфигурации» и «загрузочный модуль» теперь сосуществуют, позволяя точнее формулировать многие задачи проектирования и сопровождения программы.
      Разумеется, перечень составляющих первичных объектов — далеко не единственная форма первичного описания конкретной конфигурации. Например, в описание могут также включаться различные формы уточнения вариантов, разбиравшиеся в предыдущей главе. Можно задать конкретную конфигурацию и принципиально иначе, сформулировав лишь стоящую перед программой цель и доверив специальному планировщику автоматический подбор необходимого для достижения этой цели программного материала.
      В любом случае наличие первичного конструктивного объекта — конкретной конфигурации программы — независимо от формы его задания позволяет и разработчику, и обслуживающим программам разобраться во всех нюансах включенного в этот объект программного материала. Так, если конкретная конфигурация задана перечнем имен составляющих, то программный материал доступен непосредственно. Если же конкретная конфигурация задана в форме цели, стоящей перед программой, то для изучения материала понадобится помощь планировщика.
      «Первичность» конструктивного объекта не следует понимать слишком буквально. Например, пусть к некоторой конкретной конфигурации программы удалось прийти только после значительного числа проб и ошибок, отраженных в длинном путаном диалоге с операционной средой. Вообще говоря, полный протокол этого диалога может претендовать на роль первичного объекта, определяющего конфигурацию. Но лучше все же считать, что диалог послужил лишь инструментом для формирования другого конструктивного первичного объекта — компактного описания конкретной конфигурации, которое существенно удобнее с точки зрения последующего использования.

      2.2.3. Библиотека объектных модулей. Помимо объектных и загрузочных модулей, существует еще один часто встречающийся вторичный объект программного фонда, заслуживающий внимания с точки зрения модуляризации. Это — библиотека объектных модулей. Подобно объектному или загрузочному модулю, библиотека отражает некоторое подмножество первичного материала, которое в современных операционных средах, к сожалению, не всегда имеет единое первичное конструктивное воплощение.
      Построение такого первичного объекта для библиотеки также весьма желательно. На его основе можно анализировать состав библиотеки, автоматически поддерживать соответствие между исходными текстами и включенными в библиотеку объектными модулями и т. д.
      Оформить конструктивный первичный объект можно, как и для загрузочного модуля, с помощью перечисления, т. е. в виде перечня имен исходных текстов, трансляция которых порождает объектные модули, составляющие библиотеку. Нередко более удобным оказывается ассоциативный механизм, когда сведения о составе библиотеки не собираются явно воедино, а как бы рассыпаются по составляющим исходным текстам, принимая вид соответствующего атрибута, указывающего на причастность того или иного текста к библиотеке. С точки зрения последующего использования ассоциативный механизм не сильно разнится с перечислительным, так как надлежащие службы программного фонда легко могут собрать и предъявить разработчику или обслуживающим программам перечень первичных объектов, снабженных указанным атрибутом.
      Однако с точки зрения безболезненности развития программного фонда применение ассоциативного механизма для задания состава библиотеки дает некоторое новое качество. Дело в том, что при перечислительном способе подключение к библиотеке нового модуля потребует редактирования первичного объекта (перечня имен исходных текстов), поскольку к нему должно быть добавлено новое имя. Как уже не раз отмечалось, редактирование всегда чревато внесением ошибок, и таким образом перечислительный механизм тут нельзя отнести к безболезненным: ведь некорректность списка имен может сделать недееспособной всю библиотеку.
      Напротив, ассоциативное подключение к библиотеке нового модуля не требует какого-либо редактирования существующих текстов и поэтому может быть выполнено безболезненно. (Более подробно соотношение между перечислительным и ассоциативным механизмами будет разбираться позднее, в разд. 3.4.)

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

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

Далее

Рейтинг@Mail.ru