КОДЕКС

Правильный уровень абстракции

Размышления о проблемах создания абстракций в программной инженерии.

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

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

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

Проблема объектно-ориентированных абстракций

Мы частично решили это, установив между ними высокопроизводительный кеш. Однако никто, пишущий высокопроизводительную систему, не может полностью игнорировать поведение этого кеша.

Игровые движки

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

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

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

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

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

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

Но я не хочу вдаваться в подробности здесь. Любой, кто хочет больше узнать о Data-Oriented Design, должен проверить, что говорит об этом разработчик игр Noel: Data-Oriented Design (или почему вы можете стрелять себе в ногу с помощью ООП).

Системы контроля версий

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

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

Итак, Линус Торвальдс - не Бог, и нам не следует принимать все, что он говорит, как евангелие, но стоит прислушаться к тому, что он говорит, поскольку он добился большого успеха. Ядро Linux было не просто случайностью. Система контроля версий Git также продолжала доминировать в отрасли. Я не думаю, что вам удастся добиться такого успеха дважды, если у вас нет основных идей, к которым стоит прислушаться.

Если вам нужна VCS, написанная на C ++, поиграйте с Monotone. Действительно.
Они используют «настоящую базу данных». Они используют «хорошие объектно-ориентированные библиотеки».
Они используют «красивые абстракции C ++». И, откровенно говоря, в результате всех
этих дизайнерских решений, которые кажутся так привлекательными для некоторых специалистов по CS, в конечном
результате получается ужасный и непреодолимый беспорядок.

Это то, что всплывает, когда я думаю об управлении памятью, поскольку создатели Git для Java столкнулись с некоторыми серьезными проблемами при настройке производительности. Шон О. Пирс, один из разработчиков JGit, заметил:

JGit борется с отсутствием эффективного способа представления SHA-1.
C может просто сказать «unsigned char [20]» и встроить его в выделение памяти контейнера
.

Разработчики извлекли уроки из этого, поэтому новые языки, такие как Rust и Go, позволяют вам делать такой выбор.

Сети

Если вы какое-то время работали в этой отрасли, то, несомненно, в какой-то момент слышали о CORBA. Еще в 90-е это было в моде. Вы можете создать объект на одном компьютере и «продавать» их, чтобы сделать их доступными и вызываемыми на другом компьютере. Таким образом, я мог иметь ссылку на объект на моей машине, который фактически жил на другом компьютере, и вызывать на нем методы, как если бы это был локальный объект. Звучит неплохо, правда?

Вот только это была ужасная идея. Сети бесконечно медленнее, чем ваша собственная память. Абстрагироваться от местоположения объекта - ужасная идея. Вы никогда не должны использовать объекты, игнорируя, являются ли они локальными или удаленными. Не говоря уже о том, что большинство языков на самом деле не были созданы для CORBA.

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

Конечно, люди, влюбленные в чрезмерную инженерию, не остановились, когда CORBA разбилась и сгорела. Я убежден, что они переработали этих ребят для создания SOAP. Хорошо, я никогда не изучал ни одной из этих технологий. Но мне кажется, что SOAP - это попытка воспроизвести ошибки CORBA с помощью XML. Вызов удаленных процедур может быть выражен в виде сложных XML-документов.

Точно так же, как люди в 90-х годах, кажется, думали, что объектно-ориентированное программирование было решением каждой проблемы, позже были люди, которые, казалось, думали, что XML был решением каждой проблемы. Итак, у нас есть такие вещи, как SOAP, DocBook и еще много чего.

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

Что для нас делали абстракции?

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

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

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

Иногда это происходит спонтанно, постфактум. К старым мэйнфреймам мы подключили то, что по сути было машинами для написания механических шрифтов (телетайпов), и отправляли нажатия клавиш по последовательному кабелю. Сегодня это наследие живет на моем Mac в виде Terminal.app. Он имитирует поведение этих старомодных машин. Что касается команд ls и cat, они по-прежнему взаимодействуют с электромеханическим пишущим устройством через последовательный интерфейс. Но с помощью программного обеспечения мы их обманули. Таким образом, старое программное обеспечение продолжает работать, несмотря на то, что мира, в котором оно возникло, больше не существует.

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

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

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

Текстовые протоколы также показали себя действительно надежными. Был бы HTTP таким огромным успехом, если бы это был бинарный протокол? Я сомневаюсь.

Какова ваша позиция?

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

Я никогда не любил CORBA, когда видел ее. SOAP тоже никогда не любил. Оказалось, что мое чутье на эти технологии было правильным. И речь не идет о доступе к хрустальному шару или удаче. Эти технологии потерпели неудачу по очень простым причинам: они были слишком сложными.

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

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