На основе этих «исторических» исходников построены многие современные компьютерные технологии.

Как и любая другая индустрия, сфера компьютерных технологий прошла внушительный путь развития. Благодаря упорной работе программистов прошлого сегодня мы пользуемся высококлассными компьютерами, высококачественными современными графическими интерфейсами, дружелюбными языками программирования и футуристическими веб‑приложениями в реальном времени. Изучение истории приносит удовольствие — весьма интересно наблюдать за поступательным развитием технологий с течением времени. Только подумайте, скольких трудов стоило создать современный самолет — люди прошли огромный путь от одной лишь идеи полета до настоящих летательных аппаратов. Точно так же компьютеры прошли путь от дорогостоящих машин размером с целую комнату до современных и (относительно) недорогих устройств общего назначения.

В свободное время я часто изучаю исходники, доступные в Интернете. Некоторые кодовые базы включают исходные коды популярных современных программных модулей. Кроме того, я нашел несколько впечатляющих архивных хранилищ, которые больше не ведутся как полноценные проекты, но все еще существуют, дабы остаться в памяти следующих поколений как памятники истории информатики.

В этой статье я расскажу о нескольких исторических исходниках, которые способствовали развитию информационных технологий в целом. Мы сможем познакомиться с ними, изучить их и понять, как каждый из этих проектов повлиял на современную компьютерную экосистему и сделал нашу жизнь лучше!

Демонстрационный исходный код проекта World Wide Web (WWW)

Проект WWW предлагает способ обмена информацией через сетевые протоколы, например, через HTTP. В 1989 году Тим Бернерс‑Ли продемонстрировал первую рабочую версию WWW при помощи совершенно новых веб‑браузера и сервера. Тим написал первый веб‑браузер Nexus на языках C и Objective‑C с использованием стандартной библиотеки C и библиотеки графического интерфейса AppKit в ОС NeXTSTEP. Исходный код браузера Nexus можно найти в этом репозитории GitHub. Посмотрите на первую реализацию парсера HTML:

Парсер веб-браузера Nexus обрабатывает HTML anchor (см. источник), скриншот автора.
Парсер веб-браузера Nexus обрабатывает HTML anchor (см. источник), скриншот автора.

Теперь в нашем распоряжении есть множество полнофункциональных реализаций веб-сервера HTTP — вы даже можете создать свой собственный HTTP-сервер, используя любимый язык программирования. Каков же был первый веб-сервер? Тим Бернерс-Ли продемонстрировал самую раннюю версию WWW с помощью веб-сервера CERN httpd. Исходный код CERN httpd можно найти в этом репозитории.

Протокол HTTP родился благодаря проекту CERN httpd. Сервер генерирует HTTP-заголовки следующим образом:

CERN httpd реализует начальную спецификацию HTTP, скриншот автора
CERN httpd реализует начальную спецификацию HTTP, скриншот автора

Исходный код одного из первых компиляторов языка C

Компьютер — это электронное устройство, способное понимать только заранее определенный набор атомарных инструкций, известный как ISA Assembly. Несмотря на то, что программисты прошлого составляли ранние компьютерные программы (например, POP II) на языке Ассемблера, написание такого кода отнимает массу времени. Позднее было введено понятие компилятора и разработаны дружественные человеку языки программирования.

C — один из самых известных компилируемых языков программирования. Мы до сих пор пользуемся C для создания разнообразных программных систем. C, несомненно, является основополагающим языком — почти все базовые компоненты компьютерных экосистем были созданы на нем, так что современные языки программирования вряд ли когда‑нибудь вытеснят C, разве что кто‑то перепишет всю новейшую компьютерную историю на другом языке.

Все знают, что исходники компилятора GNU C можно найти в этом репозитории GitHub, но где лежит самая первая реализация компилятора C? В этом репозитории хранится самый ранний исходник компилятора. Данный компилятор написан не на языке B, а представляет из себя самокомпилирующийся компилятор, написанный на языке C:

Функция main исходного кода компилятора, скриншот автора
Функция main исходного кода компилятора, скриншот автора

Снимки исходного кода ранних проектов Unix

Безусловно, Unix является прародителем всех Unix‑подобных и основанных на Unix операционных систем. Популярные ОС Apple используют Darwin‑XNU. В ядро Darwin включены реализации BSD, взятые из оригинального кода Unix. В свою очередь, Unix‑подобные системы, такие как Linux и Minix, созданы на основе базовых концепций Unix.

Репозиторий unix‑history‑repo GitHub позволяет просматривать фрагменты исходного кода Unix на различных исторических этапах через Git‑ветви. Например, можно ознакомиться с исходным кодом самой ранней версии Unix следующим образом:

Просмотр исходного кода исследовательского проекта Unix, авторская запись экрана
Просмотр исходного кода исследовательского проекта Unix, авторская запись экрана

