История IT. Когда компьютеры были большими…
Некоторое время назад меня попросили рассказать или дать ссылки на историю развития IT-разработки, в которой была бы видна внутренняя логика развития, а не просто факты и события. Казалось бы, об этом должны быть книги или обзорные курсы, ведь логика развития IT-разработки в значительной мере овеществлена в логике развития языков программирования, и только в последние лет двадцать к этому добавилась логика развития фреймворков, платформ и концептуальных подходов к проектированию. Но я не нашел хороших источников.
Поэтому появился авторский текст, написанный, преимущественно, на основе моих собственных представлений. Он проверен по материалам википедии — там есть общий таймлайн в серии статей (этот откроется на 1957, наверху можно выбрать конкретный год), есть обзорная статья английская статья, которая, на мой взгляд, не раскрывает логику развития, а говорит о фактах, и есть статьи, посвященные отдельным языкам. Статьи по отдельным языкам как раз включают не только его описание, но и логику создания и развития языка. Но — изолированно от других, и простая сборка не даст целостной картины, а наоборот, будет содержать противоречивые фрагменты. Зато эти статьи позволяют проверить, насколько твои представления соответствуют реальной истории, и поправить их — что я и проделал.
История оказалась интереснее, чем я ее себе представлял. Мне было интересно ее писать и, надеюсь, вам будет интересно ее читать. При этом в статье наверняка осталось много моих собственных интерпретаций, которые не будут совпадать с вашими представлениями, и я буду рад обсудить различия.
Первоначально компьютеры создавались для решения вычислительных задач. Они были исполнительным механизмом вместо человека и просто реализовывали вычисления на конечном рабочем месте.
Что интересно — массовые вычисления выполнялись задолго до компьютеров. Еще в конце 18 века во Франции была построена система, при которой большой коллектив людей разного уровня квалификации, в основном — владеющих только простыми действиями, вычисляли таблицы математических функций с высокой точностью — это было нужно для решения инженерных задач. Потом это система развивалась, и в 20 веке существовали большие счетные бюро, обеспечивающие нужды инженеров и конструкторов во многих отраслях промышленности — строительство, судостроение, авиация, военные и так далее. Но эту историю я рассказывать не готов, хотя и слышал ее в одной из Лекций Петра Щедровицкого по СРТ.
В любом случае, в конце был человек-счетчик, снабженный тем или иным арифмометром. Их-то и хотели заменить компьютером, задача была «сделать то же самое, но без человека как вычислителя».
Для разработки алгоритмов программ использовались Блок-схемы — визуальное графическое представление, показывающее последовательные шаги, циклы и ветвления алгоритма. Статья вики Flowchart говорит, что они были разработаны для представления алгоритмов еще в 1920-х, а 1940-х были использованы фон Нейманом для проектирования компьютерных программ: «Douglas Hartree in 1949 explained that Herman Goldstine and John von Neumann had developed a flowchart (originally, diagram) to plan computer programs». Таким образом, блок-схемы старше компьютеров.
Первые программы писали непосредственно в машинных кодах — командах процессору, который их обрабатывал. Коды отражали конкретную архитектуру машины и развивались вместе с ней. Команда в машинных кодах «прибита гвоздями» к конкретному месту в памяти, где размещается она и ее данные, и эта привязка — наиболее жесткая. Когда ты объединяешь несколько программ для совместной работы, и оказывается, что они занимают одно и то же место в памяти, то одну из них надо переместить. Желательно, без переписывания и проверки ошибок, которые при этом возникают.
Эти задачи решали аппаратно: через команды вызова процедур, регистры для стековой организации памяти и базовых адресов и так далее. А в 1949 появилось программное решение — ассемблер. В нем команды записываются символически с мнемоникой, а не цифрами, программы можно вызывать одну из другой, вместо адресов данных указываются имена переменных и т.п. Это понемногу развивалось и совершенствовалось.
Ассемблер привязывался к конкретной машине и ее архитектуре, и это — проблема: при появлении новых, более совершенных компьютеров наработанные программы перенести было невозможно. В 1954–1957 был разработан Fortran (IBM) — первый язык, отвязанный от железа конкретной ЭВМ.
Назначение Фортрана — программирование вычислений. Поэтому там из структур данных там только числа и многомерные массивы, а работа с символами — минимальна, чтобы написать сообщения человеку. Именно массивы нужны для написания программ по численному решению дифференциальных уравнений и других вычислительных задач. В результате произошел значительный подъем уровня абстракции в представлении программы: раньше формулы преобразовали в программы на ассемблере, а теперь — в программы на Фортране, имеющие значительно более читаемый вид.
Но это побочный, хотя и очень полезный эффект. Главная задача, которая была решена, — это то, что программы на Фортране можно достаточно комфортно переносить между компьютерами. Там есть сложности с различной точностью вычислений и объемами памяти, но по сравнению с ассемблером это значительный шаг вперед: созданное не пропадает с устареванием компьютера.
На Фортране написано громадное количество библиотек, реализующих различные вычисления, он живет, развивается и используется до сих пор. Отметим, что обобщение часто решаемых задач и реализация их в виде процедур, параметры которых задают вариативность реализации алгоритма и позволяют одну и ту же процедуру использовать в разных задачах, и формирование из этих процедур библиотек, которые полностью закрывают потребности какого-либо класса задач, родилось именно тогда. Это дало начало процедурной парадигме программирования.
При выделении процедур очень важна удачная параметризация. Например, при численном решении уравнений каким-либо методом возникает проблема с особыми точками и краевыми эффектами, для которых существуют вариации алгоритмов. И от того, какие вариации будут предусмотрены, зависит область применения процедуры. Фортран в этом смысле беден: в процедуру нельзя передать ссылку на другую процедуру для обработки особых ситуаций, нельзя добавить при доработке библиотеки параметры по умолчанию — все это появилось гораздо позднее, в продвинутых диалектах языка. Сейчас такие задачи решать легче, но удачное обобщение и параметризация по-прежнему остаются частью слабоформализованного искусства программирования.
Развитие компьютеров в конце 1950-х вызвало волну энтузиазма по поводу потенциала создания искусственного интеллекта. Было понятно, что для решения этих задач будет нужен отдельный язык, выполняющий логические выводы — тогда надежды были связаны с таким подходом. Для решения задач искусственного интеллекта в 1955–1956 был создан Information Processing Language, из которого в 1958–1963 развился Lisp (историю можно прочитать в английской статье).
Lisp дал начало функциональной парадигме программирования и декларативному подходу. Из этих подходов позднее выросли декларативные языки логического вывода Planner (1969), Prolog (1973) и другие, и функциональные языки Schema (1975), Haskell (1990) и Clojure (2007).
В 2008 Microsoft, помимо разработки собственного функционального языка F#, включило функциональную парадигму вместе с реляционной в объектный язык C#, положив начало мультипарадигмальным языкам программирования. Но это мы забежали сильно вперед. Вообще соотношению процедурного и декларативного подхода будет посвящена отдельная статья, это — очень интересный и актуальный вопрос.
Фортран обеспечил разработку программ для чисто вычислительных задач, закрыв потребности самого главного заказчика — военных, а заодно и других инженеров-проектировщиков. Однако, у бизнеса были и другие задачи. А главное, они были у самих программистов, они не слишком хотели писать компиляторы и системное обеспечение на ассемблере. А для этого нужна работа со структурами данных, а не просто с числами, и развитая работа с текстами и файлами.
Как и сейчас, программисты не слишком хотели разбираться в бизнес-задачах, поэтому решили придумать универсальное решение — разработать универсальный алгоритмический язык. И сделать это силами всего международного сообщества. Так начал появляться язык Алгол, Algorithmic Language. История рассказана в русской и английской статьях, она прекрасна. Была недельная конференция в 1958, на которой создали стандарт языка, не слишком подумав про реализацию, и сформировали комитет по доработке IFIP. Этот комитет два года делал стандарт приемлемым для реализации, и в результате выпустил стандарт Algol-60.
И только тогда начали появляться первые реализации (список есть в английской статье), причем несколько из них сделаны Дейкстрой. Ряд реализаций был сделан в СССР, годы там не указаны, но в русской статье упоминается Алгол Курочкина для БЭСМ-6, а в его биографии говорят о реализациях для более ранних машин БЭСМ-2, выпускавшихся в 1958–62, так что это тоже было начало 1960-х.
Я, кстати, в институте обучался именно на Алголе Курочкина на БЭСМ-6, который наш преподаватель любил за чистоту и полную реализацию первоначального стандарта, в отличие от более поздней реализации Алгола-68.
Проблема Алгола в том, что это прекрасный универсальный стандарт, невозможный для реализации. Попытки довести Алгол до приемлемого уровня, избавив от излишней сложности, начались сразу после создания привели в 1968 к формированию стандарта Алгол-68. Однако, успеха не было, цитата из вики: «Язык оказался чрезвычайно развитым, но при этом весьма объёмным и сложным. Даже опытные программисты испытывали затруднения в понимании «сообщения о языке», выпущенного комитетом. Официальные документы комитета оценивают проделанную им работу положительно, хотя некоторые из членов комитета высказывались как о работе, так и о её результатах, крайне негативно. Из критиков языка наиболее известны Чарльз Хоар и Никлаус Вирт. Хоар ещё во время работы комитета критиковал проект за «неясность, сложность и сверхамбициозность». По завершении работы комитета Хоар, Вирт и ещё ряд учёных создали небольшой доклад, излагающий критику нового языка. В его резюмирующей части говорилось: «как инструмент надёжного создания сложных программ язык следует признать неудачным» (этот доклад был запрещён к распространению руководством IFIP).»
Долгая работа над универсальным языком Алгол и полуживой первый стандарт вызвали альтернативную ветвь развития языка для разработки бизнес-приложений, которым стал Cobol. История описана в вики, инициатива была академическая, но реализация спонсирована военными из министерства обороны. Разрабатывала стандарт очень компактная рабочая группа, в которую входили производители компьютеров и заказчики. Поэтому получилось очень быстро: первая конференция, на которой высказана идея и получена поддержка была в мае 1959, к декабрю согласован стандарт Cobol-1960, а уже в августе 1960 показан первый работающий компилятор.
На Коболе наработаны большие библиотеки приложений и поэтому он местами используется до сих пор и даже развивается… Такая долгая жизнь Cobol при его многочисленных недостатках непонятна и печалит сторонников «правильных» подходов к разработке, начиная со структурного программирования, появившегося в конце 60-х. Википедия приводит цитату Дейкстры «Использование Кобола калечит ум. Его преподавание, следовательно, должно рассматриваться как уголовное преступление».
Но Кобол был ориентирован на бизнес-приложения, а программистам по-прежнему надо было писать компиляторы и системный софт. Дефицит языка общего назначения привел к появлению в 1964 году языка PL/I, его разработал IBM для своих компьютеров.
Неудача в доработке Алгола вызвала к жизни большое количество альтернативных разработок практического направления. Николас Вирт создал в 1968–70 Паскаль как простую и логичную альтернативу, для целей обучения программированию.
Потребности разработки компиляторов и операционных систем привели к созданию в Bell Labs в 1968–69 языка C (Си) (история). Предшественником Cи был BCPL, используемый для разработки компиляторов, и, что интересно, созданный в 1966 очисткой предшественника CPL (1963) от лишней сложности. Язык оказался крайне удачным, на него переписали ядро UNIX, что обеспечило возможность переноса между машинами ядра операционной системы. В Си появилось динамическое управление памятью и развитая работа с указателями. Язык развивается — C++, С#, и повлиял на все последующие языки.
И в заключении интересно отметить язык BASIC. Он появился в 1964 как сокращенный диалект «для непрограммистов», который дает представление о работе компьютера на низком уровне для вычислительных задач, такой урезанный Fortran. Но его реальный расцвет пришелся на 1970-е, когда появились слабые компьютеры, для которых традиционные языки оказывались слишком тяжелыми, создать компиляторы было невозможно.
Развитие концепций программирования начиналось с проработки императивной реализации алгоритмов базовой алгоритмикой. Эта работа к концу 1960-х в целом завершена выходом первых трех томов фундаментального труда Дональда Крута Искусство программирования (1968–1973). Помимо умения реализовывать алгоритмы, было важно умение выделять схожие фрагменты кода в процедуры, обобщая их и формируя повторно используемые библиотеки. И это формировало процедурный подход к разработке.
Параллельно с этим развивалась функциональная парадигма, о которой я уже говорил раньше, описывая язык Lisp. В основе функциональной парадигмы лежит некоторый математический аппарат, у ее применения есть своя ниша в части обработки тестов, графов и больших объемов данных. Этот математический аппарат позволяет очень эффективно распараллеливать вычисления, а это востребовано.
Работа над Алголом и дальнейшее развитие привели к формированию концепции структурного программирования (по-русски и по-английски). Авторы — Дейкстра и Вирт, идея — ясность логики выполнения алгоритма из кода программы, отсутствие необходимости в дополнительной документации в виде блок-схем. Начало отсчитывают от статьи Дейкстры 1968 года.
Логическим завершением этапа эволюции подходов к разработке софта, начатой Алголом и продолженной другими языками, надо считать работу Николаса Вирта «Алгоритмы + Структуры данных = Программы» (1976), которая фиксирует следующий после алгоритмики Кнута этап развития концепций разработки софта.
В начале 1970-х появилась акторная модель, реализованная в языке Smalltalk (1972), в которой акторы обмениваются сообщениями для оркестрации совместной работы. Это задумывалось для моделирования деятельности, однако в то время возможности компьютеров не позволяли это эффективно реализовать. А сейчас акторная модель — основа архитектуры для высокопроизводительных параллельных вычислений на многих узлах, в том числе реализованная в Erlang.
В 1974, с развитием обработки больших объемов данных, появилась модель реляционных баз данных и язык SQL, реализующий реляционную парадигму программирования. В ее основу лег специальный раздел математики — реляционная алгебра. Что интересно, реляционную алгебру необходимо понимать для реализации движков СУБД, но вот для использования SQL, включая построения сложных запросов, понимание реляционной алгебры вовсе не является необходимым, гораздо проще это объяснять другим образом. К этому я еще вернусь в следующих статьях.
Есть мнение, что во второй половине 1960-х зародился ООП, объектно-ориентированный подход. Однако, статья вики допускает много трактовок. В Алголе объектов (в современном смысле) точно не было, в 1967 скандинавы сделали язык Симула с замечательными концептами, но не слишком хорошей реализацией. Smalltalk с акторной моделью, который авторы статьи также отнесли к ООП, на мой взгляд, представляет собой отдельную ветвь развития. Так что я бы рассматривал все это как предысторию ООП, а историю отсчитывал с языка С++ (1979–1985) (история).
На рубеже 80-х появился не только ООП вместе с языком C++, произошло еще одно принципиальное событие — появились персональные компьютеры. И это принципиально изменило задачи, стоящие перед IT-разработкой. Главное изменение состояло не в том, что появились компьютеры для домашнего использования, и потребовался софт для работы на них: текстовые и графические редакторы, компиляторы и средства разработки, базы данных и игры — это все так или иначе перенесли с больших компьютеров. Вопрос был в оптимизации и адаптации под ограниченные ресурсы. Главное изменение в том, что персоналки сделали компьютеры доступными небольшим компаниям, и потребовались системы автоматизации бизнес-процессов, которые сильно отличаются в разных компаниях, и типовую систему сделать сложно. И как раз эту задачу помог решить ООП. Но об этом мы поговорим в следующей статье.
А в заключении этой я хочу сказать, что мое знакомство с миром больших компьютеров не теоретическое. Основным студенческим компьютером в период моего обучения на Физтехе была БЭСМ-6. Персоналки пришли в СССР, только когда я уже был уже на старших курсах, и основным рабочим языком там был Forex, структурный диалект Фортрана, в котором были добавлены структуры данных и указатели, но не было динамического распределения памяти. Алгол и Паскаль тоже были, но их реализации заставляли желать сильно лучшего по объективным причинам. Алгол — тяжелый, а эффективную реализацию Паскаля сложно сделать на компьютере, где отсутствует побайтовая адресация и команды, все работает с 48-битными словами. И поэтому все эффективные операции со строками надо отдельно писать ассемблере.
Я там занимался системным программированием, это было интересно. Одним из результатов был многопользовательский интерактивный текстовый редактор, который в одном процессе обслуживал до 8 пользователей, редактирующих свои файлы с подключенных терминалов. Потому что на уровне ОС было ограничение на 15 пользовательских процессов, из которых только 6 интерактивных с пользователями, а подключенных терминалов было много больше. Там было много интересных задач: эмуляция потоков и обработка прерываний, управление памятью и так далее. Аналогичные системы были, но ресурсоемкие и с проблемами в эргономике. Поэтому когда редактор написали, то его быстро внедрили и он завоевал популярность, а я ощутил, что такое сопровождение системы, которая иногда сбоит и падает, теряя или портя пользовательские файлы. Несколько лет все это жило, а потом пришли персоналки, и я с большим интересом окунулся в мир разработки на C++.
На этом я завершаю статью. Продолжение следует…