Привет! Спасибо, что открыли эту вкладку среди множества других, вы молодцы!

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

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

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

Значит, это происходит само по себе? С чего начать?

1. Наследие

В XXI веке мы создаем абстракции над абстракциями, чтобы создать все более сложное программное обеспечение, которое будет работать на машинах, разработанных в 1936 году [¹].

Вы можете подумать, что если ваша платформа достаточно высокоуровневая, например, браузер, JVM, BEAM или среда выполнения Haskell, то оборудование на вас не влияет. О, но это так.

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

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

Единственный способ разработать надежное программное обеспечение - это ЗНАТЬ, КАК ЭТО РАБОТАЕТ. (Здесь и далее термин «S * IT» означает «Системы, помноженные на информационные технологии»)

Это все хрупкое! Вы потеряете мои данные, если предположите, что «резервное копирование на NAS» (среда выполнения на вашем языке → среда выполнения языка C → системный вызов → ядро ​​ОС → кеш страницы → драйвер файловой системы → [весь сетевой стек TCP / IP] → драйвер сетевой карты → сетевая карта → физический транспорт → сетевая карта → драйвер сетевой карты → [весь сетевой стек TCP / IP] → ядро ​​гипервизора (еще одна ОС) → прошивка (еще одна ОС) → страничный кеш → драйвер файловой системы → программное обеспечение RAID → контроллер RAID → прошивка жесткого диска → жесткий диск ) "Просто работает!"

(Я знаю, я пропустил большинство шагов для простоты)

Всем хорошие новости.

Это окупается практически сразу. Вам не нужно тратить бессонные недели, пытаясь отладить потерю сетевых пакетов и проблемы с подключением, если вы знаете, как работает TCP / IP. Вам не нужно переделывать приложение с нуля из-за ложных предположений.

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

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

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

Плохие новости.

Мы должны заставить его работать в программном обеспечении.

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

Хотим мы того или нет, но каждый день мы сталкиваемся с дырявыми абстракциями - часто в форме «ЧТО ?!» [³] И остается «ВАТ ?!» пока мы не будем абсолютно ясны, что происходит. [⁴]

2. Дизайн высокого уровня

Чем больше информации у нас будет, тем лучший дизайн мы сможем создать. Меньшее количество предположений означает меньшее количество итераций, меньше потраченной работы. Если мы уверены, что можем подтверждать идеи на лету, в уме или на бумаге.

Есть только одна проблема: детали мешают дизайну - они мешают нам увидеть общую картину.

Свободный переход между аэрофотоснимком и микроскопическим изображением - ключ к красивому дизайну.

Что такое оперативная память?

Оперативная память - это набор конденсаторов. Заряженный конденсатор - 1, разряженный - ноль. Практически невозможно соединить каждый конденсатор проводом, поэтому они находятся в сети; это позволяет памяти DDR4 иметь 260 контактов вместо миллиардов. Чтобы прочитать или записать значение, адрес преобразуется в столбец и строку. Вы можете настроить тайминги в BIOS: RAS - Строб адреса строки и CAS - Строб адреса столбца - это циклы, необходимые для установки строки и столбца в этой сетке.

Переменная - это абстракция по адресу в ОЗУ.

Имя переменной. Вы называете свои переменные невдохновленными «i» или «counter» вместо того, чтобы запоминать несколько тысяч простых шестнадцатеричных чисел, таких как 0x000076A9834CC4BE.

Тип переменной. Тип говорит, сколько бит читать из памяти и как интерпретировать эти биты. В зависимости от типа двоичное 01000000 может быть числом 64 или символом «@».

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

Вот почему переменная - это адрес в ОЗУ и ничего больше - один и тот же адрес означает совместное владение. Не стесняйтесь делать следующий шаг и предполагать эксклюзивный доступ к данным и полное отсутствие общего состояния - это эффективно исключит из уравнения всю концепцию RAM.

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

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

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

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

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

Я придумал термин «объектно-ориентированный» и могу сказать, что не имел в виду C ++.
~ Алан Кей Компьютерная революция еще не произошла - Keynote, OOPSLA 1997

(Вы можете заменить C ++ здесь на Java или C #, в некоторой степени на Python и JavaScript)

Что такое программа

В конечном итоге программа - это последовательный список инструкций.

Если вы знакомы с языком ассемблера, вы это уже знаете. Это выглядит как:

1. Do stuff
2. Do more stuff
3. Jump to #1 if condition

У нас есть цикл while:

while (condition) {
    do stuff
    do more stuff
}

Операторы GOTO и метка являются удобочитаемыми переходами.
Оператор If-else ”является абстракцией над переходом.
Цикл while - это абстракция над переходом.
Цикл For - это абстракция над переходом.
цикл while.
Цикл Foreach - это абстракция над циклом for.
Switch-case и сопоставление с образцом являются абстракциями над if-else (переходом).
Функция - это абстракция через прыжок.

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

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

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

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

Существует множество способов представления потока управления, и крайне важно, чтобы каждый знал мое личное мнение по этой теме: я считаю диаграммы последовательности UML [5] идеальным представлением исходных проектов.

Блок-схемы [⁴] очень хороши для работы с алгоритмами.

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

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

Важное примечание: как видите, поток управления уже предполагает поток данных. Вот почему данные имеют фундаментальное значение.

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

Плохие программисты беспокоятся о коде. Хорошие программисты беспокоятся о структурах данных и их взаимосвязях.
~ Линус Торвальдс, сообщение в список рассылки Git, 2006–06–27

3. Следующие шаги

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

Всегда спрашивайте «Почему?» и «Как это работает?».

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

В моей профессиональной жизни одно из самых громких «Ага!» моменты, когда я понял, что ядро ​​Linux делают программисты (я тоже люблю программировать!). Так что я могу знать вместо догадываться, когда мне это нужно.

Упражняться

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

Если вы хотите узнать больше о ЦП и низкоуровневом оборудовании, я настоятельно рекомендую «Ускоренный курс по информатике» на YouTube [⁷] (я не аффилирован, мне действительно нравится этот курс)

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

Лучший программист: Часть 2 - Поведение без сожалений

Если вам понравился этот пост, поделитесь им, чтобы другим он понравился.

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

Twitter: @iurii_k (DM открытые)

Ссылки

  1. Компьютерная архитектура в Википедии
  2. Сюрприз в PostgreSQL fsync ()
  3. Ват Гэри Бернхардта »
  4. ПОЧЕМУ за WAT (JavaScript) от Абхинава Сури
  5. Схема последовательности в Википедии
  6. Блок-схема в Википедии
  7. Ускоренный курс информатики на YouTube
  8. Что каждый программист должен знать о памяти