Стили, их ипостаси, методологии, методики, технологии
Поскольку ничего универсального нет, можно удариться в другую крайность, скатившись на набор рецептов и потеряв саму суть метода: гибкость и широкую применимость в самых разных областях. Если мы ориентируемся на такой ползучий эмпиризм, то дальнейшее развитие быстро упирается в эффект мусорной кучи: несистематизированные рецепты знаниями так и не становятся. Для каждого класса задач нужно искать специализированные методы и подходы.
Чем уже класс задач, тем больше общих особенностей у этих задач. Это наиболее четко прослеживается в том случае, если класс задач выделяется не по номенклатурному признаку (например, бухгалтерские задачи, задачи автоматизации документооборота), а по критериям, отражающим суть вовлеченных в задачи структур. До некоторой степени, чем абстрактнее описание задачи, тем лучше для выработки метода программирования.
Рассмотрим пример. Пусть имеется предприятие с некоторым количеством различных станков, выпускающее детали. Оно получает разнообразные заказы, и в соответствии с приоритетами заказов и технологией обработки деталей нужно динамически строить расписание работы станков. Решив эту задачу и столкнувшись через некоторое время с задачей документооборота в фирме, производящей спецификации большого числа разнообразных лекарств для потребителя и для специалистов, можно усмотреть подобие двух задач. В хорошо организованной бюрократической машине каждый исполнитель работает подобно станку, выполняя свою операцию, точно так же имеется сеть зависимостей (некоторые исполнители могут работать лишь после того, как им подготовили материал другие), и те же методы (а часто даже и почти те же программы) переносятся на планирование бумажного потока.
Таким образом, для систематизации сведений и превращения их в знания необходимо выделять общие характеристики найденных частных решений. Эти общие характеристики превращаются в приемы, а затем, при их осознании и обобщении, в методы.
Метод — сильное оружие, и поэтому наряду с большими достоинствами он обязательно имеет большие недостатки.
В частности, применение метода требует достаточно высокого интеллектуального уровня и владения рядом навыков, прививаемых точными науками, в частности, умением переходить к абстрактному от конкретного и обратно. Поскольку подавляющее большинство специалистов не владеют мышлением на таком уровне, чтобы они могли применять метод в чистом виде, метод конкретизируют в методику.
Методика — это набор шаблонов, процедур и рецептов, конкретизирующих метод4). Например, метод многоаспектного моделирования, положенный в основу UML (Unified Modelling language), конкретизирован в методику.
Примером методики служит общая часть RUP (Rational Unified Process). Сам UML лишь поставляет материал для конкретной методики: формы, в которых можно строить систему взаимосвязанных моделей, описывающих разные стороны создаваемой программы, и процедуры отладки таких описаний. Методикой может пользоваться уже значительное меньшинство5) специалистов, поскольку ее применение требует элементарных операций конкретизации и композиции и доступно людям, владеющим комбинационным мышлением. Но для успешного применения в коллективе методика должна конкретизироваться далее.
Тот же самый RUP, помимо методики применения многоаспектных моделей, содержит часть, касающуюся регламента работы программистского коллектива согласно данной методике. Это — технология. В технологии расписываются действия, даются шаблоны документов, определяются роли и функции лиц, задействованных в проекте. Поскольку в программистских коллективах чернорабочий имеет квалификацию техника обычного "железного" производства, программистские технологии, в отличие от индустриальных, оставляют некоторый простор для конкретизации и модификации, давая возможность подставлять в шаблоны целые серии динамически определяемых конкретных действий. На "железном" производстве технология — строго определенная последовательность операций, примерно соответствующая отлаженной программе в программистском мире.
RUP позволил в десятки раз поднять производительность труда программистов при решении задач, с бедным содержанием и навороченным пользовательским интерфейсом.
Знакомство с конкретной методикой индустриального программирования должно быть предметом отдельного курса, оно полезно и для тех, кто никогда в жизни не будет пользоваться такой методикой, поскольку может выйти непосредственно на уровень метода. Для них эта методика будет примером конкретизации метода, которую такой человек должен делать, если не желает оставаться непонятым.
Но, кроме методов, есть еще два этажа. Первый из высших этажей начали рассматривать в 70-е гг. XX века. Это методологии программирования6). Методология на самом деле ортогональна методам: это надстройка на другом крыле программистского здания. В этом случае достаточно сослаться на структурное программирование. Метод реализуется при помощи методологии и в ее рамках.
Второй из высших этажей впервые был систематически исследован в книге [22]. Он связан с тем, что в программировании мы имеем дело с намного более абстрактными и идеальными понятиями, чем в материальном производстве. Поэтому длина логических построений возрастает, сложность формализации используемых методов убывает, и мы в гораздо большей степени зависим от логики наших рассуждений, чем от "материи".
Логика построения отличается от логики оформления готовых рассуждений, которую преподают на стандартных курсах и на которой основана классическая версия математики. Уже с начала ХХ века в математике появилось конструктивное направление (вариантами которого являются, в частности, интуиционизм и советский конструктивизм), для которого главное не доказательство, а содержащееся в нем идеальное построение. Основатель конструктивного направления Л. Э. Я. Брауэр (Голландия) установил, что причины, по которым математическое доказательство не всегда дает построение, лежат в логике. Так появилось понятие конструктивной логики, в которой мы интересуемся не истинностью формул, а их реализуемостью (возможностью построения решения задачи заданными средствами).
В дальнейшем выяснилось, что разным классам средств и ресурсных ограничений соответствуют разные логики.
Эти логики не просто расходятся, а противоречат друг другу. Для того чтобы сохранить хотя бы минимальную внутреннюю согласованность наших рассуждений в ходе построения сложного искусственного объекта (в нашем случае программы), нужно с самого начала определить класс средств и ресурсных ограничений, которые необходимо принимать во внимание.
Таким образом возникают классы способов построения программ, логически противоречащие друг другу и применимые каждый в своей области. Эти классы дают самую общую картину программ, базирующихся на выбранных моделях вычислительной обстановки.
Структурное программирование соответствует взгляду на вычислительную обстановку как на хранилище отдельных значений, связанных отношениями, и взгляду математики XIX века на мир как на то, что может быть описано числовыми характеристиками; роль программы при этом — вычисление новых значений по старым.
Автоматное программирование соответствует рассмотрению действий как изменяющих вычислительную обстановку существенно и глобально, в результате чего то, что было, может оказаться неверным.
Сентенциальное программирование рассматривает вычислительную обстановку как глобальную регулярную структуру значений, которая может проверяться на соответствие регулярно заданным шаблонам и изменяться столь же регулярной подстановкой в нее других подструктур и перекоммутированием связей.
Событийное программирование рассматривает вычислительный мир как нечто изменяющееся во времени, а программу как совокупность активных агентов, посылающих друг другу сообщения через внешний мир и производящих в нем действия, в результате которых внешний мир может активизировать других агентов.
Все эти четыре стиля используют лишь ограниченные (с точки зрения логических формул) фрагменты соответствующих конструктивных логик. Например, в структурном стиле можно считать, что в формуле лишь одна импликация, поскольку все действия преобразуют значения, а не функции.
Функциональное программирование в его нынешней форме соответствует взгляду математики конца ХХ века на мир как на совокупность структур высших порядков и функционалов, производящих на базе одних структур другие.
Оно единственное использует полный язык конструктивной логики, в котором реализациями сложных формул являются функционалы.
Таким образом, появилось понятие стиля программирования как совокупности парадигм и методологий, соответствующих одному и тому же классу логических методов, используемых при построении программ.
На первом уровне все стили укладываются в следующий морфологический ящик по координатам действия-условия, локальность-глобальность, выявляющий назначение каждого стиля.
Локальные | Локальные | Структурный |
Глобальные | Локальные | Автоматный |
Локальные | Глобальные | Событийный |
Глобальные | Глобальные | Сентенциальный |
В структурном стиле имеется две ипостаси: циклическая и рекурсивная. Циклическая ипостась хороша, когда структуры данных статические и не слишком глубокие, и очередной слой информации практически полностью используется следующим слоем. Рекурсивная ипостась хороша, когда структуры данных динамические и глубокие, и на следующем слое нужна лишь малая часть предыдущего слоя, либо слои сами по себе имеют малую ширину.
В автоматном стиле имеется две ипостаси: последовательная и параллельная. Последовательная ипостась хороша, когда система представляется как единый блок информации, а параллельная — когда система делится на относительно автономные взаимодействующие подсистемы.
Заметим, что на автоматном стиле можно проследить, как одни и те же программы можно реализовать разными методами программирования, лежащими внутри одного и того же стиля. Методы реализации близки к технологической дисциплине, они мешают друг другу при произвольном смешении скорее технологически, чем логически или ресурсно.Если программа построена эклектической смесью нескольких методов, ее труднее отлаживать и особенно модифицировать.
В событийном стиле имеются две ипостаси: от событий и от приоритетов. Здесь можно увидеть, что стиль появляется и существует независимо от языковой поддержки и порою даже вопреки ей.
В функциональном стиле ипостаси пока не появились, поскольку он сам по себе не был осознан и все время смешивается с рекурсивной ипостасью структурного программирования. Здесь можно увидеть, как недостаток внимания к интерфейсам между разными стилями приводит к интеграции одного стиля в другой. Даже когда (как в данном случае) они неплохо взаимодействуют, они еще лучше существовали бы по отдельности.