1. История развития языков программирования
Last updated
Was this helpful?
Last updated
Was this helpful?
Любая компьютерная программа, в конечном итоге, сводится к машинному коду - набору двоичных инструкций, которые выполняются центральным процессором.
Чтобы задать эти инструкции, на заре компьютерной эры, в 40-х годах ХХ века, от программистов требовалось физически использовать различные переключатели и менять месторасположение различных перемычек. Это было чудовищно неудобно, так как компьютерную программу необходимо было вводить в компьютер вручную.
В 50-х годах компьютеры начали использовать перфокарты. Перфокарты представляли собой картонные карточки, в которых необходимо было проделать в нужных местах отверстия, чтобы задать требуемые инструкции.
На заре компьютерной эры для программирования компьютеров использовался машинный код. Он представлял собой прямой набор инструкций процессора, а также аргументы для той или иной инструкции. Приведем пример программы для вывода надписи "Hello, world!" на машинном коде.
Для того, чтобы писать в машинных кодах, требуется досконально знать внутреннее устройство компьютера и подробности работы центрального процессора. Также, различные центральные процессоры различных фирм имели свой набор команд, что приводило к тому, что программа в машинных кодах писалась под конкретную модель центрального процессора.
Годом рождения языка ассемблера можно считать 1949 год. Язык ассемблера представляет собой систему обозначений, которая позволяет облегчить написание программ в машинном коде. Вместо кодов команд используются специальные обозначения (мнемоники), например "MOV" или "ADD". Также, можно было использовать различные системы счисления, а также давать меткам символические имена. Приведем пример программы, которая печатает на экране "Hello, world!" (диалект NASM Linux).
Необходимо отметить, что инструкции на языке ассемблера один в один транслируются в инструкции в машинных кодах (по крайней мере, так было изначально). Язык ассемблера предоставляет более удобную форму записи инструкций для процессора.
Особенностью программирования в машинных кодах и на языке ассемблера было то, что процесс разработки таких программ был очень медленный, отладка и поиск ошибок занимало огромное количество времени, а сами программы представляли собой научные расчеты для военной или аэрокосмической отрасли.
FORTRAN и неструктурированные языки программирования
С течением времени, компьютеры становились все более производительными и дешевыми. Компьютерами заинтересовались не только военные и ученые, а и различные коммерческие фирмы, возникла потребность в разработке все более сложных программ, которые занимались не только научными расчетами. Существующие языки (ассемблер и язык машинных команд) не позволяли писать большие и сложные программы, к тому же, стал вопрос об удешевлении стоимости написания программ для бизнеса.
Все это сформировало потребность в развитии Computer Science и появлении принципиально новых языков программирования, которые бы позволили писать сложные программы и тратить меньше времени и денег на их производство, внедрение и поддержку.
Адмирал Грейс Хоппер, разработчик одного из высокоуровневых языков программирования, так описывала необходимость в новых инструментах для разработки компьютерных программ:
Когда-то я была профессором математики. В то время я обнаружила, что есть студенты, которые не могут изучать математику. Затем мне поручили сделать так, чтобы предпринимателям было легко пользоваться нашими компьютерами. Оказалось, что вопрос не в том, смогут ли они изучать математику, а в том, захотят ли они. [ ... ] Многие из них говорили: "Выбросьте эти символы — я не знаю, что они означают, у меня нет времени их изучать’ А тем, кто заявляет, что люди обрабатывающие данные, должны использовать математическую нотацию, я посоветую для начала обучить математической записи вице-президента или полковника или адмирала. Уверяю вас, я уже пробовала.
В конце 1953 года, сотрудник IBM Джон Бэкус предложил более практичную альтернативу языку ассемблера для программирования компьютера IBM 704, которая называлась FORTRAN. Первый компилятор для языка FORTRAN был разработан в апреле 1957 года.
Язык FORTRAN стал невероятно популярным языком высокого уровня и позволил существенно повысить эффективность разработки, внедрения и поддержки компьютерных программ.
Концепция языков высокого уровня позволяет существенно упростить и ускорить процесс разработки программного обеспечения. Основная черта высокоуровневых языков — это абстракция, то есть введение смысловых конструкций, кратко описывающих такие структуры данных и операции над ними, описания которых на машинном коде (или другом низкоуровневом языке программирования) очень длинны и сложны для понимания.
Для того, чтобы объяснить один из главных недостатков языков программирования того времени, приведем пример программы на языке FORTRAN
Обратите внимание на строку
В этой строке проверяется переменная IB
. Что означает запись 777,777,702
? Если переменная меньше или равна 0, то выполняется строка с меткой 777 - программа останавливается с кодом ошибки 1. Если переменная IB
больше 0, то выполняется строка с меткой 702 - происходит проверка переменной IC
.
Программы того времени представляли собой большое полотно кода, который был плохо структурирован, а ветвления и циклы реализовывались с помощью переходов на определенную строку или метку.
По мере увеличения количества строк кода, такой способ написания программ приводил к такому явлению как "спагетти-код" (spaghetti code) - плохо структурированная и трудная для понимания программа.
Инструкции перехода jump повсеместно применяются в машинном языке и в языке ассемблера, но в языках высокого уровня их использование приводило к тому, что когда программа разрасталась до определенного размера, ее модификация, поддержка и отладка становилась очень дорогой и медленной.
Для примера, сравните две программы для печати числе от 1 до 10 и их квадратов, реализованных на неструктурированном языке BASIC и в код в стиле структурного программирования
Безусловно, неструктурированные языки были огромным шагом вперед по сравнению с языками низкого уровня, но они лишь на время отсрочили необходимость создания более совершенных языков и парадигм программирования, которые смогли бы открыть путь к безболезненной разработке более сложных программ.
Период середины с середины 60-х сегодня известен как "кризис программного обеспечения".
Термин software появился в 1958 году, а уже через 10 лет начали говорить о кризисе программного обеспечения — это словосочетание впервые прозвучало в 1968 году в докладе Питера Наура и Брайана Рэнделла «Программная инженерия», зачитанном на конференции Научного комитета НАТО.
На протяжении десятков лет появился целый ряд публикаций, посвященных Программному кризису 1.0. По оценке Пера Флаттена и его коллег, приведенной в докладе от 1989 года, в среднем на осуществление проекта разработки ПО уходило по 18 месяцев. Это консервативная оценка, если учесть, что в 1988 году авторы статьи в Business Week этот показатель назвали равным трем годам, а в 1982-м аналитики указывали, что на программные проекты уходит по пять лет.
В 1994 году в отчете об исследовании, проведенном специалистами IBM, утверждалось. что 68% всех программных проектов отстают от графика. Там же приводились сведения о том, что превышение бюджетов проектов разработки достигает 65%. Для обозначения программных систем, выпущенных, но неиспользуемых, даже придумали термин shelfware — «ПО на полку».
Эксперты компании Standish Group в докладе CHAOS Manifesto, выпущенном в 2011 году, сетуют на высокую долю провальных проектов, правда, применяемые ими методологию анализа и выводы подвергали сомнению. Программный кризис 1.0, похоже, уже прошел, и благодаря многочисленным инкрементальным усовершенствованиям процесса разработки ПО ситуация все-таки изменилась к лучшему. Практические перемены в конечном итоге привели к тому, что сегодня ПО, как правило, разрабатывается в пределах бюджета и отвечает техническим требованиям. К сожалению, теперь надвигается кризис 2.0, и, как показано на рисунке, его первопричина — неспособность создания ПО, эффективно использующего колоссальные объемы данных, которые появились за последние 50 лет, а также учитывающего возросшие технические характеристики устройств и требования их пользователей.
Чтобы продемонстрировать рост вычислительных мощностей на протяжении 60х годов, приведем один пример. Мейнфрейм IBM 1401, выпущенный в 1959 году, выполнял до 193 300 операций сложения в минуту. Модель IBM 360/91, выпущенная в 1968 году, выполняла до 16 600 000 операций сложения в секунду!
Приведем отрывок из выступления Эдсгера Дейкстры на вручении Премии Тьюринга в 1972 году.
Основная причина кризиса программного обеспечения заключается в том, что компьютеры стали на несколько порядков мощнее! Проще говоря: пока не было машин, программирование вообще не было проблемой; когда у нас было несколько слабых компьютеров, программирование стало небольшой проблемой, а теперь, когда у нас появились гигантские компьютеры, программирование стало столь же гигантской проблемой.
В соответствии с парадигмой, любая программа, которая строится без использования оператора goto, состоит из трёх базовых управляющих конструкций: последовательность, ветвление, цикл; кроме того, используются подпрограммы. При этом разработка программы ведётся пошагово, методом «сверху вниз».
Методология структурного программирования появилась как следствие возрастания сложности решаемых на компьютерах задач, и соответственно, усложнения программного обеспечения. В 1970-е годы объёмы и сложность программ достигли такого уровня, что традиционная (неструктурированная) разработка программ перестала удовлетворять потребностям практики. Программы становились слишком сложными, чтобы их можно было нормально сопровождать. Поэтому потребовалась систематизация процесса разработки и структуры программ.
Методология структурной разработки программного обеспечения была признана «самой сильной формализацией 70-х годов».
Структурное программирование основано на принципе "вызова процедуры", что является еще одним названием "вызова функции". Процедуры также называют функциями, подпрограммами или методами. Процедура содержит последовательность исполняемых инструкций. Любая процедура может быть вызвана в любое время выполнения программа. Процедура может быть вызвана из другой процедуры или даже может вызывать саму себя.
Изначально, все процедуры были доступны в любой части программы, также как и глобальные данные. В небольших программах это не представляло никаких проблем, но чем сложнее и больше становится программа, тем чаще небольшие изменения в одной части программы могли существенно повлиять на другие части. Сложные и большие программы порождали огромное количество запутанных зависимостей и малейшее изменение в одной процедуре могло привести к каскаду ошибок во многих других процедурах, которые зависели от изменяемой процедуры.
ООП было спроектировано для того, чтобы облегчить проектирование, поддержку и повторное использование кода. Ключевыми концепциями ООП являются инкапсуляция и абстракция, которые используются для помощи в разработки больших и сложных программ. ООП - это инструмент для создания программ в миллионы строк кода таким способом, чтобы программы можно было понимать, управлять и поддерживать.
Корректное использование ООП позволяет делать код проще, безопаснее и проще для понимания и дальнейшей модификации. ООП также помогает повторно использовать функционал в другой части программы или даже в другой программе без серьезной модификации. Это помогает снизить повторное написание одного и того же кода и работу программиста в целом.
ООП также помогает делать код более стабильным и снижает количество багов, потому что когда часть кода корректно протестирована, вы можете быть уверен, что код не приведет к ошибкам при использовании его в другой части программы.
Дискуссии о том, какое программирование "лучше" не имеют смысла. Программирование, в том или ином виде, заключается в решении задачи, вы можете решить любую задачу с помощью любой парадигмы программирования, тем более, что многие языки программирования позволяют писать код в нескольких парадигмах.
Однако, не все парадигмы позволяют решать определенные задачи в равной степени эффективно. Таким образом, дискуссии насчет парадигмы программирования не имеют смысла, до тех пор, пока не определена задача, которую вы пытаетесь решить. Как только вы определили задачу и ее параметры, вы сможете понять, какая парадигма лучше подходит для ее решения.
Статья Дейкстры в переводе -