Не просто играйте на своем телефоне, а пишите для него программы!
На своем курсе я немного учу программированию, поскольку считаю, что человеку осведомленному важно узнать об этом хоть немного – главным образом то, что порой удивительно тяжело заставить даже простые программы работать как положено. Чтобы преподать такой урок, нет ничего лучше, чем поручить студентам сразиться с компьютером – и они испытают прекрасное чувство достигнутой цели, когда их проект заработает в первый раз. Полезно также иметь достаточный опыт в программировании, чтобы насторожиться, если кто-то говорит, что писать код просто или что в какой-нибудь программе нет ошибок. Если вы целый день корпели над десятью строчками и едва добились нужного результата, то с обоснованным скептицизмом отнесетесь к утверждению, что приложение из миллиона строк будет завершено вовремя и без единого недочета. С другой стороны, бывают случаи, когда полезно знать, что не все задачи в программировании сложны – например, при найме консультанта.
Существует целая тьма языков. Какой из них вам следует изучить в первую очередь? Если вы хотите написать программу для своего телефона, как призывал нас президент Обама, вам понадобится Java для Android или Swift для iPhone. Оба этих ЯП могут освоить новички, но они сложны для повседневного использования, да и в создании кода для смартфона много нюансов. Scratch, система визуального программирования от МТИ, очень хороша для детей, но на ней невозможно писать крупные или сложные программы.
В этой главе я кратко расскажу о двух ЯП – JavaScript и Python. Оба широко используются как профессиональными программистами, так и любителями. Они просты в освоении на начальном уровне, широко применимы и масштабируемы при создании более крупных программ.
Язык JavaScript включен в каждый браузер, поэтому никакое ПО скачивать не нужно. Написав программу, вы сможете использовать ее на собственных веб-страницах, чтобы показать друзьям и родственникам. Сам по себе язык простой – даже при скромном опыте работы на нем можно создавать шикарные штучки – и в то же время удивительно универсальный. Почти каждая веб-страница включает в себя что-нибудь на JavaScript, и эти строки можно изучить, просматривая ее исходный код в браузере. Правда, чтобы найти нужный пункт, вам придется полазить в паре меню: браузеры усложняют поиск, хотя этого не должно быть. С помощью JavaScript поддерживаются многие эффекты веб-страниц, включая средства Google Docs и аналогичных программ из других источников. JavaScript также служит языком для API, на таких веб-сервисах, как Twitter, Facebook[50], Amazon и так далее.
Впрочем, у JavaScript есть и недостатки. Некоторые элементы языка неудобны, и порой проявляется неожиданное поведения. Браузерные интерфейсы не так стандартизированы, как хотелось бы, поэтому в разных браузерах программы не всегда ведут себя одинаково. Но на уровне, интересном для нас, это не проблема, и даже для профессиональных программистов ситуация улучшается.
Программы на JavaScript обычно запускаются как часть веб-страницы, хотя все чаще их можно выполнять вне браузера. Если вы используете JavaScript с браузером в качестве хоста, необходимо немного изучить HTML (Hypertext Markup Language[51]) – язык для описания макета веб-страниц. (Мы мельком рассмотрим его в главе 10.) В общем, есть незначительные сложности, но все же стоит постараться и немного изучить JavaScript.
Другой наш язык – Python. Он отлично подходит для повседневной разработки программ в громадном диапазоне областей применения. За последние несколько лет Python стал стандартным языком для вводных занятий по программированию, а также для курсов по аналитике данных и машинному обучению. Хотя прежде вам пришлось бы работать с ним на вашем компьютере, сейчас появились веб-сайты, позволяющие запускать программы на Python как веб-сервис. Поэтому не нужно что-либо скачивать или изучать, как пользоваться интерфейсом командной строки. Если бы я преподавал курс программирования для людей, которые изучают свой первый ЯП, то выбрал бы именно Python.
Если вы разберетесь в приведенном здесь материале и немного поэкспериментируете, то сможете научиться программировать – по крайней мере, на базовом уровне, – а такой навык стоит того, чтобы им овладеть. Приобретенные вами знания в дальнейшем облегчат изучение других языков. Если вы хотите копнуть глубже или узнать еще чье-либо мнение, найдите в интернете учебные пособия по JavaScript или Python. Вы получите длинный список полезных сайтов, включая Codecademy, Khan Academy и W3Schools, которые обучают программированию полнейших новичков.
Несмотря на все вышесказанное, ничего страшного, если вы пролистаете эту главу, не обращая внимания на подробности синтаксиса. Для понимания других тем они не важны.
7.1. Принципы языков программирования
Языки программирования разделяют определенные базовые принципы, потому что все они представляют собой описания вычислений в виде последовательности шагов. В каждом ЯП есть методы для того, чтобы считывать входные данные, выполнять арифметические операции, хранить и извлекать промежуточные значения в ходе расчетов, решать, как продолжить процесс на основе предыдущих вычислений, отображать промежуточные результаты во время работы и сохранить итоговые по ее окончании.
ЯП имеют синтаксис — правила, которые определяют, что грамматически допустимо, а что нет. Языки программирования придирчивы к грамматике: вы должны всё писать верно, иначе последует жалоба. Кроме того, любой ЯП обладает семантикой, то есть четко определенным значением для всего, что вы можете сказать на конкретном языке.
Теоретически в отношении каждой программы можно однозначно определить, корректна ли она с точки зрения синтактиса, и если да, то какой в нее вложен смысл. К сожалению, этого идеала не всегда удается достичь. Как в любом документе на естественном языке, в программировании все обычно определяется словами – но их определения бывают двусмысленными и могут допускать разную интерпретацию. Кроме того, разработчики ошибаются, а языки со временем развиваются. Соответственно, реализации JavaScript отличаются в разных браузерах и даже в различных версиях одного и того же. Аналогично существует две версии Python, в основном совместимые, но их несхожесть все-таки раздражает. К счастью, вторая версия выходит из употребления: ее заменит Python 3, и эта проблема исчезнет.
Большинство ЯП имеют три компонента. Первый – это сам язык: команды для компьютера, велящие ему выполнить арифметическую операцию, проверить, соблюдаются ли условия, и повторить вычисления. Второй – библиотеки кода, написанные другие людьми, которые вы можете использовать в своей программе. Это уже готовые модули, и вам не нужно их заново составлять. Типичные их примеры – математические функции, календарные расчеты, функции поиска и действий с текстом. Третий компонент – доступ к среде, в которой работает программа. Так, программа на JavaScript, запущенная в браузере, может получать входные данные от пользователя, реагировать на события (нажатие кнопки, ввод текста в форму), а также побуждать браузер отобразить иной контент или перейти на другую страницу. Любой программе на Python предоставляется доступ к файловой системе на компьютере, где она запущена, однако это запрещено программам на JavaScript, работающим в браузере.
7.2. Первая программа на JavaScript
Я начну с языка JavaScript, затем мы перейдем к Python. После изучения JavaScript вам будет легче читать раздел про Python, хотя вы можете пойти в обратном порядке. Как правило, если вы разобрались в одном языке, освоить другие становится легче: вы уже понимаете принципы работы, нужно только выучить синтаксис.
Первая программа на JavaScript максимально короткая: она просто выводит диалоговое окно со словами Hello, world («Привет, мир») при загрузке веб-страницы. Вот полная страница в HTML – с этой разметкой мы еще познакомимся, когда будем говорить о Всемирной паутине в главе 10. Сейчас мы сосредоточимся на одной строчке JavaScript, которая появляется между .
7.3. Вторая программа на JavaScript
Вторая программа на JavaScript будет запрашивать у пользователя имя и выводить персонализированное приветствие:
В этой программе есть новые конструкции и идеи. Во-первых, слово var вводит (или объявляет) некую переменную — место в оперативной памяти, где программа может хранить значение во время работы. «Переменной» она называется потому, что ее значение способно меняться в ходе вычислений. Объявление переменной в языке высокого уровня аналогично присвоению имени ячейке памяти, что мы делали на ассемблерном языке в компьютере-игрушке. Образно говоря, такие объявления определяют действующих лиц, список персонажей в пьесе. Я назвал переменную username, то есть «имя пользователя», что указывает на ее роль в этой программе.
Во-вторых, программа задействует одну из библиотек JavaScript, где определена функция prompt, которая похожа на alert, но ее всплывающее диалоговое окно будет запрашивать у пользователя ввод. Любой текст, напечатанный им, будет доступен программе как значение, вычисленное функцией prompt. Оно присваивается переменной username в строчке:
username = prompt("Как вас зовут?");
Знак равенства «=» означает «выполнить операцию на правой стороне и сохранить результат в переменной, стоящей слева». Похоже на сохранение значения накопителя в памяти компьютера-игрушки. То, как здесь интерпретируется знак равенства, дает нам повод поговорить о семантике. Эта операция называется присвоением, причем «=» здесь означает не равенство, а копирование значения. Большинство языков программирования для присвоения использует знак равенства, пусть даже люди путают его с математическим равенством.
В последней инструкции, alert, используется знак плюс +:
alert("Привет, " + username);
Он соединяет слово «Привет» (а также запятую и пробел) и имя, которое ввел пользователь. Знак + тоже может
сбить с толку, потому что в этом контексте он означает не сложение чисел, а объединение (конкатенацию) двух последовательностей текстовых символов.
Когда вы запускаете программу, prompt выводит диалоговое окно, где вы можете напечатать текст, как показано на рис. 7.2 (в Firefox).
Рис. 7.2. Диалоговое окно, ожидающее ввода
Если вы введете «Джо» и нажмете ОК, то появится окно сообщения (см. рис. 7.3.)
Рис. 7.3. Появление кнопки ОК в диалоговом окне
Довольно просто будет расширить эту программу и создать отдельный ввод для имени и фамилии. В целом есть множество вариантов решений, с которыми можно попрактиковаться. Обратите внимание: если вы наберете «Меня зовут Джо», то в итоговом окошке появится «Привет, Меня зовут Джо». Если вы хотите, чтобы компьютер вел себя умнее, то запрограммируйте его сами.
7.4. Циклы и условия
На рис. 5.6 приводилась версия программы на JavaScript, которая суммирует последовательность цифр. На рис. 7.4 я повторил тот код, чтобы вам не пришлось перелистывать назад.
Рис. 7.4. Программа на JavaScript для сложения чисел
Напомню, что программа считывает числа, пока не будет введен нуль, а затем выводит сумму. Выше мы уже рассмотрели некоторые элементы языка, представленные в этом коде, – объявление, присвоение, а также функцию prompt. В первой строчке объявляются две переменные с именами num и sum, которые будут использоваться в программе. Вторая инструкция задает sum значение О, а третья присваивает num значение, которое пользователь печатает в диалоговом окне.
Затем появляется важный компонент – цикл while, в который входят строчки с 4 по 7. Компьютеры как устройства прекрасно умеют раз за разом выполнять последовательности инструкций, и проблема только в том, как выразить это повторение на ЯП. В языке для Игрушки мы ввели инструкцию GOTO, которая задает переход к другому месту в программе, а не к следующей команде по порядку, и инструкцию IFZERO, выполняющую переход, только если значение в накопителе равно нулю.
Эти концепции появляются в большинстве высокоуровневых языков в командах вида «цикл while», которые обеспечивают более упорядоченный и рациональный метод повторения последовательности операций. Оператор while проверяет условие (прописанное в круглых скобках) и, если оно истинно, выполняет по порядку все выражения между фигурными скобками Затем он возвращается к началу и снова проверяет условие. Этот цикл будет продолжаться, пока условие истинно. Когда оно становится ложным, программа выполняет то, что следует за закрывающей фигурной скобкой цикла.
Такая методика почти точно соответствует IFZERO и GOTO в программе для компьютера-игрушки, описанной в главе 3. Разница только в том, что с «цикл while» нам не нужно придумывать метки, а проверяемым условием может служить любое выражение, которое определяется как истинное или ложное. В данном случае проверяется, не записан ли в переменную num символ 0. Оператор! = означает «не равно»; он унаследован от языка С, как и сама инструкция while.
Сейчас я не уделял внимания типу данных, которые обрабатывают программы из примеров, но в целом компьютеры «внутри себя» четко разделяют числа вроде 123 и произвольный текст, такой как Hello. Одни языки требуют, чтобы программисты тщательно прописывали это различие, а другие пытаются угадать, что имелось в виду. JavaScript ближе ко второй позиции, но иногда необходимо уточнить тип данных, с которыми вы работаете, и то, как интерпретировать значения.
Итак, функция prompt возвращает символы (текст), и затем проверяется, нет ли там буквенной константы О, что задается путем помещения 0 в одинарные кавычки. Без них он воспринимался бы как число.
Функция parselnt преобразует текст во внутреннюю форму, пригодную для операций целочисленной арифметики. Другими словами, эти входные данные обрабатываются как целое число (например, 123), а не как три символа, случайно оказавшиеся десятичными цифрами. Если мы не используем parselnt, то данные, возвращенные функцией prompt, будут интерпретироваться как текст, и тогда оператор + добавит их в конец предыдущего текста. Результатом стала бы конкатенация всех цифр, которые ввел пользователь, что, пожалуй, занимательно, но не совсем то, что нам нужно. В следующем примере, показанном на рис. 7.5, выполняется немного другая работа: поиск наибольшего числа из всех введенных. Это повод представить вам еще одну команду потока управления – if-else, которая встречается в той или иной форме во всех высокоуровневых языках, играя роль способа принятия решения. По сути, это универсальный вариант IFZERO. Версия if-else в JavaScript такая же, как и в С.
Оператор if-else может иметь две формы. У показанного здесь нет части else: если условие в круглых скобках истинно, то выполняются команды, заключенные в { }. И в любом случае далее прогоняются инструкции, которые идут после закрывающей фигурной скобки. Более общая форма оператора содержит элемент else для последовательности команд, которые выполняются, если условие ложное. Далее, независимо от истинности условия, прогоняется инструкция, следующая за if-else.
Возможно, вы заметили, что в программах из примеров используется отступ для выделения структуры. Так, команды, зависящие от while и if, имеют отступ. Данная практика полезна, так как она позволяет с первого взгляда увидеть, насколько широка «зона влияния» операторов вроде while и if, которые управляют другими инструкциями.
Эту программу легко протестировать, запустив ее с веб-страницы, но профессионалы проверят ее заранее. Они будут моделировать поведение кода, мысленно проходя по инструкциям программы по одной за раз, чтобы сымитировать действия компьютера.
Рис. 7.5. Отыскание наибольшего числа из последовательности
Например, попробуйте прогнать в голове последовательности «1, 2, 0» и «2, 1, 0». Можете даже начать с последовательности «О», а затем «1, 0», дабы убедиться, что в простейших случаях все выполняется правильно. Это хорошая практика, помогающая удостовериться, что вы понимаете, как работает программа. Если вы так поступите, то убедитесь, что код дает верный результат для любой последовательности вводимых значений.
Или все-таки нет? Программа отлично работает, если вводится хотя бы одно положительное число. Но что, если все они окажутся отрицательными? Если вы попробуете указать такие значения, то программа всегда будет сообщать, что наибольшее число – это ноль.
Задумайтесь на мгновение почему. Программа отслеживает самое большое значение, которое на данный момент записано в переменной шах (прямо как с поиском самого высокого человека в комнате). Переменная должна иметь некоторое начальное значение до того, как мы начнем сравнивать с ней последующие числа, поэтому, перед тем как пользователь начинает печатать, программа задает значение, равное нулю. Все работает хорошо, если хотя бы одно входное значение больше нуля, как в случае с ростом людей. Но если пользователь задает только отрицательные числа, то программа не выводит самое большое из них. Она отображает первоначальное значение max, которое никогда не обновляется.
Эту ошибку легко устранить. Я покажу одно решение в конце обсуждения JavaScript, но вам тоже будет полезно подумать, как все отладить.
Данный пример также показывает важность тестирования. Для него требуется нечто большее, чем просто ввод случайных значений в программу. Хорошие тестировщики тщательно поразмыслят, что может пойти не так, включая странные или недопустимые входные данные, «пограничные» или «предельные» случаи – например, отсутствие данных или деление на ноль. Они не упустят и вероятность того, что будут введены только отрицательные числа. Но проблема в том, что по мере разрастания программы станет намного труднее продумывать все тестовые случаи, особенно если нужно учитывать участие людей, которые склонны задавать случайные значения, причем неопределенное количество раз и безо всякого порядка. Идеального решения не существует, но не помешает тщательно проработать и реализовать программу, а также с самого начала включить в нее проверки согласованности и работоспособности. Тогда, если что-то пойдет не так, программа наверняка обнаружит это сама и на ранней стадии.
7.5. Библиотеки и интерфейсы JavaScript
JavaScript играет важную роль как механизм расширения для сложных веб-приложений. Хороший пример – Google Maps. Язык предоставляет библиотеки и API, поэтому операции с картами могут задаваться программами JavaScript, а не только щелчками мыши. Таким образом, кто угодно может написать на JavaScript код для отображения информации на карте от Google. API прост в использовании: например, код на рис. 7.6 (если добавить несколько строчек HTML и ключ авторизации от Google) показывает место на карте (рис. 7.7), где, возможно, какой-нибудь читатель однажды поживет несколько лет.
Как мы увидим в главе 11, в интернете отмечается тенденция все больше использовать JavaScript, в том числе с программируемыми интерфейсами, как у Google Карт. Один из недостатков здесь – сложность защиты интеллектуальной собственности. Ведь если вы используете JavaScript, то обязаны раскрывать исходный код. Любой желающий может заглянуть в браузере в ИК страницы.
Рис. 7.6. JavaScript-код для использования Google Maps
Рис. 7.7. В такой перспективе выглядит скромно, да?
Порой код в JavaScript делают запутанным – то ли намеренно, то ли пытаясь добиться компактности, чтобы он загружался быстрее. И в результате код становится совсем непостижимым, если вам не хватает решимости, чтобы разобраться.
7.6. Как работает JavaScript
Вспомните описание компиляторов, ассемблеров и машинных команд в главе 5. Программа на JavaScript преобразуется в исполняемую форму аналогичным образом, однако подробности существенно отличаются. Когда браузер встречает код JavaScript на веб-странице (например, увидев тег