Миф о «простом языке для непрограммистов»

+7 926 604 54 63 address

«Мы сделали язык, на котором смогут писать программы даже те, кто не умеет программировать».

В 99% случаев за этой фразой скрывается не более чем оправдание для плохо задизайненного языка. И от того, чтобы написать «100%», меня удержало только то, что я не все случаи в истории видел, поэтому, мало ли — надо дать миру шанс.

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

Тут вся штука в том, что очень многие путают «язык, у которого очень мало команд» с «языком, на котором легко писать программы» или с «языком, на котором легко научиться писать программы». На самом деле, всё обстоит чуть ли не с точностью до «наоборот»: язык, у которого очень мало команд, крайне сложен и в освоении, и в использовании.

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

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

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

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

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

Ну да ладно, чтобы стало понятнее, перейдём к примерам.

Есть у нас крайне актуальная жизненная задача: покрасить все шарики из вон того ящика в красный или зелёный цвет. Выбирая один из двух цветов наугад.

Вот каким образом это записывается на аналогах этих самых «языков для непрограммистов».

  1. Считаем, сколько шаров в ящике, и запоминаем это значение
  2. Если в ящике ноль шаров, то переходим на п.11.
  3. Заведём счётчик.
  4. Запишем в него 1.
  5. Возьмём из ящика шар с порядковым номером, соответствующим текущему значению счётчика.
  6. Подбросим монетку.
  7. Если выпала решка, то красим шар в красный цвет.
  8. Если выпал орёл, то красим шар в зелёный цвет.
  9. Увеличим значение счётчика на 1.
  10. Если оно всё ещё не равно количеству шаров в ящике, то перейдём на п.5.
  11. Конец.

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

  1. Решка означает красный цвет, орёл — зелёный.
  2. Для каждого шара в ящике сделаем вот что: кинем монетку и покрасим шар в тот цвет, который нам показала монетка.

Ну и какой вариант вам проще понимать? Специалист вы или нет — однозначно второй.

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

Как перебрать шарики? Ну, OK, опишем способ перебора элементов.

Однако все эти вещи тоже абстрагируются: мы описываем их решение один раз, а потом уже просто пользуемся им так, будто оно всем известно. Своеобразная компьютерная математика таким образом превращается во что-то, гораздо более привычное мозгу человека. Как, в данном случае, например, некие неясные неспециалисту счётчики и извлечение по порядковому номеру, превратились в понятную операцию с множеством: «сделать вот это вот для всех шаров из этого ящика».

Ведь именно так люди друг другу говорят, нет? «Помой тарелки в раковине». Без счётчиков и так далее. И почему-то все неспециалисты в программировании отлично понимают, что им предложили сделать.

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

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

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

И нет, неспециалистам так совершенно точно не проще. Ведь вам совершенно точно не будет проще с тем, кто не понимает, что значат слова «со всеми шариками в ящике мы что-то там сделаем» или «помоем всю посуду в раковине».

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

Ну ладно, хотя бы второе: ведь всё-таки легче один раз объяснить человеку, который не в курсе, что означает «сделать вот это вот с каждым элементом множества», нежели каждый раз описывать, каким образом надо со счётчиком наперевес брать тарелку номер один, потом тарелку номер два, а до того посчитать, сколько там всего тарелок, чтобы на нужном значении счётчика остановиться.

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

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

Разработчики же вышеупомянутых «простых языков для неспециалистов» упорно, раз за разом, создают ущербный инструмент, при помощи которого предлагается решать каждую задачу «с нуля», описывая её решение чуть ли не на самом низком и приближенном к «внутреннему компьютерному языку» уровне. Что, разумеется, не просто сложнее, а чаще всего вообще невозможно — ничей мозг с таким просто не способен справиться. Он ещё как-то более-менее способен выразить на внутреннем компьютерном языке что-то относительно простое и короткое — пусть даже с серьёзными затратами времени — но если оно длинное и сложное, то без абстракций уже никуда.

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

Называется он «Машина Тьюринга».

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

Для головки можно задать правила, такого типа:

  1. Изменить состояние машины, каждое из которых является, по сути, просто неким идентификатором.
  2. На основании того, что записано в данной ячейке и текущего состояния, сместиться на определённое количество ячеек назад или вперёд.
  3. На основании того, что записано в данной ячейке и текущего состояния, прочитать или записать что-то в ячейку.

При достижении некоторого заданного состояния машина останавливается.

Если бы тезис о том, что язык с наименьшим количеством команд является наиболее простым для неспециалистов, был бы верен, то Машина Тьюринга уделывала бы в этом плане все языки мира.

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

Ну, точнее, самым сложным из тех, которые не пытались придумать с заранее заданной целью: «быть ещё более сложным в использовании, чем Машина Тьюринга».

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

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

Хотя, казалось бы, всего ничего команд — очень быстро можно всё выучить.

Примечание

Статья вдохновлена вот этой странной лекцией: https://youtu.be/MFPqCqcv7kY.

.
Комментарии