Новый год для игровых разработчиков начался с волны критики, обрушившейся в адрес комитета по стандартизации C++ после публикации Араса Пранкевичуса «Жалобы по поводу современного C++». Возник серьезный вопрос: действительно ли комитет стандартов потерял связь с реальностью, или все наоборот, и это игровые разработчики откололись от остального С++ сообщества?
Вашему вниманию предлагается перевод популярного поста Бена Дина, — ветерана игровой индустрии, проработавшего продолжительный срок в компаниях Blizzard, Electronic Arts и Bullfrog в качестве разработчика на C++ и тимлида, — в котором он отвечает на критику с позиции собственного опыта.
TL;DR: Комитет по стандартизации C++ не имеет скрытой цели игнорировать нужды игровых разработчиков, а «современный» C++ не собирается становиться «неотлаживаемым» языком.
На протяжении всей прошлой недели в Twitter шла активная дискуссия, в ходе которой многие программисты – особенно те из них, кто работает в сфере игровой разработки – высказались о том, что нынешний вектор развития «современного C++» не отвечает их потребностям. В частности, с позиции обычного игрового разработчика, все выглядит так, будто производительность отладки в языке игнорируется, а оптимизация кода становится ожидаемой и необходимой.
В силу того, что на 2019 год я успел проработать в игровой индустрии более 23 лет, у меня имеется собственное мнение, основанное на наблюдениях по данной теме применительно к игровой разработке, которым мне и хотелось бы поделиться. Важна ли для игровых разработчиков «отлаживаемость» и почему? В чем заключаются вопросы, связанные с ней?
Для начала — небольшой экскурс в историю.
Многие игровые разработчики, пишущие на C++, работают в Microsoft Visual C++. Исторически сложилось, что вокруг платформ Microsoft сформировался огромный рынок для игр, и это отразилось на типичном опыте рядового игрового программиста. В 90-ые и 2000-ые большинство игр писалось с учетом этих обстоятельств. Даже с появлением консолей других производителей и ростом популярности мобильных игр, достоянием многих AAA-студий и многочисленных игровых программистов на сегодняшний день являются инструменты, произведенные Microsoft.
Visual Studio — это, возможно, самый лучший отладчик для C++ на свете. Причем сильнее всего Visual Studio действительно выделяется именно по части отладки программ — больше, чем своими front-end, back-end, реализацией STL или чем-либо еще. В последние пять лет Microsoft добилась серьезных успехов в развитии инструментов для разработки на C++, но даже и до этих заслуг отладчик в Visual Studio всегда был очень крутым. Так что когда вы занимаетесь разработкой на ПК с Windows, у вас под рукой всегда есть дебаггер мирового класса.
Учитывая вышесказанное, давайте рассмотрим процесс получения кода, в котором не будет багов; имеющиеся у нас возможности с точки зрения программиста, который не занимается играми; а также ограничения, с которыми сталкиваются игровые разработчики. Если перефразировать основной довод в пользу «вектора развития современного С++», то он сведется к типам, инструментам и тестам. Следуя этой мысли, отладчик должен выступать последней линией обороны. Прежде, чем мы ее достигнем, у нас имеются следующие возможности.
Возможность №1: Типы
Мы можем использовать столько сильной типизации, сколько потребуется, для того, чтобы исключить целые классы багов во время компиляции. Сильная типизация, вне сомнения, является возможностью, которую предоставила нам недавняя эволюция C++; например, начиная с C++11, мы успели получить:
- значительное расширение
type traits
; - такие нововведения, как
nullptr
иscoped enum
для борьбы с наследием C — слабой типизацией; - GSL и вспомогательные инструменты;
- концепты в C++20.
Некоторым из вас может не нравиться метапрограммирование шаблонов; другим может не нравиться стиль написания кода, при котором почти повсеместно используется auto
. Вне зависимости от этих предпочтений, здесь явно прослеживается основной мотив для использования перечисленных стилей в C++ — это стремление помочь компилятору, чтобы он в свою очередь мог помочь нам, используя при этом то, что он знает лучше всего: систему типов.
Если говорить об игровом программировании, здесь сильная типизация представляет собой широкое поле для исследования, и ее активно применяют знакомые мне игровые программисты, которые заинтересованы в том, чтобы на практике улучшить свои навыки применения C++. Здесь вызывают обеспокоенность две важные вещи: влияние на время компиляции, и влияние на читабельность кода.
Откровенно говоря, вы легко можете проигнорировать время компиляции — но только при условии, что вы — программист в очень большой компании, которая не занимается играми и обладает устоявшейся внутренней инфраструктурой и бесконечными вычислительными мощностями для того, чтобы скомпилировать любой код, который вы только можете написать. Подобные огромные компании обеспокоены стоимостью компиляции — поэтому используют модули — но, как правило, у отдельных разработчиков боли это не вызывает. В то же время, для большинства игровых программистов это совсем не так. У инди-разработчиков нет ферм для создания сборок; разработчики AAA-игр часто используют что-то вроде Incredibuild, но, учитывая тот факт, что они запросто могут работать с кодовой базой, которой исполнилось 10 и более лет, процесс сборки все еще может занимать 15-20 минут.
Мы можем поспорить насчет относительной стоимости добавления «железа» против стоимости времени программиста, и я согласен с позицией, что «железо» обходится дешевле, однако:
- Аппаратные средства — это реальные разовые расходы, которые будут возложены на бюджет текущего квартала, в отличие от не столь осязаемых расходов во времени/найме/и тому подобном, которые будут распределены на больший период времени. Люди плохо справляются с решением в пользу такого компромисса, а компании специально построены таким образом, чтобы оптимизировать краткосрочную прибыль.
- Инфраструктура требует поддержки, и почти никто не идет в игровую индустрию для того, чтобы стать релиз-инженером. В сравнении с другими областями, где используется C++, зарплата игровых разработчиков не настолько велика — а не-игровым инженерам платят здесь еще меньше.
Можно также порассуждать на тему того, что время компиляции никогда не должно было дойти до такого состояния; и снова я с вами соглашусь. Цена этого в постоянной бдительности — исходящей, опять же, от релиз-инженера — и, в идеале, некоторого автоматизированного инструмента, позволяющего отслеживать изменения во времени, требуемом для сборки билда. К счастью, за счет появления CI-систем этой цели сегодня можно достичь гораздо легче.
Возможность №2: Инструменты
Мы должны использовать максимум доступных нам инструментов — предупреждения (warnings), статический анализ, санитайзеры, инструменты динамического анализа, профилировщики и прочие.
Мой опыт говорит, что игровые разработчики используют эти инструменты там, где это возможно, но здесь у индустрии в целом имеется несколько проблем:
- Данные инструменты имеют тенденцию лучше работать на платформах, не связанных с Microsoft — и, как упоминалось ранее, это не является типичным сценарием в игровой разработке.
- Эти инструменты в большинстве своем нацелены на работу со «стандартным» C++. В них «из коробки» поддерживается
std::vector
, но не мой самописный классCStaticVector
из гипотетического движка. Безусловно, винить в этом инструменты бесполезно, но это по-прежнему один из барьеров в их использовании, который приходится преодолевать разработчикам. - Создание и поддержка CI-цепочки, которая будет запускать все эти инструменты, требует присутствия релиз-инженеров — и, как упоминалось ранее, найм людей на инженерные вакансии, не связанные непосредственно с играми, является системной проблемой для игровой индустрии.
Итак, раз эти инструменты так хорошо работают со стандартным C++, почему же игровые разработчики тогда не используют STL?
С чего бы начать ответ на этот вопрос? Пожалуй, с очередного экскурса в историю игровой разработки:
- До начала 90-ых, мы не доверяли компиляторам C, поэтому мы писали игры на ассемблере.
- С начала и до середины 90-ых, мы начали доверять компиляторам C, но мы все еще не доверяли компиляторам C++. Наш код представлял собой C, в котором применялись комментарии в стиле C++, и нам больше не требовалось все время писать typedef-ы для наших структур.
- Около 2000 года в мире игровой разработки произошла революция C++. Это была эпоха паттернов проектирования и больших иерархий классов. В то время поддержка STL на консолях оставляла желать лучшего, а миром тогда правили именно консоли. На PS2 мы навеки застряли с GCC 2.95.
- Примерно в 2010 году предпринимаются еще две революции. Боль от использования больших иерархий классов стимулировала разработку компонентного подхода к коду. Это изменение продолжает свою эволюцию и сегодня в виде архитектур Entity-Component-System. Рука об руку с этим шла вторая революция — попытка воспользоваться преимуществом многопроцессорных архитектур.
В ходе этих сдвигов парадигм постоянно изменялись и сами платформы игровой разработки, причем изменялись серьезно. Сегментированая память уступила место плоскому адресному пространству. Платформы стали многопроцессорными, симметричными и не очень. Игровым разработчикам, привыкшим работать с архитектурами Intel, пришлось привыкать к MIPS (Playstation), затем к специальному «железу» с гетерогенными CPU (PS2), после этого к PowerPC (XBox 360), затем к еще большей гетерогенности (PS3)… С каждой новой платформой приходили новые рабочие характеристики для процессоров, памяти и дисков. Если вы хотели добиться оптимальной производительности, то вы были вынуждены переписывать ваш старый код, причем много и часто. Я даже не стану упоминать то, как сильно на игры повлияло появление и рост популярности Интернета, а также ограничения, которые накладывали на разработчиков держатели платформ.
Исторически сложилось, что реализации STL на игровых платформах были неудовлетворительными. Не является секретом и то, что STL-контейнеры слабо подходят для игр. Если прижать игрового разработчика к стенке, то возможно он признается в том, что std::string
— вполне себе ОК, и std::vector
— разумный вариант по умолчанию. Но у всех контейнеров, содержащихся в STL, имеется проблема контроля аллокации и инициализации. Во многих играх приходится беспокоиться по поводу ограничения памяти для различных задач — и для тех объектов, память для которых скорее всего придется выделять динамически во время геймплея, часто используются slab или arena аллокаторы. Амортизированное константное время — недостаточно хороший результат, поскольку аллокация потенциально является одной из самых «дорогих» вещей, что могут произойти во время выполнения программы, и мне не хочется пропускать кадр только из-за того, что она произошла тогда, когда я этого не ожидал. Я, как игровой разработчик, должен управлять своими требованиями к памяти заранее.
Похожая история получается и для других зависимостей в общем. Игровые разработчики хотят знать, на что уходит каждый цикл процессора, где и когда и за что отвечает каждый байт памяти, а также где и когда контролируется каждый поток выполнения. До последнего времени, компиляторы Microsoft меняли ABI с каждым обновлением — поэтому, если у вас было много зависимостей, то перестраивание всех их могло быть болезненным процессом. Игровые разработчики обычно предпочитают небольшие зависимости, которые легко интегрируются, делают всего одну вещь и делают ее хорошо — желательно с API в стиле C — и при этом используются во многих компаниях, находятся в открытом доступе (public domain) или имеют бесплатную лицензию, которая не требует указания автора. SQLite и zlib — хорошие примеры того, что предпочитают использовать игровые разработчики.
Помимо этого, индустрия игр на С++ имеет богатую историю больных синдромом «Not invented here». Этого следует ожидать от индустрии, которая начиналась с одиночек-энтузиастов, которые мастерили что-то свое на совершенно новом оборудовании и не имели никаких других вариантов. Игровая индустрия, помимо прочего, единственная, где программисты указываются в титрах без определенного порядка. Писать разнообразные штуки весело, и это помогает вашей карьере! Гораздо лучше строить что-то свое, чем покупать готовое! А поскольку мы так беспокоимся о производительности, мы можем адаптировать наше решение таким образом, чтобы оно подходило именно для нашего проекта — вместо того, чтобы взять обобщенное решение, бездумно тратящее имеющиеся ресурсы. Неприязнь к Boost — основной пример того, как подобное
- Для начала, для решения той или иной проблемы мы подключаем к проекту библиотеку из Boost.
- Все работает очень даже хорошо. Когда нужно обновиться, возникает небольшая боль, но не больше, чем при обновлении любой другой зависимости.
- Другая игра хочет использовать наш код, но камнем преткновения становится то, что мы используем Boost — несмотря на то, что наш опыт использования Boost прошел вполне нормально.
- Мы убираем код с использованием Boost, но теперь перед нами встает новая проблема: мы должны решить задачу, которую до этого вместо наш решала библиотека из Boost.
- Мы по сути копируем части кода Boost, которые нам нужны, в наши собственные пространства имен.
- Позже, мы неизбежно и раз за разом сталкиваемся с тем, что нам нужна дополнительная функциональность, которая уже была бы в оригинальном коде, если бы мы его не выкинули. Но теперь владельцами этого кода являемся мы сами, поэтому нам приходится продолжать поддерживать его.
Нам не нравится что-либо огромное, пытающееся сделать слишком много дел одновременно или способное повлиять на время компиляции — и это вполне разумно. В чем люди ошибаются снова и снова, так это в том, что они противостоят тому, чтобы принять предполагаемую боль сегодня — в то время как из-за этого решения их ждет весьма реальная и гораздо большая боль при поддержке чего-либо за счет чьего-то еще бюджета, которую им придется испытывать в течение трех следующих лет. Увы, но наличие доказательств в виде игр, успешно использующих блюдо из STL и Boost, никоим образом не может повлиять на психологию человека и переубедить игровых разработчиков.
В силу всех этих причин, многие игровые компании создали свои собственные библиотеки, которые покрывают то, что делает STL — и даже больше — и при этом поддерживают специфические для игровой разработки кейсы использования. Отдельные большие игровые компании даже смогли осилить разработку собственной, полноценной, практически полностью совместимой по API замены STL, что в дальнейшем повлекло за собой огромные расходы на поддержку данного проекта.
Вполне разумно подыскать улучшенную альтернативу std::map
, или применить small buffer optimization в std::vector
. Гораздо менее приемлемо быть обреченным на поддержку своих собственных реализаций algorithms
или type traits
, что не принесет практически никакой пользы. Как по мне, прискорбно, что STL для большинства разработчиков — это одни лишь контейнеры. Поскольку при изучении STL на старте обучают именно им, то говоря об STL большинство подразумевает std::vector
— хотя на самом деле им следовало бы думать про std::find_if
.
Возможность №3: Тесты
Утверждается, что должно осуществляться экстенсивное тестирование, TDD и/или BDD должно покрывать весь код, который можно покрыть, а с багами необходимо бороться написанием новых тестов.
Поэтому давайте обсудим тему тестирования.
Судя по моему опыту, автоматизированное тестирование в игровой индустрии практически не используется. Почему?
1. Потому что корректность не столь важна, а реальная спецификация отсутствует.
Будучи молодым программистом в игровой индустрии, я быстро избавился от мысли о том, что я должен стремиться моделировать что-либо реалистично. Игры — это пускание пыли в глаза (smoke and mirrors) и поиск коротких путуй. Никого не волнует, насколько реалистична ваша симуляция; главное, чтобы она была увлекательной. Когда у вас нет другой спецификации, кроме как «игра должна ощущаться правильно», отсутствует сам предмет тестирования. Благодаря багам геймплей может даже становиться лучше. Достаточно часто баг попадает в релиз, и даже завоевывает любовь пользователей (вспомните того же Ганди из Civilization). Игры отличаются от других сфер, в которых используется C++; здесь нехватка корректности не приводит к тому, что кто-то в итоге лишается своих сбережений.
2. Потому что это тяжело.
Разумеется, вам хотелось бы производить автоматизированные тесты везде, где вы сможете. Это может быть осуществлено для некоторых подсистем, для которых есть четко сформулированные конечные результаты. Юнит-тестирование в игровой индустрии, конечно, присутствует, но как правило ограничивается низкоуровневым кодом — упомянутыми ранее аналогами STL, процедурами преобразования строк, методами физического движка и т.д. Те случаи, когда у исполняемого участка кода есть предсказуемые результаты, обычно тестируются юнит-тестами, хотя TDD здесь и не применяется — поскольку игровые программисты предпочитают упрощать себе жизнь, а не наоборот. Но как вы протестируете код геймплея (смотрите пункт первый)? Как только вы выходите за рамки юнит-тестирования, то сразу встречаетесь с еще одной причиной, почему тестирование игр является настолько сложным.
3. Потому что в него вовлечен контент.
Тестирование нетривиальных систем возможно будет включать в себя предоставление контента, с участием которого оно будет осуществляться. Большинство инженеров не слишком хороши в плане изготовления этого контента своими силами, так что для получения осмысленного теста потребуется привлечь кого-либо с нужными навыками создания контента. После чего вы столкнетесь с проблемой измерения того, что вы получаете на выходе — ведь это больше не строка или число, а изображение на экране или звук, которые изменяются с течением времени.
4. Потому что мы его не практикуем.
Юнит-тестирование — это функция, для которой мне известны возможные входы и выходы. Однако геймплей — это непредсказуемое, складывающееся динамически поведение, и я не знаю, как подобное явление можно было бы как следует протестировать. Что я могу протестировать — если, конечно, я получу разрешение от своего менеджера уделить этому достаточное время — это, например, производительность, или высокоуровневые возможности вроди матчмейкинга, которые я могу проанализировать. Подобная инфраструктурная работа может быть увлекательно для некоторых игровых программистов, но большинству она попросту неинтересна, — да еще и вдобавок требует одобрения и поддержки со стороны владельца кошелька. В роли игрового программиста, я никогда не имею возможности заняться практикой написания высокоуровневых тестов.
5. Поскольку [компания] не видит необходимости в автоматизированном тестировании.
Наша главная цель — это выпустить игру. Мы живем во времена индустрии, которая движется вперед за счет хитов, которые зарабатывают большую часть своих денег в первый месяц продаж, когда расходы на маркетинг этих хитов максимальны. Жизненный цикл консолей научил нас тому, что код в любом случае проживет не так уж и долго. Если мы работаем над онлайн-игрой, то скорее всего получим дополнительное время на тестирование матчмейкинга или нагрузки на сервера. Поскольку для релиза игры нам требуется, чтобы ее производительность была в порядке, мы должны как минимум произвести тестирование производительности, но мы не должны автоматизировать этот процесс. Для менеджмента в индустрии игр автоматизированное тестирование — это не более, чем трата времени и денег. Для его проведения приходится нанимать опытных инженеров, которые произведут работу, результат которой будет практически незаметен. Это же время можно было бы потратить на разработку новых фич. В краткосрочной перспективе для тестирования игры гораздо выгоднее использовать персонал QA, что приводит нас к следующему пункту.
6. Потому что в целом тестирование относят в играх к второсортной деятельности.
Я обожаю хороших QA-специалистов. Для меня они на вес золота. Они знают, как сделать вашу игру лучше, ломая ее таким образом, который никогда бы не пришел вам в голову. Они — профильные эксперты в вашем геймплее в том плане, в котором вы не разбираетесь, и едва ли когда-либо разберетесь. Они — лучше, чем команда супер-способных компиляторов, помогающих вам делать все как надо. Я рад тому, что мне выпал шанс поработать с несколькими замечательными QA-специалистами за годы моей работы.
Я почти всегда был вынужден сражаться только за то, чтобы они остались в моей команде.
В больших AAA-компаниях, организация, занимающаяся QA — это обычно совершенно отдельный отдел от любой команды разработки, со своим собственным менеджментом и организационной структурой. Делается это якобы для того, чтобы они могли проявить объективность во время проведения тестирования. На практике, все оказывается далеко не так прекрасно.
К ним относятся, как к шестеренкам в огромном механизме, которых часто перебрасывают между проектами без предупреждений и в целом относятся к ним так, будто с их работой может справиться любой. Когда проект «съезжает» с даты дедлайна, инженеры могут ощутить кранч на своей шкуре, но QA достается гораздо сильнее, ведь им приходится работать в ночную смену и по выходным, плюс им же еще и достается за то, что они приносят невеселые новости о текущем состоянии качества проекта.
Им серьезно недоплачивают. Самые опытные тестировщики с годами экспертизы в предметной области получают меньше половины того, что платят разработчику среднего уровня. Мне приходилось работать с умнейшими QA-инженерами, которые создавали пайплайны для тестирования производительности с трекингом и оповещениями, создавали фреймворки для тестирования API и для нагрузочного тестирования и выполняли множество других задач, якобы недостойных времени «настоящих инженеров». Я уверен в том, что эти умнейшие люди получали бы гораздо больше, если бы работали в любой другой большой технологической компании.
Им не доверяют. Не редкость, что тестировщиков держат отдельно от остальных разработчиков, а их бейджи позволяют им получать доступ только к тому этажу здания, где они работают сами — или же и вовсе использовать отдельный вход.
Они вынуждены подчиняться. Тестировщикам часто говорят не беспокоить других инженеров. Когда им нужно сообщить о баге напрямую, их просят обращаться к инженерам уважительно, вроде «Миссис Х.» или «Мистер Y.». Иногда мне звонило раздраженное начальство QA-отделов — в тех случаях, когда я для совместного расследования связывался напрямую с теми, кто обнаруживал баг.
Все это звучит как страшная сказка, и пусть сталкиваться с подобными вещами приходится далеко не всем, к несчастью это происходит все еще довольно часто; настолько часто, что инженеры начинают думать — возможно, сами находясь под грузом постоянного стресса, но это их не извиняет — что работа QA состоит в том, чтобы искать их же баги, или, что еще хуже, начинают винить QA за баги.
В лучших командах, с которыми мне приходилось работать, мы настаивали на том, чтобы в наших командах были свои QA-инженеры, которые работали бы с нами вместе. При этом они не теряли своей объективности или желания добиться лучшего результата. Им было приятно получать помощь от программистов в написании автоматизированных тестов. В чем я точно не сомневаюсь, так это в том, что игровой индустрии было бы полезно заниматься автоматизацией чаще.
Производительность отладки
С учетом всего вышесказанного — привычки заниматься отладкой, платформой для API и инструментов, которая до сих пор взрослеет, и сложностью (в совокупности с недостатком культуры) автоматизированного тестирования — становится ясно, почему игровые разработчики так настаивают на возможности отладки.
Но при этом остаются проблемы с самой отладкой, и проблемы с тем, как игровые разработчики справляются с нынешним вектором развития C++.
Главная проблема отладки состоит в том, что она не масштабируется. Среди игровых разработчиков разработчиков, читающих данный пост, найдутся те, кто решит, что описанные мною явления не сходятся с тем, что они наблюдали на своей практике. Вполне возможно, это из-за того, что рано или поздно им самим пришлось столкнуться с проблемой масштабируемости отладки, и они нашли способ обойти ее.
Другими словами, мы хотим иметь производительную отладку, потому что для того, чтобы ловить баги, нам часто нужно иметь возможность выполнять запуск приложений с достаточно большими и репрезентативными наборами данных. Но на самом деле, когда мы достигаем этой точки, то обычно дебаггер становится слишком грубым инструментом для использования — вне зависимости от того, производителен он или нет. Конечно, установка точек останова на данных (data breakpoints) может быть полезна для поимки проблем среднего размера, но что делать, если мы столкнемся с реальными багами — теми, которые остаются после того, как мы казалось бы уже все пофиксили? С теми самыми, которые возникают под нагрузкой в сети, или в случае нехватки памяти, или работающей на пределе возможностей многопоточности, или случаются лишь для небольшого, еще не идентифицированного подмножества на фоне миллиона других игроков, или возникают только на дисковых версиях игры, или только в сборке на немецком языке, или спустя три часа, проведенных за тестированием стабильности (soak testing)?
Черта с два мы можем положиться на один лишь отладчик. В этом случае мы делаем то, что мы делали всегда. Мы пытаемся изолировать проблему, заставить ее происходить чаще; мы добавляем логирование и просеиваем нашу программу через него; мы подстраиваем таймеры и настройки потоков; мы применяем двоичный поиск по билдам; мы изучаем дампы ядра и крэшлоги; мы пытаемся воспроизвести проблему, урезая контент до минимума; мы размышляем насчет того, что может быть причиной проблемы, и обсуждаем ее.
Зачастую, пока мы доберемся до настоящей причины «крэша», мы успеем исправить несколько других вещей. Другими словами, мы решаем проблемы, и в конце концов, использование дебаггера — это лишь небольшая часть данного процесса. Так что да, скорость отладки — приятное дополнение, но ее нехватка не мешает нам продолжать оставаться инженерами. Нам по-прежнему требуются другие наши навыки, вроде способностей анализировать дампы ядра и читать оптимизированный ассемблер.
При использовании «современного С++» я пользуюсь отладчиком тем же самым образом, что и обычно. Я прохожу им по свеженаписанному коду; ставлю брейкпоинты на тех данных, которые меня интересуют; использую дебаггер для того, чтобы исследовать незнакомый код. С приходом «современного C++» ничего из этого не меняется, — и да, даже несмотря на то, что STL использует _Уродливые _Идентификаторы, это не делает STL магией. Иногда бывает полезным посмотреть, что STL делает «под капотом», или же переступить через нее; или, как теперь можно сделать, использовать отладчик для того, чтобы скрыть код библиотеки от меня.
Когда я сталкиваюсь с проблемами производительности отладки, то дело обычно не в том, что «современный C++» замедляет меня — дело в том, что к этому моменту я уже пытаюсь сделать слишком много всего. Использование отладчика не масштабируется — в отличие от типов, инструментов и тестов.
Я сам был обеспокоен проблемой того, что код на C++ требует все больше и больше оптимизации, и я интересовался мнением разработчиков компиляторов по этому поводу. Факт состоит в том, что здесь нет однозначного ответа. Мы уже находимся в континууме, и у нас есть возможность продвигаться дальше в этом направлении без причинения вреда возможности отладки кода. Сегодня наши компиляторы выполняют copy elision (пропуск копии) для временных объектов, даже если мы не просим их производить данную оптимизацию. На нашу возможности отладки приложений это никак не влияет. Сомневаюсь, что мы станем жаловаться на то, что отладочные билды стали включать NRVO или еще полдюжины оптимизаций, которые могут быть произведены таким образом, что во время отладки мы их и не заметим. Подозреваю, что C++ движется как раз в этом направлении.
Эпилог: Путь современного С++
Если вы работаете программистом в сфере игровой разработки и вам не нравится, куда движется C++, то у вас по сути есть два варианта возможных дальнейших действий.
1. Ничего не делать
Если предположить, что вы все еще собираетесь писать код на C++, то вы можете просто продолжать использовать язык так же, как делали и до этого. Нет необходимости начинать использовать любые новые возможности, если вы не хотите этого делать. Практически все из того то, чем вы пользуетесь сейчас, будет продолжать поддерживаться — и при этом в последующие годы вы будете продолжать пожинать плоды совершенствования компилятора.
Это совершенно адекватная стратегия поведения для тех, кто работает на себя или с командой единомышленников. C++98, вместе с некоторым набором более новых функций, по-прежнему хорошо подходить для того, чтобы писать на нем игры.
Однако, если вы работаете в большой компании, то рано или поздно вам придется столкнуться с изменениями в языке, поскольку вам придется увеличивать команду и нанимать новых людей. В свою очередь, когда вы будете нанимать C++-разработчиков, это будет означать найм разработчиков на «современном» C++. Произойдет смена поколений — как это уже приключилось с ассемблером, C и C++98. Вы сможете управлять процессом, если установите ограничения на то, что разрешено в вашей кодовой базе, а что – нет, но и это решение не спасет вас в долгосрочной перспективе. И что вам делать в таком случае?
2. Принять участие
Вместо того, чтобы раз в год ездить лишь на одну GDC, начните посещать CppCon, где вы получите гораздо большую пользу от денег, потраченных вашей компанией на билет. Участвуйте в обсуждениях стандартов; вступайте в группы и подписывайтесь на рассылки; читайте черновики стандартов и предоставляйте авторам обратную связь. Если вы сможете еще и посетить встречи комитета, то это будет просто отлично, но даже если и нет — вы все еще можете сделать многое для того, чтобы донести до других вашу точку зрения.
Участие в комитете по C++ открыто для всех. Вся необходимая информация для тех, кто хочет принять участие в работе SG14, или SG7, или SG15 — или любой другой рабочей группе, касающейся сферы ваших интересов — может быть найдена на isocpp.org. У комитета нет никаких тайных планов — в самом деле, вы и правда считаете, что свыше 200 программистов могут согласовать между собой единую повестку? Здесь даже у «начальства» комитета зачастую не удается «пропихнуть» свои идеи.
Если вы хотите, чтобы ваше мнение было услышано, то вы должны начать говорить там, где ваше мнение может быть услышано, а не на Twitter или Reddit. Пожалуйста, воспользуйтесь этим советом — я с нетерпением ожидаю нашей дискуссии.
Автор: Владимир Маслов