Автоматное программирование
- 1 year ago
- 0
- 0
Структу́рное программи́рование — парадигма программирования , в основе которой лежит представление программы в виде иерархической структуры блоков . Концептуализирована в конце 1960-х — начале 1970-х годов на фундаменте теоремы Бёма — Якопини , математически обосновывающей возможность структурной организации программ, и работы Эдсгера Дейкстры ( англ. ).
В соответствии с парадигмой, любая программа, которая строится без использования оператора goto, состоит из трёх базовых управляющих конструкций: последовательность, ветвление , цикл ; кроме того, используются подпрограммы . При этом разработка программы ведётся пошагово, методом «сверху вниз».
Методология структурного программирования появилась как следствие возрастания сложности решаемых на компьютерах задач, и соответственно, усложнения программного обеспечения. В 1970-е годы объёмы и сложность программ достигли такого уровня, что традиционная (неструктурированная) разработка программ перестала удовлетворять потребностям практики. Программы становились слишком сложными, чтобы их можно было нормально сопровождать. Поэтому потребовалась систематизация процесса разработки и структуры программ.
Методология структурной разработки программного обеспечения была признана «самой сильной формализацией 70-х годов».
По мнению Бертрана Мейера, «Революция во взглядах на программирование, начатая Дейкстрой, привела к движению, известному как структурное программирование, которое предложило систематический, рациональный подход к конструированию программ. Структурное программирование стало основой всего, что сделано в методологии программирования, включая и объектное программирование » .
Первоначально идея структурного программирования появилась на свет в связи с оператором goto и сомнениями в целесообразности его применения. Впервые подобные сомнения высказал Хайнц Земанек (Heinz Zemanek) на совещании по языку Алгол в начале 1959 года в Копенгагене. Однако это выступление не привлекло к себе внимания и не имело последствий. Эдсгер Дейкстра вспоминает: «До некоторой степени я виню себя за то, что в то время не смог оценить значимость этой идеи» .
Ситуация коренным образом изменилась через десять лет, когда в марте 1968 года Дейкстра опубликовал своё знаменитое письмо «Оператор Go To считается вредным» (Go To Statement Considered Harmful ). Это поистине исторический документ, оказавший заметное влияние на дальнейшее развитие программирования.
Судьба самого документа очень интересна. Дело в том, что Дейкстра дал статье совсем другое название: «Доводы против оператора GO TO» (A Case against the GO TO Statement).
Однако в момент публикации произошло нечто непонятное — статья почему-то загадочным образом превратилась в «Письмо к редактору», причем прежнее название столь же загадочно исчезло. Что произошло на самом деле? Дейкстра объяснил таинственное превращение статьи в письмо лишь много лет спустя, в 2001 году, за год до смерти.
Журнал Communications of the ACM опубликовал мой текст под названием «Оператор GOTO считается вредным». В последующие годы его часто цитировали. К сожалению, зачастую это делали люди, которые видели в нём не больше, чем сказано в заголовке. Этот заголовок стал краеугольным камнем моей славы…
Как все это случилось? Я отправил статью под названием «Доводы против оператора GO TO». Чтобы ускорить публикацию, редактор превратил мою статью в «Письмо к редактору». При этом он придумал для статьи новое название, которое изобрел сам. Редактором был Никлаус Вирт .
Цель структурного программирования — повысить производительность труда программистов, в том числе при разработке больших и сложных программных комплексов, сократить число ошибок, упростить отладку, модификацию и сопровождение программного обеспечения.
Такая цель была поставлена в связи с ростом сложности программ и неспособностью разработчиков и руководителей крупных программных проектов справиться с проблемами, возникшими в 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 .
Теорема Бёма-Якопини написана сложным языком и в непривычных обозначениях. Если использовать современную терминологию и обозначения, она примет вид:
Любая программа, заданная в виде блок-схемы, может быть представлена с помощью трёх управляющих структур:
- последовательность — обозначается: f THEN g,
- ветвление — обозначается: IF p THEN f ELSE g,
- цикл — обозначается: WHILE p DO f,
где f, g — блок-схемы с одним входом и одним выходом,
- р — условие,
- THEN, IF, ELSE, WHILE, DO — ключевые слова .
Пояснение. Формула f THEN g означает следующее: сначала выполняется программа f, затем выполняется программа g.
Как отмечает ( англ. ), данная теорема резко контрастирует с обычной (в 1960—1970 годы) практикой программирования, когда наблюдалось массовое использование операторов перехода goto .
Бём и Якопини не употребляли термин «структурное программирование». Тем не менее, доказанную ими теорему (и её последующие вариации у разных авторов) впоследствии стали называть «теоремой о структурном программировании», «структурной теоремой» , «теоремой о структурировании» .
Становление и развитие структурного программирования связано с именем Эдсгера Дейкстры .
Принцип 1. Следует отказаться от использования оператора безусловного перехода goto.
Принцип 2. Любая программа строится из трёх базовых управляющих конструкций: последовательность, ветвление, цикл.
Принцип 3. В программе базовые управляющие конструкции могут быть вложены друг в друга произвольным образом. Никаких других средств управления последовательностью выполнения операций не предусматривается.
Принцип 4. Повторяющиеся фрагменты программы можно оформить в виде подпрограмм (процедур и функций ). Таким же образом (в виде подпрограмм) можно оформить логически целостные фрагменты программы, даже если они не повторяются.
Принцип 5. Каждую логически законченную группу инструкций следует оформить как блок . Блоки являются основой структурного программирования.
BEGIN..END
(в языке Паскаль) или фигурными скобками {…} (в языке C) или отступами (в языке Питон).
Принцип 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 и т. д. и заменить их на управляющую графику, то есть использовать двумерное структурное программирование .