(и предложение сделать это проще)

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

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

10100100 à 00000000

Программа может выглядеть так:

Если вы прочитали 0, переместитесь на одну позицию вперед.

Если вы прочитали 1, напишите 0 и переместитесь на одну позицию вперед.

Сделайте это восемь раз, затем остановитесь.

Большинство современных компьютеров считывают более длинный сегмент ленты, чем одну ячейку или один «бит». Четыре бита («полубайт», восемь битов (байт) или более. Количество битов — это «слово», а 32 бита или 64 бита — это обычная длина слова на персональных компьютерах, 128 — на более крупных устройствах.

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

РегистрХ = 00000000.

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

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

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

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

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

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

Ада Лавлейс, считающаяся первым программистом, выразила трудности следующим образом:

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

Конечно, у нее была суперсила:

«Мой мозг — нечто большее, чем просто смертный; как покажет время».

Немногие программисты разделяют способности графини Лавлейс, и проблема ментальной модели остается серьезной трудностью. Фред Брукс заметил это в своей знаменитой статье: «Нет серебряной пули: сущность и случайность в программной инженерии».

«Сущность программного объекта — это конструкция взаимосвязанных концепций: наборов данных, взаимосвязей между элементами данных, алгоритмов и вызовов функций. Эта сущность абстрактна в том смысле, что концептуальная конструкция одна и та же при многих различных представлениях. Тем не менее, он очень точен и детализирован.

Я считаю, что трудной частью [программирования] является спецификация, дизайн и тестирование этой концептуальной конструкции… Конечно, мы все еще допускаем синтаксические ошибки; но они нечеткие по сравнению с концептуальными ошибками в большинстве систем».

Фред Брукс написал в 1986 году. С тех пор проблема ментального моделирования резко возросла.

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

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

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

Это первая причина сложности программирования.

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

Компьютер имеет набор примитивных операций, воплощенных в схемах аппаратного обеспечения.

Операторы, которые вы делаете в своей программе, вызывают выполнение одной или нескольких из этих примитивных операций вместе с «данными», над которыми они выполняются.

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

Бесконечность — опасная вещь, особенно в машине Тьюринга, которая использует конечную последовательность нулей и единиц на бесконечной ленте.

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

Три оператора в примере программы, приведенном выше,

Если вы прочитали 0, переместитесь на одну позицию вперед.

Если вы прочитали 1, напишите 0 и переместитесь на одну позицию вперед.

Сделайте это восемь раз, затем остановитесь.

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

Установите счетчик на ноль.

Если вы прочитали 0, переместитесь на одну позицию вперед и увеличьте счетчик.

Если вы прочитали 1, сотрите ячейку, переместитесь на одну позицию вперед и увеличьте счетчик.

Если счетчик = 8, переместиться на восемь клеток назад.

Сбросить счетчик на ноль.

Если вы читаете ноль (ни единицу, ни ноль), напишите 0, переместитесь вперед на 1 пробел и увеличьте счетчик.

Если счетчик = 8, Стоп.

Та же отправная точка, тот же конечный результат. Две разные программы.

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

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

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

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

Если вам трудно поверить в эту программу бесконечности, рассмотрите пример. Я мог бы написать очень простую программу под названием «Hello World» на любом из нескольких сотен компьютерных языков, которые были изобретены за эти годы. Когда моя программа компилируется в инструкции и операции машинного уровня, выбор и последовательность этих операций будут совершенно другими. Тем не менее, тот же результат — будут отображаться слова «Hello World».

Вторая причина трудности программирования связана с отсутствием каких-либо объективных критериев для выбора «хорошей» и уж точно не «лучшей» программы из бесконечного множества возможностей.

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

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

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

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

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

Есть способ упростить программирование.

Проще говоря:

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

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

Небольшие и простые программы менее уязвимы для ошибок и других несоответствий.

Небольшие и простые программы легко изменить или, благодаря минимальным усилиям, необходимым для их создания, легко и с минимальными затратами заменить.

Большие программы могут быть созданы из меньших программ как компонентов.

Легко сказать, но как именно это возможно?

Подробности о том, как будут опубликованы в последующих сообщениях; но ключом к этому является простое изменение точки зрения.

Вместо:

· сосредоточение внимания на происходящем внутри машины;

· построение фантастических структур — все более сложных и запутанных — в бесконечном, но произвольном пространстве возможностей, которое представлено бесконечной лентой машины Тьюринга;

· попытка невозможного — построение мысленной модели того, что происходит внутри машины.

Наблюдайте за миром вне машины и:

· Используйте простую метафору «люди на работе» (люди могут быть реальными людьми или неодушевленными предметами, которые вы антропоморфизируете) и то, как они индивидуально или коллективно выполняют задачи и достигают целей.

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

· Напишите эту небольшую программу. Разверните его немедленно. Оцените его эффективность и ценность. Изменяйте, адаптируйте и развивайте по мере необходимости.

Конечно, это сложнее, чем представлено — но ненамного.

Существуют принципы и методы разложения мира вне машины; принципы и приемы структурного проектирования программ; и принципы и методы, применяемые к программному коду (инструкции, из которых состоит ваша программа.

Детали относительно тривиальны.

Самый сложный аспект упрощения программирования — это изменение перспективы на сто восемьдесят градусов:

От внутренней части машины к миру в целом.