
В геймдеве и разработке ПО бытует крайне живучая концепция, призванная оправдать нагромождение лишних уровней абстракции. Тим Суини как-то заметил: «Я готов пожертвовать 10% производительности, если это сделает процесс создания игр более продуктивным, простым и приятным». Этот довод звучит соблазнительно: ценой небольших потерь мы получаем элегантные паттерны и выразительные возможности языка, позволяющие быстрее писать «плохой» код. Под «плохим» здесь понимается код, который, будучи медленнее идеального аналога, решает ту же задачу. Для бизнеса такой подход часто кажется оправданным, хотя на практике управленцам редко есть дело до сложности абстракций или красоты кода — у них свои, сугубо утилитарные метрики успеха, зачастую идущие вразрез с качеством продукта.
Уточню: под «плохим кодом» я подразумеваю не визуальную эстетику в IDE — там всё может быть безупречно: идеальные отступы, самодокументированные имена и продуманная иерархия. Я говорю о том «железе», которое исполняется на процессоре или GPU, превращаясь в просадки FPS, вечную загрузку уровней и шум вентиляторов.
Эта статья — ответ на очередной приступ «клинокодомании» в студии, когда в качестве истины в последней инстанции вновь извлекается книга Мартина. Однако «Clean Code» — это не про чистоту в её общепринятом смысле, а про личный «стиль Дядюшки Боба». Если бы мы изначально называли это методикой конкретного автора, а не сакральной «чистотой», дискуссии о ней потеряли бы свою религиозную окраску. Мы бы спорили не об абстрактных идеалах, а о применимости конкретных приёмов, избегая постоянной подмены понятий, где «чистый» (годный) код приравнивается к «Clean» (написанному по методичке).
Не всё то золото, что блестит
Важное отступление: почему не стоит слепо копировать примеры из «красной книги». Роберт Мартин писал Clean Code в 2008 году, опираясь на опыт консультирования корпораций, внедряющих Agile, ООП и экстремальное программирование. Для крупного бизнес-софта главной проблемой является поддержка и расширяемость кода на горизонте лет, а не стоимость каждой микросекунды выполнения. В геймдеве и Realtime-системах подобные абстракции становятся избыточным бременем, увеличивающим стоимость итерации на каждом кадре.
Проблема начинается тогда, когда абстракция из инструмента превращается в самоцель. Рассмотрим обычный обход массива. «Чистый» код выглядит нарядно — с итераторами, виртуальными методами и иерархией объектов, но он неизбежно проигрывает в производительности.
// Изящно, но каждое обращение — это аллокация и потеря локальности данных
for (Entity* e : scene.getAllEntities())
e->getTransform()->update(dt); // Виртуальные вызовы и непредсказуемые прыжки по памяти
Да, это легко читается, но из-за разреженной структуры памяти процессор постоянно сталкивается с промахами кеша, а виртуальные вызовы блокируют инлайнинг и векторизацию. Альтернатива — плоский массив структур (SoA/AoS) — выглядит для приверженцев Clean Code «грязнее» и проще, но именно такой код позволяет компилятору развернуться на полную мощность. Это не жертва качеством, это иной способ мышления: работа с потоками данных вместо фетишизации объектов.
// Плотный массив: линейный доступ радует кеш-линии
for (size_t i = 0; i < count; ++i)
positions[i] += velocities[i] * dt; // Эффективная векторизация и предсказуемость
Ловушка продуктивности
Аргумент «мы меняем время работы CPU на скорость написания кода» разбивается о реальность цикла разработки. Разработчик — самый частый потребитель своего же кода. Медленная архитектура увеличивает время компиляции, время «кукинга» ассетов, время запуска редактора и время прохождения до нужной точки в игре. Если на написание кода вы потратили на час меньше, но теперь каждый прогон билда занимает на минуту дольше, а за день вы делаете десятки итераций — вы проиграли.
Плохая производительность системы — это не локальная проблема. Она мультиплицируется. Если ваш движок тормозит, вы тормозите геймдизайнера, который ждет обновления ассета; вы тормозите билд-инженера и коллег по цеху. В цепочке зависимостей это выглядит как «эффект домино»: один неоптимальный узел увеличивает издержки всей студии. Мы платим за «чистый код» временем высокооплачиваемых специалистов, которые вынуждены ждать завершения бесконечных процессов.
Цена «чистоты»
Когда нам говорят, что потеря пары миллисекунд — это допустимая цена за читаемость, стоит вспомнить, что 16.6 мс на кадр (для 60 FPS) — это крайне жесткий бюджет. Физика, анимация, ИИ, рендеринг — всё это должно уложиться в один цикл. Внедрение «чистых» абстракций, каждая из которых «стоит» 0.0008 мс, при масштабировании на тысячи объектов превращается в неиграбельный проект.
Сегодняшние игры зачастую грузятся и работают хуже, чем тайтлы десятилетней давности, именно из-за того, что деградация производительности накапливается на стыках компонентов. Чистота ради чистоты становится техническим долгом, который мы оплачиваем комфортом пользователей и собственными рабочими часами.
Код, разумеется, не должен быть хаотичным. Но когда вам в следующий раз предложат внедрить «чистую архитектуру», предложите принести профайлер. Идеи должны проходить проверку не только эстетикой, но и железом, временем сборки и терпением коллег. Чистота кода — это не цель, а компромисс, который должен быть оправдан результатами, а не слепой верой в догматы.
З.Ы. Здесь и здесь поднимаются похожие темы.
З.З.Ы. На моем сайте https://dalerank.github.io/ собраны другие материалы по разработке игр, доступные на нескольких языках.



