Итак, вы хотите стать программистом! Ну, может быть, не быть одним, а просто делать что-то. С чего начать? Это место. Здесь мы рассмотрим программирование с точки зрения полного новичка, не делая никаких предположений о том, что вы, возможно, уже знаете. В наших упражнениях мы сосредоточимся на интерфейсной веб-разработке в Typescript, также известной как создание веб-страницы. Попутно мы рассмотрим некоторые исторические истоки программирования и то, как они сегодня влияют на его ограничения и возможности. Вы готовы? Давайте начнем!

Мой ребенок работает на компьютере

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

Давайте уберем их с дороги:

  1. Настройка и сборка оборудования.
  2. Настройка программного обеспечения.
  3. Проектирование сетей.
  4. Проектирование программного обеспечения на бумаге в виде набора идей (архитектуры).
  5. Использование программного обеспечения любого типа, в том числе подключение различного рода.
  6. Решение проблем с компьютером и техническая поддержка.
  7. Техническое письмо.

Если это не программирование, то что? Под программированием понимается конкретный акт написания кода, который в конечном итоге будет работать на определенном оборудовании. Мы подробно рассмотрим, как выглядит этот код и как он работает, но достаточно сказать, что если вы не пишете код, вы не программируете. Вот почему программисты называют друг друга кодерами, а нашу работу кодированием. Вы еще услышите термин devs, сокращение от разработчики программного обеспечения.

Итак… сейчас сколько программистов вы знаете? Вероятно, очень мало. Оказывается, программирование — это что-то вроде редкой профессии. Только около 2% населения США занято программированием, и менее 1% могут делать это хорошо. Программирование также неблагодарная работа, полная поломок, исправления ошибок и сопутствующих жалоб клиентов, в то время как похвала и признание редко слышны, если вообще слышны.

Где я могу зарегистрироваться?

Если это так ужасно и сложно, то почему кто-то этим занимается? Одной из причин, безусловно, являются деньги. Программирование всегда входит в число самых высокооплачиваемых профессий, конкурируя с юристами и врачами за первое место по доходам. Но это не настоящая привлекательность для большинства программистов. Привлекательность программирования в том, что оно предлагает неограниченные возможности — небесные замки, как я подумал об этом в детстве. Правда разработки программного обеспечения заключается в том, что с помощью программного обеспечения можно сделать абсолютно все. Нет никаких ограничений. Сколько работ вы знаете, которые могут сказать это?

Мы можем убедиться, что это правда, просто оглядевшись вокруг. Программное обеспечение поглотило мир. Это во всем, от сельского хозяйства и энергетики до транспорта и видеоигр. Даже новые формы жизни создаются с помощью CRISPR, а мРНК-вакцины собираются с помощью программного обеспечения. Если вы станете программистом — на любом языке и на любой платформе — этот безграничный мир откроется вам полностью. Это довольно головокружительная вещь!

Все компьютеры эквивалентны

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

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

Пытаясь обобщить совершенно новую идею вычислений, Тьюринг выдвинул теорию о физической машине, которая могла бы выполнять лишь крошечный набор физических операций:

  1. Проделайте отверстие в бесконечной бумажной ленте.
  2. Перейти к другому месту на ленте.
  3. Узнайте, было ли в этом месте пробито отверстие.

Машина Тьюринга была всего лишь умственным упражнением, и ее не нужно было строить. Вас бы удивило, если бы вы узнали, что бумагоделательная машина Тьюринга может также запускать космический шаттл и играть в Forza? Это могло бы.

Почему же тогда никто не пытался совершать видеозвонки или создавать автомобили с автоматическим управлением с помощью компьютеров 1960-х годов? Причина сводится к двум различиям между любыми двумя машинами, полными по Тьюрингу:

  1. Как быстро они бегают и…
  2. Насколько легко их программировать.

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

Много мигающих огней

К счастью, вместо физических машин Тьюринга компьютерная индустрия уже к 40-м годам была одержима идеей создания цифровых компьютеров. Вместо бумажной ленты для хранения данных и инструкций эти машины будут удерживать напряжение (или нет) в электронной схеме. Вы можете думать об этих напряжениях как об ударах по бумаге. Если в ленте присутствует дырка, в цепи присутствует напряжение. Если нет, то нет. Реальные кремниевые схемы, выгравированные во всех компьютерных чипах, имеют именно такую ​​конструкцию под капотом.

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