Как вы можете видеть, кодовые базы ранних версий Unix состоят из исходных файлов ассемблера PDP-7, но в версии Unix 4 можно найти файлы на языке C. Автор этого хранилища сгенерировал на базе Git историю развития Unix на основе проекта unix‑history‑make.

Мне очень приятно видеть вклад пионеров компьютерных наук в виде Git‑коммитов на GitHub. Например, посмотрите, как на следующем скриншоте указывается, будто GitHub существовал в 1970 году — даже несмотря на то, что это неправда:

История развития Unix в виде коммитов Git, скриншот автора
История развития Unix в виде коммитов Git, скриншот автора

Можно даже визуализировать эти коммиты с помощью 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:

Функция main ядра Linux v0.01, скриншот автора
Функция 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:

Реализация встроенной функции Math.random в Mocha, скриншот автора
Реализация встроенной функции Math.random в Mocha, скриншот автора

Заключение

Технологии развиваются ежедневно — популярные проекты устаревают и уступают место чему‑то новому. Но крайне важно понимать, что мы изобретаем что‑то новое и делаем свою жизнь лучше только благодаря упорному труду программистов прошлого. Поэтому мы обязаны бережно хранить их потрясающие разработки и позволять грядущим поколениям изучать их. Возможно, через сотни лет новые разработчики смогут использовать то, что подарили нам программисты прошлого, например, язык C, архитектуру Unix, протокол HTTP и многое, многое другое.

Когда вы начинаете изучать новый язык программирования, библиотеку или фреймворк, уделите внимание изучению его внутренних компонентов, истории и зависимостям, тогда вы станете намного лучше разбираться в этой технологии.

Комментарии (15)


  1. mOlind
    00.00.0000 00:00
    +23

    Достаточно посмотреть свой код, который ты писал год, два, три назад. :)


  1. NeoNN
    00.00.0000 00:00
    +42

    И что это даст, пролистывание простыней свичей и ифов?


    1. iig
      00.00.0000 00:00
      +8

      Ну, как же.. void main() работы самого Торвальдса! Напоминает void setup() в моём скетче для ардуины ;)


    1. Eugeeny
      00.00.0000 00:00
      +1

      Ничего, обычная сеошная блевота, нужная ради накручивания просмотров рекламы, лайков на медиуме и рейтинга в корпо-блоге


  1. axe_chita
    00.00.0000 00:00
    +3

    А где исходный код MSDOS 1.1 и MSDOS 2.0? Тоже интересная часть истории:)


  1. connected201
    00.00.0000 00:00
    +3

    тут надо ещё добавить исходные коды яндекса :)


  1. AMDmi3
    00.00.0000 00:00
    +2

    Мне кажется, или в приведенном коде CERN httpd переполнение буфера при попытке раздать файл размером 100 десятичных гигабайт? Такой исторический код надо закопать и никогда на него не смотреть - это совсем другие языки (даже если это C), совсем другие требования, другая экспертиза. По современным меркам это один сплошной антипаттерн.


  1. Interreto
    00.00.0000 00:00
    +5

    Разработчик никому ничего не должен!


  1. aelaa
    00.00.0000 00:00
    +2

    А где исходники Doom Engine? Безусловный шедевр


  1. vadimr
    00.00.0000 00:00
    +5

    Шедевральная вещь – это исходный код программы-монитора Apple II, написанный Возняком. Я многое в своё время из него почерпнул, разбирая построчно, благо, он был неоднократно опубликован. Например, чтобы пропустить следующую команду размером 2 байта, не тратя ещё 2 байта на минимальную команду перехода, Возняк использовал 1 байт с подходящим кодом команды, который вместе со следующей 2-байтовой командой образовывал безвредную 3-байтовую команду (бывшая команда становилась полем данных новой команды). Так он каждый раз экономил 1 байт за счёт отказа от уровня абстракции ассемблера и работы на уровне голого машинного кода. И весь монитор умещался в ПЗУ размером 2 килобайта (а этот монитор включал набор процедур, как сейчас сказали бы, bios, плюс дизассемблер и собственный командный язык).


    1. iig
      00.00.0000 00:00

      1 байт с подходящим кодом команды, который вместе со следующей 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 строки. Вряд ли это можно ещё где-то использовать.


      1. 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= (это всё фишки Бейсика).


        1. iig
          00.00.0000 00:00

          Интересный пример байтоложества ;) Сэкономлен 1 (один!) байт в одном месте программы. Конечно, когда в ПЗУ всего 2048 байт, это не лишнее, есть даже шедевральный рассказ про последний байт. Но это не масштабитруется; на ПЗУ в 1МБ 1024 байта экономить будет очень дорого.


  1. 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;
    }


  1. amadonus
    00.00.0000 00:00

    В разные времена были разные приоритеты. То на чем экономили 30 лет назад не имеет смысла сейчас.