Структурное программирование

Структу́рное программи́рование—парадигма программирования, в основе которой лежит представление программы в виде иерархической структурыблоков.
Концептуализирована в конце 1960-х — начале 1970-х годов на фундаментетеоремы Бёма — Якопини, математически обосновывающей возможность структурной организации программ, и работыЭдсгера Дейкстры«О вреде оператора goto»(англ.Goto considered harmful).
В соответствии с парадигмой, любая программа, которая строится без использования оператора goto, состоит из трёх базовых управляющих конструкций: последовательность,ветвление,цикл; кроме того, используютсяподпрограммы. При этом разработка программы ведётся пошагово, методом «сверху вниз».
Методология структурного программирования появилась как следствие возрастания сложности решаемых на компьютерах задач, и соответственно, усложнения программного обеспечения. В 1970-е годы объёмы и сложность программ достигли такого уровня, что традиционная (неструктурированная) разработка программ перестала удовлетворять потребностям практики. Программы становились слишком сложными, чтобы их можно было нормально сопровождать. Поэтому потребовалась систематизация процесса разработки и структуры программ.
Методология структурной разработки программного обеспечения была признана «самой сильной формализацией 70-х годов».
По мнению Бертрана Мейера, «Революция во взглядах на программирование, начатая Дейкстрой, привела к движению, известному как структурное программирование, которое предложило систематический, рациональный подход к конструированию программ. Структурное программирование стало основой всего, что сделано в методологии программирования, включая иобъектное программирование».
Первоначально идея структурного программирования появилась на свет в связи с оператором goto и сомнениями в целесообразности его применения. Впервые подобные сомнения высказал Хайнц Земанек (Heinz Zemanek) на совещании по языкуАлголв начале 1959 года в Копенгагене. Однако это выступление не привлекло к себе внимания и не имело последствий.Эдсгер Дейкстравспоминает: «До некоторой степени я виню себя за то, что в то время не смог оценить значимость этой идеи».
Ситуация коренным образом изменилась через десять лет, когда в марте 1968 года Дейкстра опубликовал своё знаменитое письмо «Оператор Go To считается вредным» (Go To StatementConsidered Harmful). Это поистине исторический документ, оказавший заметное влияние на дальнейшее развитие программирования.
Судьба самого документа очень интересна. Дело в том, что Дейкстра дал статье совсем другое название: «Доводы против оператора GO TO» (A Case against the GO TO Statement).
Однако в момент публикации произошло нечто непонятное — статья почему-то загадочным образом превратилась в «Письмо к редактору», причем прежнее название столь же загадочно исчезло. Что произошло на самом деле? Дейкстра объяснил таинственное превращение статьи в письмо лишь много лет спустя, в 2001 году, за год до смерти.
Цель структурного программирования — повысить производительность труда программистов, в том числе при разработке больших и сложных программных комплексов, сократить число ошибок, упростить отладку, модификацию и сопровождение программного обеспечения.
Такая цель была поставлена в связи с ростом сложности программ и неспособностью разработчиков и руководителей крупных программных проектов справиться с проблемами, возникшими в 1960—1970 годы в связи с развитием программных средств.
Структурное программирование призвано, в частности, устранить беспорядок и ошибки в программах, вызванные трудностями чтения кода, несистематизированным, неудобным для восприятия и анализаисходным текстомпрограммы. Такой текст нередко характеризуют как «спагетти-код».
Спагетти-код— плохо спроектированная, слабо структурированная, запутанная и трудная для пониманияпрограмма, содержащая много операторовgoto(особенно переходов назад),исключенийи других конструкций, ухудшающих структурированность. Один из самых известныхантипаттерновпрограммирования.
Спагетти-код назван так потому, что ход выполнения программы похож на мискуспагетти, то есть извилистый и запутанный. Иногда называется «кенгуру-код» (kangaroo code) из-за множества инструкцийjump.
В настоящее время термин применяется не только к случаям злоупотребления goto, но и к любому «многосвязному» коду, в котором один и тот же небольшой фрагмент исполняется в большом количестве различных ситуаций и выполняет много различных логических функций.
Спагетти-код может быть отлажен и работать правильно и с высокой производительностью, но он крайне сложен в сопровождении и развитии. Доработка спагетти-кода для добавления новой функциональности иногда несет значительный потенциал внесения новых ошибок. По этой причине становится практически неизбежнымрефакторинг— главное лекарство от спагетти.
Начиная с 1970-х годов, оператор безусловного перехода goto оказался в центре систематической и всевозрастающей критики. Неправильное и необдуманное использование оператора goto висходном текстепрограммы приводит к получению запутанного,неудобочитаемого«спагетти-кода». По тексту такого кода практически невозможно понять порядок исполнения и взаимозависимость фрагментов.
Впервые эта точка зрения была отражена в статьеЭдсгера Дейкстры«Оператор Go To считается вредным». Дейкстра заметил, что качество программного кода обратно пропорционально количеству операторов goto в нём. Статья приобрела широкую известность, в результате чего взгляды на использование оператора goto были существенно пересмотрены. В работе «Заметки по структурному программированию»Дейкстра обосновал тот факт, что для кода без goto намного легче проверитьформальную корректность.
Код с goto трудно форматировать, так как он может нарушать иерархичность выполнения (парадигму структурного программирования) и потому отступы, призванные отображать структуру программы, не всегда могут быть выставлены правильно. Кроме того, оператор goto мешаетоптимизации компиляторамиуправляющих структур.
Некоторые способы применения goto могут создавать проблемы с логикой исполнения программы:
Доводы против оператора goto оказались столь серьёзными, что в структурном программировании его стали рассматривать как крайне нежелательный. Это нашло отражение при проектировании новых языков программирования. Например, goto запрещён вJavaиRuby. В ряде современных языков он всё же оставлен из соображений эффективности в тех редких случаях, когда применение goto оправданно. Так, goto сохранился вАде— одном из наиболее продуманных с точки зрения архитектуры языков за всю историю.
Однако в языках высокого уровня, где этот оператор сохранился, на его использование, как правило, накладываются жёсткие ограничения, препятствующие использованию наиболее опасных методов его применения: например, запрещается передавать управление извне цикла, процедуры или функции внутрь. Стандарт языка C++ запрещает обход инициализации переменной с помощью goto.
Теорему сформулировали и доказали итальянские математикиКоррадо Бёми Джузеппе Якопини (Giuseppe Jacopini). Они опубликовали её в 1965 году на итальянском языке и в 1966 году на английском. Наряду с теоремой, в статье Бёма и Якопини описывались методы преобразования неструктурных алгоритмов в структурные на примере созданного Бёмом языка программированияP′′. Язык P′′ — первыйполный по Тьюрингуязык программированиябез оператораgoto.
Теорема Бёма-Якопини написана сложным языком и в непривычных обозначениях. Если использовать современную терминологию и обозначения, она примет вид:
Как отмечаетХарлан Миллс(англ.Harlan Mills), данная теорема резко контрастирует с обычной (в 1960—1970 годы) практикой программирования, когда наблюдалось массовое использование операторов перехода goto.
Бём и Якопини не употребляли термин «структурное программирование». Тем не менее, доказанную ими теорему (и её последующие вариации у разных авторов) впоследствии стали называть «теоремой о структурном программировании», «структурной теоремой», «теоремой о структурировании».
Становление и развитие структурного программирования связано с именем Эдсгера Дейкстры.
Принцип 1.Следует отказаться от использования оператора безусловного перехода goto.
Принцип 2.Любая программа строится из трёх базовых управляющих конструкций: последовательность, ветвление, цикл.
Принцип 3.В программе базовые управляющие конструкции могут быть вложены друг в друга произвольным образом.Никаких других средств управления последовательностью выполнения операций не предусматривается.
Принцип 4.Повторяющиеся фрагменты программы можно оформить в видеподпрограмм(процедур ифункций).Таким же образом (в виде подпрограмм) можно оформить логически целостные фрагменты программы, даже если они не повторяются.
Принцип 5.Каждую логически законченную группу инструкций следует оформить какблок.Блоки являются основой структурного программирования.
Принцип 6.Все перечисленные конструкции должны иметь один вход и один выход.
Принцип 7.Разработка программы ведётся пошагово, методом «сверху вниз»(top-down method).
Сначала пишется текст основной программы, в котором, вместо каждого связного логического фрагмента текста, вставляется вызов подпрограммы, которая будет выполнять этот фрагмент. Вместо настоящих, работающих подпрограмм, в программу вставляются фиктивные части —заглушки, которые, говоря упрощенно, ничего не делают.
Если говорить точнее, заглушка удовлетворяет требованиям интерфейса заменяемого фрагмента (модуля), но не выполняет его функций или выполняет их частично. Затем заглушки заменяются или дорабатываются до настоящих полнофункциональных фрагментов (модулей) в соответствии с планом программирования. На каждой стадии процесса реализации уже созданная программа должна правильно работать по отношению к более низкому уровню. Полученная программа проверяется и отлаживается.
После того, какпрограммистубедится, что подпрограммы вызываются в правильной последовательности (то есть общая структура программы верна), подпрограммы-заглушки последовательно заменяются на реально работающие, причём разработка каждой подпрограммы ведётся тем же методом, что и основной программы. Разработка заканчивается тогда, когда не останется ни одной заглушки.
Такая последовательность гарантирует, что на каждом этапе разработки программист одновременно имеет дело с обозримым и понятным ему множеством фрагментов, и может быть уверен, что общая структура всех более высоких уровней программы верна.
При сопровождении и внесении изменений в программу выясняется, в какие именно процедуры нужно внести изменения. Они вносятся, не затрагивая части программы, непосредственно не связанные с ними. Это позволяет гарантировать, что при внесении изменений и исправлении ошибок не выйдет из строя какая-то часть программы, находящаяся в данный момент вне зоны внимания программиста.
Следует также учесть, что в «Предисловии» к книге «Структурное программирование»Тони Хоаротмечает, что принципы структурного программирования в равной степени могут применяться при разработке программ как «сверху вниз», так и «снизу вверх».
Подпрограммы не являлись необходимым условием возможности реализации структурного программирования. Изначально подпрограммы появились как средство оптимизации программ по объёму занимаемой памяти — они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времениданная функция подпрограмм стала вспомогательной, главное их назначение — структуризация программы с целью удобства её понимания и сопровождения.
Выделение набора действий в подпрограмму и вызов её по мере необходимости позволяет логически выделить целостную подзадачу, имеющую типовое решение. Такое действие имеет ещё одно (помимо экономии памяти) преимущество перед повторением однотипных действий. Любое изменение (исправление ошибки, оптимизация, расширение функциональности), сделанное в подпрограмме, автоматически отражается на всех её вызовах, в то время как при дублировании каждое изменение необходимо вносить в каждое вхождение изменяемого кода.
Даже в тех случаях, когда в подпрограмму выделяется однократно производимый набор действий, это оправдано, так как позволяет сократить размеры целостных блоков кода, составляющих программу, то есть сделать программу более понятной и обозримой.
Следование принципам структурного программирования сделало тексты программ, даже довольно крупных, нормально читаемыми. Серьёзно облегчилось понимание программ, появилась возможность разработки программ в нормальном промышленном режиме, когда программу может без особых затруднений понять не только её автор, но и другие программисты. Это позволило разрабатывать достаточно крупные для того времени программные комплексы силами коллективов разработчиков, и сопровождать эти комплексы в течение многих лет, даже в условиях неизбежных изменений в составе персонала.
Структурное программирование значительно повышает ясность иудобочитаемостьпрограмм.Эдвард Йорданпоясняет:
Улучшение удобочитаемости структурных программ объясняется тем, что отсутствие оператора goto позволяет читать программу сверху донизу без разрывов, вызванных передачами управления. В итоге можно сразу (одним взглядом) обнаружить условия, необходимые для модификации того или иного фрагмента программы.
Р-технология производства программ, или «технология двумерного программирования»была создана вИнституте кибернетики имени В. М. Глушкова. Графическая система Р-технологии программирования закреплена в стандартахГОСТ 19.005—85,ГОСТ Р ИСО/МЭК 8631—94и международном стандартеISО 8631Н.
Автор Р-технологии программирования доктор физико-математических наук профессор Игорь Вельбицкий предложил пересмотреть само понятие «структура программы». По его мнению, «структура — понятие многомерное. Поэтому отображение этого понятия с помощью линейных текстов (последовательности операторов) сводит практически на нет преимущества структурного подхода. Огромные ассоциативные возможности зрительного аппарата и аппарата мышления человека используются практически вхолостую — для распознавания структурных образов в виде единообразной последовательности символов».
Методология двумерного структурного программирования существенно отличается от классического одномерного (текстового) структурного программирования.
Идеи структурного программирования разрабатывались, когдакомпьютерная графикафактически ещё не существовала и основным инструментом алгоритмиста и программиста был одномерный (линейный илиступенчатый) текст. До появления компьютерной графики методология классического структурного программирования быланаилучшимрешением.
С появлением компьютерной графики ситуация изменилась. Используя выразительные средства графики, появилась возможность видоизменить, развить и дополнить три типа базовых (текстовых) управляющих структурных конструкций, а также полностью отказаться отключевых словif, then, else,case, switch, break,while, do, repeat, until, for, foreach, continue, loop, exit, when, last и т. д. и заменить их на управляющую графику, то есть использовать двумерное структурное программирование.