Найти тему
Сделай игру

Магия программного обеспечения

Оглавление

Вы, наверное, уже написали немало строк кода в своей жизни. Или немного - не суть важно: процесс обучению написания кода, зачастую, связан с изучением логических конструкций, на которых работает программа, но практически не касается главного вопроса: почему эти конструкции именно такие? Хочу немного про это рассказать. Не думаю, что открою великие тайны, но для тех, кто не интересовался ранее, надеюсь, будет полезно.

Камень он и есть камень
Камень он и есть камень

О том, как всё сложно

Многие из разработчиков, в той или иной мере, проходили курс связанный с аппаратным обеспечением: pnp-переходы, селекторы, мультиплексоры, транзисторы, триггеры и многое другое было в нём. И хотя большинство из нас знает, что процессор набит транзисторами под завязку, увы, далеко не все понимают, как всё это взаимодействует.

"Гарвардская архитектура", "архитектура фон Неймана" - также довольно известные архитектуры, которые должны что-то сказать про процессор, но если не приходится работать на системном уровне отличия этих подходов не только быстро забываются.

А жаль, потому что именно тут лежит ключ к пониманию того, как вообще работает программирование.

Эволюция

ЭВМ развивались постепенно, всё время уменьшая размеры используемого оборудования. Архитектуры современных компьютеров могут принципиально почти не отличаться от архитектуры старых компьютеров размером с несколько комнат (например, ЕС 1038, это то, на что мне довелось посмотреть, но не поработать), хотя в остальном различия могут быть весьма значительными.

ЕС 1038
ЕС 1038

По сути, эволюция происходила в уменьшении в размерах, но не в принципе действий. Шестерёнки заменялись на реле, реле на лампы, лампы на транзисторы, связки транзисторов на микросхемы, микросхемы компоновались в процессоры с единым корпусом.

Но самое главное оставалось неизменным: подход, который закладывался в основу работы с таким оборудованием. Хочу ещё раз подчеркнуть: та логика (булева алгебра, комбинаторная логика), которая была в основе аппаратного обеспечения почти 100 лет назад используется и по сей день в работе аппаратного обеспечения, а, значит, и в работе программ.

Как программа связана с железом

Очень часто мы используем какие-то особенности языка программирования, до конца не понимая, какие из них - это дань традициям, какие - особенности языка, а какие - необходимость.

Скажем, ссылка на данные - это где? Оказывается, ссылка на данные реализуется на уровне процессора. То есть есть специальная инструкция для большинства процессоров, которая позволяет передать в качестве аргумента не значение, а адрес ячейки памяти и использовать привязанные к ней данные. Чтобы выполнить такую операцию - требуется разместить внутри процессора специальное оборудование (микро-микросхемку), которая способна вот так выбрать данные.

Данное действие можно осуществить и без наличия такой инструкции у процессора, но выполнение программ может сильно замедлится.

То есть, внимание, это важно: большая часть программных финтов, которые мы можем использовать в языках высокого уровня - это не просто программные конструкции, а специальное оборудование, размещённое на кристалле процессора или рядом. И оно, фактически, выполняет эти действия.

Языки высокого уровня

Первое, что надо знать, чтобы создать язык высокого уровня - это то, а как вообще всё работает. То есть нельзя написать язык, не понимая устройства всего набора программно-аппаратных средств, которые будут использоваться "этажом ниже".

Поэтому понимание того, как всё работает почти всегда оказывает сильное влияние на разработчика новых языков: можно добавить много синтаксического сахара, упрощений, общих или новых подходов (как пример - Rust с его моделью управления памятью), но в целом, оторваться от изначальных парадигм нельзя, т.к. они фундаментальны.

Вот и получается, что то, каким является язык программирования, определяется не хотелками разработчика (или команды разработки), а архитектурой аппаратного обеспечения.

Это, вроде бы, логично, но, с другой стороны, у меня раньше часто возникали мысли, что все языки высокого уровня уже перешли на новый уровень абстракций и уже почти никак не связаны с железом, позволяя, благодаря быстродействию современных процессоров, создавать комбинации существующих инструкций для достижения результатов. Усиливало это чувство веб-разработка.

Однако, всё оказалось с точностью до наоборот.

В итоге

Наверное, получилось немного сумбурно, но хочется подытожить:

  • Аппаратное обеспечение, что очевидно, первично в работе приложений;
  • Аппаратное обеспечение долго эволюционировало, но изменялось, скорее, в размерах, нежели принципиально;
  • Аппаратное обеспечение имеет свою собственную логику работы и правила работы;
  • Программное обеспечение подчиняется правилам, которое накладывает аппаратное обеспечение;
  • И этим правилам подчиняются даже языки высокого уровня: они просто добавляют обобщения, абстракции и библиотечные функции для упрощения работы, но в остальном - продолжают следовать указанным правилам;
  • Теоретически, от этого можно, кажется, и отклониться и ровно так же, теоретически, попасть в некоторое абстрактное "ничто".

P.S.

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

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