4.4. Однофакторность гнезд
Одним из наиболее существенных технологических свойств проектируемого вариантного гнезда каркаса многовариантной программы является число изменяющихся факторов, влияющих на содержимое гнезда. Весьма нежелательно появление многофакторных гнезд, которые, в отличие от однофакторных, вызывают серьезные технологические затруднения.
Однофакторность, как и многие другие свойства гнезда, закладывается на самой ранней фазе работ по обеспечению многовариантности на фазе модуляризации, или, точнее, на фазе проектирования каркаса.
4.4.1. Проектирование каркаса. Доминирующим побудительным мотивом модуляризации многовариантных программ является изменяемость (см. разд. 2.4.4). Каждый цикл вычислительного эксперимента включает в себя модификацию расчетной программы, такие модификации поглощают львиную долю времени программиста-экспериментатора, и поэтому основные усилия при модуляризации должны быть направлены на упрощение процесса выполнения изменений.
Прежде всего необходимо попытаться предвосхитить как можно больше вероятных направлений модификации расчетной программы, т. е. выявить изменяемые в ходе эксперимента факторы. Такими факторами могут оказаться, например: те или иные конструкторские решения, принимаемые при моделировании установки; различные способы отражения элементов установки в математической модели; методы, используемые при расчете; геометрия (прямоугольная, сферическая), в которой выполняется расчет; точность вычислений; организация работы с таблицами и внешней памятью и т. д.
Каждому выявленному изменяемому фактору желательно сопоставить точку роста вариантное гнездо проектируемого каркаса расчетной программы. Хорошо, когда все вариантные гнезда оформляются еще на стадии проектирования. Если же сразу сформировать постоянный каркас не удалось и некоторый полезный изменяемый фактор предложен только в ходе эксперимента, когда многие программы уже написаны, то для создания соответствующего нового гнезда каркаса можно воспользоваться техникой оформления варианта, подробно разобранной в гл. 1.
Каркас позволяет упростить и обезопасить основные технологические моменты вычислительного эксперимента: переключение с одного реализованного значения изменяемого фактора на другое осуществляется путем переназначения сменного модуля, а появление нового значения изменяемого фактора реализуется как безболезненное расширение набора сменных модулей. Проектирование такого каркаса весьма непростая задача, требующая творческого подхода. Некоторые ее аспекты уже рассматривались нами в гл. 2 при изучении проблемы более общей модуляризации программного фонда.
Каркасы многовариантных программ могут иметь самые разнообразные формы. Лучше, если выделяемые гнезда каркаса будут односвязными (см. разд. 3.6.2), но не надо пренебрегать и многосвязными гнездами нередко они оказываются ничуть не менее наглядными и технологичными.
4.4.2. Причины многофакторности гнезд. Главная опасность, подстерегающая разработчика при проектировании каркаса, появление многофакторных гнезд, т. е. гнезд, содержимое которых зависит от нескольких изменяемых в ходе эксперимента факторов. Можно указать следующие два источника многофакторности.
Во-первых, с существованием многофакторных гнезд иногда мирятся из-за соображений эффективности. Действительно, изредка удается добиться некоторого увеличения скорости выполнения расчетной программы, тесно переплетая части алгоритма, зависящие от различных факторов. Однако получаемый таким образом выигрыш в эффективности обычно настолько мал, что он никак не окупает усилий, затрачиваемых затем на борьбу с последствиями рыхлой структуры многовариантной программы.
Во-вторых, причиной появления многофакторных гнезд может послужить наличие какой-либо зависимости между некоторыми из выделенных изменяющихся факторов. В этом случае два или более связанных значений зависимых факторов будут образовывать устойчивые сочетания, каждому из которых, по-видимому, надо сопоставить сменный модуль одного совокупного многофакторного гнезда.
Для того чтобы избавиться от многофакторных гнезд, отражающих устойчивые сочетания значений, приходится анализировать и корректировать понятийный базис решаемой задачи, добиваясь первичности и независимости выделяемых изменяющихся факторов и обеспечивая тем самым базисность и ортогональность (см. разд. 2.4.4) реализующих эти факторы модулей. Подобный анализ задачи, помимо очевидной технологической пользы, часто оказывается весьма плодотворным, позволяя выявить глубинные свойства исследуемой проблемы.
4.4.3. Технологические трудности. Указанные выше объективные причины многофакторности на практике встречаются нечасто. В подавляющем большинстве случаев многофакторные гнезда возникают просто вследствие грубых ошибок проектирования, и при известном навыке изгнание их из каркаса не составляет особого труда. Если все же избежать появления таких гнезд не удалось, то разработчик сталкивается с множеством технологических трудностей.
Прежде всего, программирование для многофакторных гнезд сопряжено с излишними трудозатратами. Поясним это простыми арифметическими выкладками. Пусть некоторое вариантное гнездо заполняется сменными модулями, зависящими от двух изменяющихся факторов, каждый из которых в ходе вычислительного эксперимента принимает 10 различных значений. Тогда для реализации всех возможных комбинаций этих факторов потребуется 10 x 10 = 100 сменных модулей. В то же время, если бы удалось расчленить эти факторы, заведя для каждого отдельное гнездо, то потребовалось бы всего 10 + 10 = 20 сменных модулей. При этом размер однофакторного модуля будет, грубо говоря, вдвое меньше размера двухфакторного, поскольку задачи, решаемые двухфакторным модулем, поделятся между двумя однофакторными. Таким образом, однофакторная схема оказывается здесь в десять раз экономичнее, чем двухфакторная!
Однако дело даже не в количестве и не в размерах модулей, хотя и они достаточно убедительно свидетельствуют в пользу однофакторных гнезд. Беда в том, что многофакторный модуль имеет размытую структуру. Изучая его текст, трудно распознать, где начинаются и заканчиваются фрагменты, реализующие отдельные охватываемые им факторы.
Кроме того, использование многофакторных модулей неизбежно ведет к дублированию текстов, негативные последствия которого подробно разбирались в разд. 1.3. Ведь различные значения изменяемых факторов комбинируются в эксперименте в самых разнообразных сочетаниях, в результате чего регулярно появляются модули с совпадающими значениями некоторых факторов. При единообразной реализации тексты таких модулей будут содержать сходные фрагменты. Но это сходство, а нередко и идентичность текстов никак не будут проявлены, что, разумеется, технологически неприемлемо.
Многофакторные гнезда сильно проигрывают однофакторным в отношении простоты и наглядности описания конкретной конфигурации программы. Сменный модуль для однофакторного гнезда имеет лишь один сборочный атрибут значение фактора. Назначение модуля на роль заполнителя гнезда в собираемой расчетной программе производится посредством довольно простой конструкции
имя_гнезда < имя_сменного_модуля | (1) |
Если же назвать гнездо именем изменяющегося фактора, а модуль именем значения фактора, то конструкция примет весьма удобочитаемый непроцедурный (см. разд. 3.6.1) вид
фактор < значение_фактора | (2) |
Ничего подобного сделать с многофакторным гнездом не удается. Можно, конечно, задать значения всех факторов, охватываемых гнездом, посредством конструкций вида (2), а затем поручить средствам системной поддержки отыскать соответствующий сменный модуль. С точки зрения непроцедурности все будет в порядке, чего нельзя, к сожалению, сказать о наглядности и компактности.
Фрагмент описания конкретной конфигурации, определяющий посредством группы значений факторов содержимое многофакторного гнезда, внешне весьма далек от таких стоящих за ним программных объектов, как вариантное гнездо и подставляемый в него сменный модуль. Иначе говоря, тут теряется наглядность построения программы, свойственная однофакторным гнездам благодаря интерпретации (1) элемента описания. Кроме того, использование целой группы значений в качестве сборочного атрибута сменного модуля выглядит существенно тяжеловеснее, чем единственное значение для однофакторного случая.
4.4.4. Атрибуты модуля в описании конфигурации. Даже когда удалось добиться однофакторности всех гнезд спроектированного каркаса, нельзя расслабиться, полагая, что все опасности уже позади. Время от времени разработчику начинает казаться, что имеющиеся в его распоряжении формы задания конкретной конфигурации собираемой программы слишком бедны. Появляется желание в некоторых случаях при назначении сменного модуля, заполняющего гнездо, указывать не имя этого модуля и не значение изменяющегося фактора (как предписывают правые части выражений (1) или (2) ), а некоторые другие атрибуты требующегося модуля.
Атрибутов у каждого модуля довольно много: дата создания, дата последнего редактирования, автор, язык программирования (транслятор) и др. Наличие большого набора атрибутов существенно облегчает ведение программного хозяйства, позволяя рассматривать имеющийся программный фонд под разными углами зрения.
Однако использование подобных атрибутов в описании конкретной конфигурации многовариантной программы вызывает решительные возражения, хотя на первый взгляд представляется вполне невинной затеей. Не всегда удается сразу разглядеть надвигающуюся многофакторность гнезд, сталкиваясь с вопросами, подобными следующему: «почему, собственно, нельзя сначала построить одну конкретную конфигурацию, выбирая из программного фонда наилучшие с точки зрения времени выполнения сменные модули, а затем, опираясь на тот же каркас и тот же программный фонд, построить другую конкретную конфигурацию, исходя из совершенно иных побуждений, например, отдавая предпочтение сменным модулям, запрограммированным, скажем, Ивановым?»
Данному вопросу можно, вообще говоря, придать совершенно корректную однофакторную интерпретацию. В программе могут быть выделены (и оформлены в виде многосвязного вариантного гнезда) части, в наибольшей степени влияющие на скорость выполнения. Затем программируются два многосвязных модуля: БЫСТРЫЙ, который записывается на ассемблере, и более медленный, но МОБИЛЬНЫЙ, записываемый на языке высокого уровня.
Кроме того, могут сосуществовать, скажем, две методики вычислений, одна из которых предложена и реализована Ивановым, а другая Петровым. В каркасе заводится вариантное гнездо МЕТОДИКА, а творения Иванова и Петрова превращаются в сменные модули с соответствующими именами (хотя для идентификации методик лучше использовать не фамилии разработчиков, а функциональные характеристики, по которым они отличаются).
Тогда чтобы получить быструю версию выполняемой программы, в описании конкретной конфигурации достаточно указать многосвязный модуль БЫСТРЫЙ, задающий включение в формируемую программу ассемблерных компонентов. Все остальные реализации вариантных гнезд, в том числе и методика вычислений, выбираются по умолчанию.
Для расчетов по методике Иванова задается только назначение
МЕТОДИКА < ИВАНОВ
в результате чего гнездо МЕТОДИКА заполняется модулем с именем ИВАНОВ, а по умолчанию выбирается БЫСТРЫЙ или МОБИЛЬНЫЙ модуль.
Но в сформулированном выше вопросе обычно подразумевается несколько иное построение программы, по существу противоречащее однофакторности гнезд каркаса. Предполагается, что все атрибуты модуля программного фонда равноправны в том смысле, что каждый из них наравне с основным сборочным атрибутом (т. е. значением изменяющегося фактора) может, вообще говоря, фигурировать в описании конкретной конфигурации.
Например, для одного и того же гнезда каркаса Сидоров мог написать на ассемблере модуль, имеющий атрибуты (БЫСТРЫЙ, СИДОРОВ), а Иванов на Фортране модуль с атрибутами (МОБИЛЬНЫЙ, ИВАНОВ). Тогда в первую запрошенную конкретную конфигурацию программы будет включен первый из модулей из-за наличия у него атрибута БЫСТРЫЙ, а во вторую второй из-за атрибута ИВАНОВ.
Закономерно возникает вопрос: а каково же все-таки предназначение заполняемого этими модулями вариантного гнезда? Неясно, служит ли оно для разрешения противоречия «быстрый мобильный» или же для того, чтобы дать возможность проявиться творческой индивидуальности Иванова и Сидорова. Такое построение размывает функциональную структуру программы, чрезвычайно затрудняя ее изучение и последующее развитие.
Единственный вид дополнительных атрибутов, включение которых в описание конкретной конфигурации иногда действительно может быть в какой-то мере оправдано, связан с отражением выполняемых время от времени реорганизаций текста модуля или программы, т. е. с такими понятиями, как «поколение» или «поставка». Об этих понятиях речь пойдет далее, в разд. 4.12.
|