Вход Процесс Выход

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

  1. Появляется некоторый вход. Это может быть от набора текста или от некоторых сохраненных данных.
  2. Происходит какой-то процесс, например, выполнение математических действий или другого алгоритма.
  3. Вывод куда-то поступает — например, на дисплей, динамики или другой процесс.

Современные операционные системы позволяют выполнять эти шаги, не беспокоясь о том, как появляются входные данные или куда поступают выходные данные. Собственно, в этом и заключается цель операционных систем. Например, когда программист пишет приложение для Windows, он или она позволяет Windows обрабатывать части ввода и вывода, так что программисту приложения это не нужно.

Это также является причиной того, что разные операционные системы несовместимы друг с другом. Даже если две машины имеют один и тот же процессор, каждая операционная система будет по-разному обрабатывать ввод и вывод. Вот почему настольные программы, написанные для Windows, не могут работать на Mac без существенных изменений в их коде — и почему приложения для iPhone из App Store не будут работать на телефоне Android.

Одометр и почтовый ящик

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

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

Именно такие дисплеи мы видели на старых кассовых аппаратах. Кассиру не нужно следить за общей суммой — она отображается на дисплее, «перекатываясь вперед» каждый раз, когда вводится цена товара. Нажмите кнопку, чтобы получить 1 доллар, и показания одометра переместятся на 1 вперед. У вас есть купон? Это может откатить одометр назад на 50 центов.

Чтобы превратить кассовый аппарат в компьютер, мы должны сначала добавить что-то еще к набору схем: хранилище. Мне нравится думать о хранилище как о наборе почтовых ящиков (или закутках из моего 70-летнего детства). Что мы можем сделать с этими почтовыми ящиками? Мы можем сохранить значения с одометра!

Если продуктовому магазину нужно отслеживать покупки 20 человек, ему потребуется 20 почтовых ящиков, по одному на каждую сумму. Начиная с суммы первого клиента в первом почтовом ящике, компьютер может перейти к «следующему почтовому ящику» после того, как клиент заплатит. Когда все клиенты заканчивали расплачиваться, их индивидуальные итоги все еще оставались в почтовых ящиках.

Общий итог

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

Это не только общая сумма покупок в магазине, но и общая сумма вычислений, потому что это все, что нам нужно для работы компьютера. Если мы дадим себе еще несколько одометров и еще несколько закутков для работы (и дадим этим частям настоящие названия), у нас будет схема каждого современного компьютера!

Одометры аналоговых компьютеров на самом деле называются регистрами, а почтовые ящики известны как места хранения. Вы можете видеть, что с несколькими дополнительными регистрами и гораздо большим количеством мест хранения мы можем легко выполнять более сложные вычисления. Если любой регистр может обращаться к любому месту хранения как для чтения, так и для записи, мы можем написать программу любой сложности, ограниченную только объемом памяти, который у нас есть.

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

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

Почему мы не можем просто вводить текст прямо в файл на диске? Фундаментальное ограничение процессора заключается в том, что он может воздействовать только на данные, которые находятся в его памяти, с которой он физически связан на кремниевом уровне. Любые данные, которые находятся в других типах хранилища, должны быть загружены в эту память, прежде чем можно будет начать обработку. Точно так же для сохранения любые данные, которые находятся в памяти, должны быть записаны во внешнее хранилище, если они хотят сохраниться при перезаписывании при загрузке новых данных в то же место или при отключении питания. .

Обратите внимание, что регистры, ячейки памяти и дисковые накопители имеют собственную схему адресации. Чтобы переместить данные из Location 2 в Drive 1 в Location 1 в памяти, мы должны написать правильный адрес как для исходного, так и для целевого местоположения.

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

Аналогичная проблема возникает при адресации ячеек памяти. На самом деле физическая память состоит из строк, называемых banks, и столбцов, называемых адресами или смещениями. Но кто хочет попытаться отследить это? Было бы намного лучше, если бы мы могли обозначать ячейки памяти именем, а не двумя длинными числами. Тогда мы могли бы сказать в нашей программе: «Переместите значение из Susan’s «почтовый ящик» (память) в Steven’s. Или: «Вычтите 10% из значения в Marty’s ячейке памяти».

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

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

