На основе этих «исторических» исходников построены многие современные компьютерные технологии.
Как и любая другая индустрия, сфера компьютерных технологий прошла внушительный путь развития. Благодаря упорной работе программистов прошлого сегодня мы пользуемся высококлассными компьютерами, высококачественными современными графическими интерфейсами, дружелюбными языками программирования и футуристическими веб‑приложениями в реальном времени. Изучение истории приносит удовольствие — весьма интересно наблюдать за поступательным развитием технологий с течением времени. Только подумайте, скольких трудов стоило создать современный самолет — люди прошли огромный путь от одной лишь идеи полета до настоящих летательных аппаратов. Точно так же компьютеры прошли путь от дорогостоящих машин размером с целую комнату до современных и (относительно) недорогих устройств общего назначения.
В свободное время я часто изучаю исходники, доступные в Интернете. Некоторые кодовые базы включают исходные коды популярных современных программных модулей. Кроме того, я нашел несколько впечатляющих архивных хранилищ, которые больше не ведутся как полноценные проекты, но все еще существуют, дабы остаться в памяти следующих поколений как памятники истории информатики.
В этой статье я расскажу о нескольких исторических исходниках, которые способствовали развитию информационных технологий в целом. Мы сможем познакомиться с ними, изучить их и понять, как каждый из этих проектов повлиял на современную компьютерную экосистему и сделал нашу жизнь лучше!
Демонстрационный исходный код проекта World Wide Web (WWW)
Проект WWW предлагает способ обмена информацией через сетевые протоколы, например, через HTTP. В 1989 году Тим Бернерс‑Ли продемонстрировал первую рабочую версию WWW при помощи совершенно новых веб‑браузера и сервера. Тим написал первый веб‑браузер Nexus на языках C и Objective‑C с использованием стандартной библиотеки C и библиотеки графического интерфейса AppKit в ОС NeXTSTEP. Исходный код браузера Nexus можно найти в этом репозитории GitHub. Посмотрите на первую реализацию парсера HTML:
Теперь в нашем распоряжении есть множество полнофункциональных реализаций веб-сервера HTTP — вы даже можете создать свой собственный HTTP-сервер, используя любимый язык программирования. Каков же был первый веб-сервер? Тим Бернерс-Ли продемонстрировал самую раннюю версию WWW с помощью веб-сервера CERN httpd. Исходный код CERN httpd можно найти в этом репозитории.
Протокол HTTP родился благодаря проекту CERN httpd. Сервер генерирует HTTP-заголовки следующим образом:
Исходный код одного из первых компиляторов языка C
Компьютер — это электронное устройство, способное понимать только заранее определенный набор атомарных инструкций, известный как ISA Assembly. Несмотря на то, что программисты прошлого составляли ранние компьютерные программы (например, POP II) на языке Ассемблера, написание такого кода отнимает массу времени. Позднее было введено понятие компилятора и разработаны дружественные человеку языки программирования.
C — один из самых известных компилируемых языков программирования. Мы до сих пор пользуемся C для создания разнообразных программных систем. C, несомненно, является основополагающим языком — почти все базовые компоненты компьютерных экосистем были созданы на нем, так что современные языки программирования вряд ли когда‑нибудь вытеснят C, разве что кто‑то перепишет всю новейшую компьютерную историю на другом языке.
Все знают, что исходники компилятора GNU C можно найти в этом репозитории GitHub, но где лежит самая первая реализация компилятора C? В этом репозитории хранится самый ранний исходник компилятора. Данный компилятор написан не на языке B, а представляет из себя самокомпилирующийся компилятор, написанный на языке C:
Снимки исходного кода ранних проектов Unix
Безусловно, Unix является прародителем всех Unix‑подобных и основанных на Unix операционных систем. Популярные ОС Apple используют Darwin‑XNU. В ядро Darwin включены реализации BSD, взятые из оригинального кода Unix. В свою очередь, Unix‑подобные системы, такие как Linux и Minix, созданы на основе базовых концепций Unix.
Репозиторий unix‑history‑repo GitHub позволяет просматривать фрагменты исходного кода Unix на различных исторических этапах через Git‑ветви. Например, можно ознакомиться с исходным кодом самой ранней версии Unix следующим образом:
Как вы можете видеть, кодовые базы ранних версий Unix состоят из исходных файлов ассемблера PDP-7, но в версии Unix 4 можно найти файлы на языке C. Автор этого хранилища сгенерировал на базе Git историю развития Unix на основе проекта unix‑history‑make.
Мне очень приятно видеть вклад пионеров компьютерных наук в виде Git‑коммитов на GitHub. Например, посмотрите, как на следующем скриншоте указывается, будто GitHub существовал в 1970 году — даже несмотря на то, что это неправда:
Можно даже визуализировать эти коммиты с помощью Gource! (Недавно я создал это видео с помощью Gource).
Первый релиз Linux (v0.01)
Линус Торвальдс создал ядро Linux как свободную и открытую альтернативу операционным системам Unix и Minix. Исходный код Linux можно найти в официальном открытом репозитории на GitHub, но его история начинается с версии 2.6. Первая версия ядра Linux называлась 0.01. Исторические исходные тексты Linux 0.01 можно найти в этом репозитории GitHub.
Несмотря на то, что современная кодовая база Linux кажется сложной для понимания, кодовая база этой версии легко читается, поскольку в ней относительно мало исходных файлов, и она поддерживает только процессоры i386. Посмотрите на минималистичную функцию main в Linux v0.01:
Вначале разработка ядра Linux была всего лишь хобби-проектом Торвальдса, однако теперь миллионы облачных серверов, мобильных и встраиваемых устройств используют ядро Linux в качестве базовой платформы! Даже автомобильные компании используют форки ядра Linux (например, Tesla).
Первый движок JavaScript (Mocha)
После создания WWW люди начали публиковать общедоступные веб‑страницы со статическим содержимым и гиперссылками в рамках концепции Web 1.0. Кроме того, началась активная разработка веб‑браузеров. В одной из версий браузера Netscape Navigator появился новый скриптовый язык, исполняемый на стороне клиента, он позволял придать статичным веб‑страницам динамичность. В первой редакции этот скриптовый язык был известен как LiveScript, но позже автор проекта Брендан Эйх и компания Netscape изменили его название на JavaScript.
Популярные веб‑браузеры поддерживают использование современных API, таких как WebSockets, WebGL, DOM и WebRTC, благодаря существованию JavaScript. JavaScript работает как промежуточный слой между браузером и веб‑страницей и предоставляет разработчикам удобный инструмент доступа к веб‑интерфейсам. Он также помогает программистам снизить нагрузку на сервер, используя для некоторых задач вычислительные мощности клиента.
Репозиторий mocha1995 на GitHub позволяет экспериментировать с первым движком JavaScript в браузере посредством Emscripten. В отличие от сложных исходных кодов современных JavaScript‑движков, исходный код движка Mocha очень прост для понимания.
Посмотрите, как в нем реализована встроенная функция Math.random:
Заключение
Технологии развиваются ежедневно — популярные проекты устаревают и уступают место чему‑то новому. Но крайне важно понимать, что мы изобретаем что‑то новое и делаем свою жизнь лучше только благодаря упорному труду программистов прошлого. Поэтому мы обязаны бережно хранить их потрясающие разработки и позволять грядущим поколениям изучать их. Возможно, через сотни лет новые разработчики смогут использовать то, что подарили нам программисты прошлого, например, язык C, архитектуру Unix, протокол HTTP и многое, многое другое.
Когда вы начинаете изучать новый язык программирования, библиотеку или фреймворк, уделите внимание изучению его внутренних компонентов, истории и зависимостям, тогда вы станете намного лучше разбираться в этой технологии.
Комментарии (15)
NeoNN
00.00.0000 00:00+42И что это даст, пролистывание простыней свичей и ифов?
iig
00.00.0000 00:00+8Ну, как же.. void main() работы самого Торвальдса! Напоминает void setup() в моём скетче для ардуины ;)
Eugeeny
00.00.0000 00:00+1Ничего, обычная сеошная блевота, нужная ради накручивания просмотров рекламы, лайков на медиуме и рейтинга в корпо-блоге
axe_chita
00.00.0000 00:00+3А где исходный код MSDOS 1.1 и MSDOS 2.0? Тоже интересная часть истории:)
AMDmi3
00.00.0000 00:00+2Мне кажется, или в приведенном коде CERN httpd переполнение буфера при попытке раздать файл размером 100 десятичных гигабайт? Такой исторический код надо закопать и никогда на него не смотреть - это совсем другие языки (даже если это C), совсем другие требования, другая экспертиза. По современным меркам это один сплошной антипаттерн.
vadimr
00.00.0000 00:00+5Шедевральная вещь – это исходный код программы-монитора Apple II, написанный Возняком. Я многое в своё время из него почерпнул, разбирая построчно, благо, он был неоднократно опубликован. Например, чтобы пропустить следующую команду размером 2 байта, не тратя ещё 2 байта на минимальную команду перехода, Возняк использовал 1 байт с подходящим кодом команды, который вместе со следующей 2-байтовой командой образовывал безвредную 3-байтовую команду (бывшая команда становилась полем данных новой команды). Так он каждый раз экономил 1 байт за счёт отказа от уровня абстракции ассемблера и работы на уровне голого машинного кода. И весь монитор умещался в ПЗУ размером 2 килобайта (а этот монитор включал набор процедур, как сейчас сказали бы, bios, плюс дизассемблер и собственный командный язык).
iig
00.00.0000 00:001 байт с подходящим кодом команды, который вместе со следующей 2-байтовой командой образовывал безвредную 3-байтовую команду
А можно немного более развернуто? НЯП в эту конструкцию должно быть 2 точки входа, где-то должны быть jmp (ненулевого размера) для перехода?
Мне попадалась интересная конструкция передачи параметров в функцию через PC
call function .data Hello, World\0 // continue execution here
.label function pull ax // вынимаем из стека указатель на Hello, world // обрабатываем строку до \0 // AX теперь указывает на \0, который заодно NOP в 8080 jmp ax
Экономятся инструкции push перед вызовом функции, pull внутри функции, и jmp вместо ret. Но код вперемешку с данными, никаких early return, никакой кроссплатформенности. Удобно передавать только константные zero-terminated строки. Вряд ли это можно ещё где-то использовать.
vadimr
00.00.0000 00:00Например, так вот (это, правда, из соседнего кода, AppleSoft BASIC):
db57: a9 20 OUTSP lda #‘ ’ ;print a space db59: 2c db #$2C ;skip over next line db5a: a9 3f OUTQUES lda #‘?’ ;print question mark ; Print char from A-reg db5c: 09 80 OUTDO ora #$80 ;print A-reg db5e: c9 a0 cmp #$a0 ;control chr? db60: 90 02 bcc LDB64 ;skip if so db62: 05 f3 ora FLASH_BIT ;=$40 for FLASH, else $00 db64: 20 ed fd LDB64 jsr MON_COUT ;ANDs with $3F (INVERSE), $7F (FLASH) db67: 29 7f and #$7f db69: 48 pha db6a: a5 f1 lda SPEEDZ ;complement of speed # db6c: 20 a8 fc jsr MON_WAIT ;so SPEED=255 becomes A=1 db6f: 68 pla db70: 60 rts
Если мы вызываем подпрограмму OUTQUES по адресу $db5a, то загружаем в аккумулятор код вопросительного знака и уходим дальше в подпрограмму печати произвольного символа из аккумулятора OUTDO, которая находится ниже. А если мы вызываем подпрограмму OUTSP по адресу $db59, то мы загружаем в аккумулятор код пробела, выполняем машинную команду $2c, которая вместе со следующей командой складывается в бесполезную инструкцию тестирования битов bit $3fa9, и опять-таки уходим на код OUTDO. Таким образом, на три точки входа с различными параметрами в печать символа мы потратили всего 5 байтов. Хотя в мнемонике ассемблера мы должны были бы вместо db #$2c поставить двухбайтовый условный переход, например, bne *+2, или даже, рассуждая тупо, трёхбайтовый безусловный – jmp $db5c.
Сам код OUTDO здесь использует подпрограмму монитора MON_COUT для печати символа, но перед этим применяет к коду символа маску, установленному режимами вывода INVERSE и FLASH, а также делает задержку печати, установленную режимом SPEED= (это всё фишки Бейсика).
iig
00.00.0000 00:00Интересный пример байтоложества ;) Сэкономлен 1 (один!) байт в одном месте программы. Конечно, когда в ПЗУ всего 2048 байт, это не лишнее, есть даже шедевральный рассказ про последний байт. Но это не масштабитруется; на ПЗУ в 1МБ 1024 байта экономить будет очень дорого.
Den618
00.00.0000 00:00+2А как же легендарный алгоритм обратного корня из Quake III Arena?
float Q_rsqrt( float number ) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = * ( long * ) &y; // evil floating point bit level hacking i = 0x5f3759df - ( i >> 1 ); // what the fuck? y = * ( float * ) &i; y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed return y; }
amadonus
00.00.0000 00:00В разные времена были разные приоритеты. То на чем экономили 30 лет назад не имеет смысла сейчас.
mOlind
Достаточно посмотреть свой код, который ты писал год, два, три назад. :)