Оформление варианта
Пусть на некоторой стадии создания программы удалось найти усиление для одного из входящих в нее и ранее уже отлаженных алгоритмов. Запрограммировав новый, более удачный алгоритм, обычно не спешат с окончательным уничтожением заменяемого им фрагмента программы, сознательно допуская на какое-то время сосуществование обоих фрагментов в программном фонде.
Дело в том, что при обнаружении каких-либо неполадок в новой версии программы проще всего отвести подозрения от нового участка, вернув на прежнее место старый фрагмент. Кроме того, нередко нет полной уверенности в том, что новый алгоритм по всем параметрам превосходит старый, и, следовательно, не исключается возможность отката к прежнему решению. В результате два или даже несколько вариантных алгоритмических фрагментов программы будут сосуществовать до тех пор, пока одному из решений не будет отдано безусловное предпочтение - только тогда его конкуренты окончательно ликвидируются.
Возможна ситуация, когда вариантные фрагменты присутствуют в программном фонде постоянно. Речь идет, конечно, не о старье, отслужившем свое и лишь по забывчивости не попавшем в свое время в мусорную корзину, а о сознательно сохраняемых, регулярно сменяющих друг друга в выполняемой программе равноправных вариантах. В последнем случае вариантные фрагменты представляют собой различные версии программы, отражающие, например, различные модификации модели исследуемого объекта.
Отметим, что сосуществование вариантных фрагментов в программном фонде вовсе не подразумевает их одновременного присутствия в выполняемой программе. Более того, одновременное присутствие фрагментов обычно нежелательно, а нередко и невозможно. Например, если альтернативой линейному поиску в некоторой таблице выбрано хеширование, то в выполняемой программе может работать либо один, либо другой соответствующий вариантный фрагмент, но не оба вместе. Включение обоих фрагментов не только перегружает программу, но и может привести к серьезным противоречиям, в частности из-за нестыковки описаний структур данных.
Для решения данной задачи используется механизм "Оформления варианта". Делается это следующим образом, сначала в исходном тексте программы выделяется вариантный фрагмент. Сделать это можно, например, посредством указания начального и конечного символов, но лучше, если квантами выделения будут синтаксические единицы языка программирования. Тем самым формируется вариантное гнездо, т.е. указывается место в тексте, предназначенное для подстановки одного из имеющихся вариантных фрагментов.
В момент формирования гнезда единственным претендентом на размещение в нем является только что выделенный вариантный фрагмент исходного текста. Однако теперь программист получает возможность образовать для вновь сформированного гнезда еще один вариантный фрагмент. Новый фрагмент можно объявить активным, т.е. включить в формируемую версию выполняемой программы, вытесняя из нее старый фрагмент. В то же время в программном фонде старый фрагмент сохраняется, там оба вариантных фрагмента сосуществуют на равных правах. Затем, разумеется, можно снова сделать активным старый фрагмент, или же образовать в данном гнезде еще один вариантный фрагмент и сделать активным его и т.д.
Любой из вариантных фрагментов можно уничтожить. Если у гнезда останется только один принадлежащий ему вариантный фрагмент, то можно ликвидировать и гнездо, т.е. сделать данный участок программы безвариантным. При ликвидации единственный принадлежащий гнезду вариантный фрагмент подставляется на место гнезда и полностью сливается с окружающим текстом программы.
Формальное определение вариантного гнезда в исходном тексте может задаваться предложением #VARIANT вида
#VARIANT имя_гнезда[.имя_компонента], где имя_компонента используется, если гнездо представляет собой односвязный компонент многосвязного гнезда. На место вариантного гнезда препроцессор подставляет текст ровно одного сменного модуля, назначенного этому гнезду в описании конфигурации собираемой программы.
В приведенном решении все изменения программы производятся безболезненно, не нарушая работоспособности отлаженных версий, поскольку ни на одной стадии процессов оформления и ликвидации варианта не требуется редактирование текста, существовавшего ранее. Исключается какое бы то ни было дублирование текстов программ. Наконец, вариант оформляется посредством специально предназначенных для этой цели конструкций, что позволяет легко распознать присутствие вариантности при последующем анализе программы.
Обсуждая безболезненность приведенного решения, имеет смысл рассмотреть еще одну грань данной проблемы. Пусть программа, в которой вы намереваетесь оформить вариантный фрагмент, интенсивно используется вашими коллегами для проведения важных расчетов. Тогда, обеспечивая безболезненность оформления варианта, необходимо в первую очередь позаботится о том, чтобы ваше экспериментирование не отразилось на работе соседей.
Точнее говоря, хотелось бы, чтобы все то время, которое вы посвятите отладке нового варианта, ваши коллеги могли бы не подозревать об ожидающем их сюрпризе – появлении новой модификации алгоритма – и продолжать работать со старой версией программы. Для этого достаточно слегка видоизменить предложенную выше схему, а именно считать, что старый вариантный фрагмент подставляется во вновь образованное вариантное гнездо по умолчанию. Тогда вам придется явно указывать новый вариантный фрагмент в описании конфигурации своей экспериментальной версии программы. А ваши коллеги в это время будут, как ни в чем не бывало использовать прежнее описание конфигурации, отражающее старую отлаженную версию.
Отметим, что здесь понятие безболезненности затрагивает уже не только тексты программ, но и описание конфигурации. Такое обобщение следует признать совершенно естественным. Ведь для ваших коллег практически безразлично, редактирование какого текста (программы или описания конфигурации) приведет к потере работоспособности.
Наборное гнездо
Потребности и в вариантных, и в наборных гнездах могут возникать в задачах из практически любой предметной области. Однако в вариантных гнездах наиболее остро нуждается относительно обособленная отрасль программирования – задачи вычислительного эксперимента. Наборные гнезда, являются некоторым обобщением вариантных гнезд, и поэтому могут быть использованы для более широкой области программирования.
Наборные гнезда каркаса программы предназначаются для подстановки на их место нескольких однородных модулей. Таким образом, наборное гнездо служит для оформления группы однородных смежных элементов программы, повышая наглядность и обеспечивая возможность безболезненного расширения этой группы. Наборное гнездо представляет собой цикл периода сборки программы. Цикл повторяется столько раз, сколько имеется в программном фонде однородных модулей, предназначенных данной конкретной конфигурацией для подстановки в наборное гнездо, а переменная цикла в это время последовательно пробегает все подставляемые модули.
#SET имя_набора
тело_гнезда
[ #DELIMITER разделитель ]
#END_OF_SET
Предложения #SET и #END_OF_SET очерчивают границы гнезда, а имя_набора задает подставляемый набор однородных модулей и одновременно служит в качестве переменной цикла, пробегающей по всем подставляемым модулям. В цикле многократно воспроизводится тело_гнезда, представляющее собой произвольный текст на исходном языке, в котором располагаются точки включения односвязных компонентов модуля. Точки включения задаются с помощью конструкций вставки вида
#имя_набора.имя_компонента
Если модуль односвязный, то имя компонента не указывается и конструкция вставки приобретает более простой вид:
#имя_набора
Для включения в формируемый текст имени очередного однородного модуля используется конструкция вставки, где на месте имени компонента записывается зарезервированное слово NAME:
#имя_набора.NAME
Сходным образом включается в текст номер текущего повторения цикла (NUMBER), общее число однородных модулей (SIZE) и т.д.
Часть #DELIMITER может быть опущена. Если она присутствует, то между повторениями цикла (но не вслед за последним повтрением) записыается разделитель.
В программе может располагаться несколько наборных гнезд, относящихся к одному набору. В каждом из этих гнезд элементы набора перебираются в одной и той же последовательности.
Описывая конкретную конфигурацию формируемой программы, для задания требуемого содержимого наборного гнезда можно использовать два механизма: перечислительный и ассоциативный. Безболезненность существенно зависит от того, которому из этих двух механизмов отдано предпочтение.
При перечислительной схеме в описании конфигурации явно перечисляются имена сменных модулей, размещаемых в гнезде. Если новые модули, пополняющие программный фонд, не должны участвовать в отлаженных ранее версиях программы, то с точки зрения безболезненности заполнение наборного гнезда по перечислительной схеме ничем не отличается от заполнения вариантного гнезда, т.е. применения перечислительной схемы безболезненно.
Однако, если вновь создаваемые сменные модули нужно подключать к имеющимся версиям, то перечислительная схема теряет даже свойство безболезненности для окружения. Ведь при этой схеме приходится вручную редактировать существующий первичный объект – описание конкретной версии программы, содержащее перечень входящих в нее модулей.
При ассоциативной схеме в наборном гнезде размещаются либо все имеющиеся в пакете модули, предназначенные для этого гнезда, либо только те из них, которые обладают некоторыми свойствами (атрибутами), указанными в описании конфигурации. Тут новый сменный модуль всегда может сразу же включиться в существовавшую ранее версию программы, поскольку назначение его производится не непосредственно (путем указания имени), а неявно (путем указания свойства).
С одной стороны, подключение происходит безболезненно для окружения. Ни соседние модули, ни тексты описаний конкретных конфигураций не меняются. Тем не менее, новый модуль не только огранично вливается в пакетное окружение, но и, возможно, сразу же на равных правах со всеми включается в работу.
С другой стороны, требованию безболезненности для работоспособности ассоциативная схема не удовлетворяет. Причина в том, что если в подключаемом модуле имеются ошибки, то его появление (из-за неявного указания) в ранее отлаженной версии программы может привести к потере работоспособности.