Больше, чем слова

До этого последнего примера информации о сотрудниках мы обсуждали только использование регистров или хранилищ для отслеживания чисел. Но что, если мы хотим обработать данные другого типа, например текст, из которого состоит сотрудник name или email? Как можно изобразить буквы и слова (или астероиды) на вращающемся одометре? Ответ заключается в том, что они не могут.

Чтобы перейти от необработанных чисел к буквам и словам, нам нужен своего рода шифр, таблица преобразования, в которой каждое число соответствует одной букве. Тот, который мы используем сегодня, называется Юникод. Из-за долгой и красочной истории, которую я не буду подробно описывать здесь, код Unicode для заглавной буквы A65. Буква B — это 66 и так далее. Таким образом, все глифы, используемые в языках мира, перечислены в Unicode.

Это просто, как я вижу это

Мы сказали, что в Юникоде число 65 представляет букву «А». Но очевидно, что это также представляет собой фактическое число 65, например, когда мы суммировали покупки этих клиентов на кассе. Мы не хотим, чтобы чья-то покупка на сумму 65 долларов США отображалась как $A в квитанции. Точно так же, если они бросят шоколадный батончик за два доллара, мы не хотим пытаться добавить 2 к букве «А».

На практике число 65 может появляться в самых разных контекстах. Это может быть температура субботним утром в Санта-Крузе или яркость красного пикселя в RGB-дисплее вашего монитора. Важным выводом является то, что на чистом металле реально только число 65 — потому что оно где-то сидит на одометре. Всякий раз, когда мы имеем дело с компьютерными значениями, правильное получение значения — это половина дела, а правильная интерпретация — вторая половина. Базовое оборудование понятия не имеет о том, что вы намеревались; это может дать вам только 65.

Операторы и операнды

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

Каждая инструкция делится на оператор и операнд (произносится как А-мур-и). Оператор говорит что делать, а операнд говорит что делать. Если бы мы пытались добавить значение в хранилище в регистр (очень распространенная операция), оператор добавить, а операнды — имя регистра и адрес места хранения.

Скачок к программируемости

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

  1. Набор ячеек памяти для хранения данных.
  2. Список операций, которые процессор может выполнять со значениями в памяти.
  3. Набор устройств ввода, которые заставляют данные появляться в памяти.
  4. Набор устройств вывода, которые отображают значения из памяти.

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

Единственный аспект работы с этим оборудованием, который мы не описали, — это кодирование инструкций, которые заставляют процессор делать что-то полезное. Поскольку каждое семейство процессоров или микросхем имеет свой собственный встроенный набор инструкций, языки программирования были изобретены Джоном Бэкусом в 1948 году, когда он представил FORTRAN. FORTRAN и последующие за ним языки позволяют нам «написать один раз, запускать где угодно» и создавать программы, которые работают на различных аппаратных процессорах.

Компиляторы и интерпретаторы

Чтобы перейти от операторов языка программирования, которые мы пишем на Typescript (или FORTRAN), к фактическим операторам машинного языка, записанным в микросхему, должен произойти некоторый перевод. Этот этап преобразования известен как компиляция, а программное обеспечение, которое выполняет эту работу, называется компилятором. Независимо от того, на каком языке мы пишем или когда мы вводим наш код, этот шаг компиляции должен быть выполнен.

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

Не имея обзора всей программы сверху вниз, интерпретаторы обычно не могут предложить такого рода оптимизации — поэтому большинство знакомых нам программ, таких как Microsoft Word или Photoshop, компилируются. Однако на практике современные интерпретаторы оказались почти такими же быстрыми, как и компиляторы.

JavaScript и его двоюродный брат из будущего Typescript — это интерпретируемые языки, которые запускаются в браузерах, таких как Chrome, Safari или Firefox. Каждый раз, когда вы открываете окно браузера, вам доступен интерпретатор JavaScript с собственным набором языковых операторов, которые позволяют нам работать с данными в памяти и хранилище. Именно эту среду мы будем использовать для изучения программирования.

Как дела, док?

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

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

Как всегда, спасибо, что присоединились ко мне!

— D