Большинство тестов языков программирования — это синтетика. Мы сравниваем скорость сортировки массивов, подсчёт аллокаций и другие упражнения, которые почти не встречаются в реальной жизни.
А вот настоящие приложения — редакторы, игры, GUI-интерфейсы, базы данных — живут совсем в другом мире. Они управляют не сырыми числами, а сложными структурами объектов. И если присмотреться, почти все эти структуры сводятся к одной универсальной модели: DOM-подобному графу.
Всё сводится к DOM-у
Откройте любое современное приложение — и вы увидите знакомые сущности и связи.
Игровой движок: сцена, акторы, компоненты иерархически вложенные и перекрестно связанные.
UI-фреймворк: контролы внутри контейнеров, окон, панелей — иерархия и связи.
Редактор документов: страницы, стили, текстовые блоки, абзацы.
MVC, MVVM и прочие архитектуры: модели, представления, контроллеры разложенные по контейнерам и подписанные друг на друга.
Базы данных: записи и документы, вложенные в таблицы и коллекции и связанные ключами.
Разные области, разные названия, но структура одна и та же.
Универсальная форма данных
Если убрать детали, всё сводится к трём уровням:
Дерево владения
Каждый объект принадлежит своему владельцу.
Актор принадлежит игровой сцене, абзац принадлежит тексту, кнопка — форме.
Как узлы в XML или JSON, это дерево определяет, кто контролирует чье время жизни, кто кого удаляет.

Сеть перекрестных ссылок
Реальный мир живет не только деревом. Кнопка ссылается на другую форму. GUI-окно хранит ссылку на сфокусированный элемент. Паттерн издатель-подписка весь построен на слабых перекрестных ссылках между произвольными компонентами. Все эти связи не должны владеть объектами и обязаны безопасно разрываться при их удалении.

DAG неизменяемых ресурсов
Есть еще то, что используется всеми — строки, стили, текстуры, меши, шрифты. Они неизменяемы и переиспользуются без копирования. Они неизменяемы и потому их расшаривание между иерархиями объектов вообще никак не контролируется.
Менять их можно, но только через явное дублирование — классический copy-on-write.

Вот и всё: дерево, сеть и DAG. Эта тройка лежит в основе практически любой организации данных современного приложения.
Как современные языки справляются с этими структурами?
Универсальное тестовое задание
Чтобы сравнить языки честно, нужно одно общее задание. Берём упрощенное приложение — редактор карточек. Вот таких:

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

Пример возможной структуры классов:

Какие операции поддерживаем:
Создание, копирование, удаление документов, карточек в документах и элементов в карточках.
Изменение любых полей любых вышеперечисленных объектов.
Для текстовых стилей - копирование, модификация, перевод некоторых текстовых блоков на модифицированный стиль.
Проход по перекрестным ссылкам с проверкой на не-оторванность.
Удаление карточки из метода элемента этой карточки.
Правила:
Документы, карточки и их элементы должны быть изменяемыми.
Стили и битмапы — неизменяемые ресурсы, разделяемые между текстовыми блоками и картинками.
Любое их изменение должно выполняться через copy-on-write.Удаление любых объектов из иерархии не должно вызывать сбоев — даже если где-то в стеке остались ссылки на них.
Перекрестные ссылки из коннекторов к другим элементам и от кнопок к карточкам должны автоматически обрываться при удалении любого из двух объектов (кто ссылается - на кого ссылаются).
Обращение по оборванной перекрестной ссылке должно контролироваться и пресекаться, но без падения программы.
Копирование карточек и любых их элементов обязано сохранять структуру связей. Например, если копируется карточка, то все коннекторы в копии должны ссылаться на копии оригинальных элементов.
Контроль циклов — группу элементов нельзя вставлять в себя, и в свои подгруппы.
Контроль единственности владельца. Карточка не может быть вставлена в несколько документов одновременно и не может быть вставлена в один и тот же документ несколько раз. Аналогично с элементами карточек — они должны иметь строго одного владельца — или карточку или группу.
Почему это лучший тест для языка
Если язык умеет описывать такую модель — он готов к реальной разработке. Если нет — никакая скорость и сборщик мусора не помогут.
DOM-подобные структуры проверяют всё сразу:
Может ли язык безопасно управлять временем жизни объектов?
Поддерживает ли разделяемые ресурсы без утечек?
Работают ли слабые ссылки или показывают на мусор?
Можно ли копировать объекты, сохраняя топологию связей?
Устойчиво ли приложение при произвольных изменениях?
Это не лабораторный эксперимент — это реальная модель поведения живой программы.
Что оцениваем
Критерий |
Вопрос |
Безопасность памяти |
Возможны ли висячие ссылки и краши? |
Предотвращение утечек |
Всё ли освобождается корректно? |
Ясность владения |
Понятно ли, кто чем владеет и когда? |
Копирование |
Сохраняется ли структура связей? |
Слабые ссылки |
Автоматически ли инвалидируются? |
Устойчивость |
Переживает ли система произвольные изменения? |
Выразительность |
Можно ли это описать без боли и избыточности? |
Момент обнаружения ошибок |
Поймаются ли циклы владения, множественное владение, попытка изменения расшаренного ресурса во время компиляции или только при запуске. |
Почему это важно
Обычно мы оцениваем языки по скорости вычислений или потребляемой памяти. Но скорость — это не проблема XXI века.
Настоящая сложность — управление живым состоянием, когда в памяти крутятся тысячи взаимосвязанных объектов, а приложение всё ещё должно оставаться стабильным.
DOM-подобные структуры — не про веб и не про XML. Это универсальная форма данных, через которую можно описать почти любую программу.
DOM бенчмарк заставляет язык показать, как он справляется с этой задачей: умеет ли он сочетать владение, разделение и ссылки без хаоса.
Если умеет — это язык, на котором можно писать реальные системы. Если нет — всё остальное не имеет значения.
Что дальше
В следующей части я протестирую на этом бенчмарке С++ и JavaScript, как примеры языков с подсчетом ссылок+RAII и со сборщиком мусора. Я прошу всех неравнодушных поучаствовать - показать реализацию этого бенчмарка на вашем любимом языке программирования. Особо приглашаются любители Раста - это ваш шанс показать насколько Rust заточен для реальных задач.
Комментарии (2)
knight_of_light_1
10.10.2025 04:22Очередная нейростатья, где афтор поленился даже глупые llm-паттерны убрать, все эти сравнения, метафоры — по-любому это писал живой человек)
Xexa
Т.е к аллокации(выделение и распределение памяти) и сортировке(найти/вставить) вернулись с этим "домом"