Почему я выбрал серверную разработку в геймдеве
Меня зовут Арсен, я .NET Developer в компании Plarium, занимаюсь серверной частью проекта Raid: Shadow Legends, мобильной RPG в жанре темного фэнтези.
В этой статье я расскажу, чего стоит ждать от работы в геймдеве и о том, как это — разрабатывать проект, в котором количество активных игроков в день превышает миллион и где каждая минута упавшего сервера стоит компании репутации и денег.
Как я пришел к .NET
Я начал карьеру с должности фулстек-девелопера в небольшой IT-компании: бэкенд — на .NET, фронтенд — на Angular. Мне нравилось самому отвечать за весь цикл разработки и знать, как что реализовано на клиенте и сервере, как хранится в базах данных. Но были и минусы — огромный спектр задач и миллион ежедневно обновляющихся фреймворков. Когда пытаешься уследить за одним, пропускаешь другое и неизбежно где-то проседаешь. Я захотел стать узконаправленным специалистом, поэтому начал задумываться о переходе на .NET или фронтенд.
Когда я почувствовал себя увереннее в профессии, мне захотелось работать в компании покрупнее, с более интересными проектами. Я перешел в другую аутсорс-компанию, где занимался чисто сервером. Работая там, попал на конференцию uDev и узнал больше о Plarium. К тому времени я уже немного разбирался в Unity — смотрел уроки на YouTube, делал pet projects, — поэтому решил попробоваться как Unity Developer и получил оффер.
Поскольку мне нравится писать чистый код, без всяких юайных штук, то, поработав какое-то время в Plarium на клиенте, я понял, что сервер мне все-таки ближе. Когда мне предложили написать тулзу для гейм-дизайнеров на WPF, я сразу ухватился за возможность и понял: всё, .NET — это мое. Перешел на серверную сторону геймдева и работаю здесь почти 3 года.
Что отличает работу в геймдеве
Восприятие продукта своим
В продуктовом геймдеве я стал по-другому относиться к проектам: они больше воспринимаются «своими». В первую неделю работы я на дейлике услышал фразу: «Мы делаем это для себя», — и как-то проникся. На аутсорсе я привык давать эстимейты в часах, а здесь — в днях: мы много времени уделяем код-ревью и можем позволить себе поиск самого оптимального решения.
Мне повезло поучаствовать в разработке одной мобильной игры с начала. Я знал каждого из команды и понимал, как всё устроено. Я ощущал принадлежность к чему-то большому, что никуда от меня не уйдет. Конечно, игра может не взлететь, но ты работал над ней от начала и до закрытия проекта — она всё равно твоя.
С огромным проектом на аутсорсе так не происходит. Ты не знаешь, будет он у вас завтра или нет. Даже когда в разработке долгосрочный проект, всё равно чувствуешь, что выполняешь его для внешнего заказчика, который внезапно может сказать: «Ребята, вы нам не подходите, мы решили работать с другой компанией».
Для меня важно, что я могу влиять на продукт. Когда мы делали эту мобильную игру, гейм-дизайнеры, разработчики, тестировщики, менеджеры собирались и спорили, зайдет эта фича или нет. Бывали прямо жесткие баталии — наверное, такая атмосфера в стартапе. Вот ты разработчик, перед тобой стоит директор, и ты ему рассказываешь, почему это может взлететь. И он говорит: да, это круто, давайте делать.
Быстрое решение проблем
Думаю, геймдев не подойдет тем, кто считает, что разработка игр — сплошной фан и развлечения. Это далеко не так.
В этой работе много напряжения. Поломка на проде — это разочарованные или разозленные игроки, жалобы в саппорт, негатив в чатах. Нужно не только максимально быстро пофиксить проблему, но и предупредить о работах на сервере, возместить игрокам ущерб. Однажды на одном из наших проектов-стратегий на продакшн попал тестовый код выдачи игровых ресурсов. Сервер стал каждую минуту выдавать недельную награду. Это произошло на выходных, поэтому наши ребята не сразу обнаружили проблему. Как только заметили, написали фикс и перелили сервер на проде. Но можно представить, насколько нарушился игровой баланс, когда пользователи за короткий промежуток времени получили такое количество внутриигровых кристаллов.
Срочные изменения в спринте — тоже стрессовый фактор. Релиз фичи мог быть запланирован через три месяца, но аналитики посчитали, что выгоднее перенести её в ближайший спринт вместо другой задачи. Или изменилась политика стора — нужно отложить другие таски и за пару дней железно внести обновления в игру.
Ответственность за фичи и фидбэк от игроков
Когда сделал фичу, люди ставят 5 звезд, пишут «классно», и это вдохновляет. Но, если фича нравится игрокам, это в первую очередь заслуга гейм-дизайнеров. Как серверный разработчик я отвечаю за то, чтобы фича работала корректно и стабильно, чтобы игра не вылетала и не было проблем с производительностью.
Если на продакшене что-то отвалится после рабочего дня, я должен буду это посмотреть. На аутсорсе таких порывов не было, в геймдеве же забить и не переживать не получается. Не только из-за недовольства игроков, но и от мысли, что это я накосячил. Можно в 12 ночи зайти в чат команды, а там как будто полноценный рабочий день.
На одном из проектов как-то начали откатываться пользователи. Это была офлайн-игра: каждое действие пользователя мы сохраняли на девайсе и раз в
После очередного релиза начало падать много ошибок такого типа, посыпались жалобы игроков. Мы временно отключили валидацию на сервере, чтобы разобраться. Оказалось, проблема была в обратной совместимости. У нас дублировалась логика на сервере и клиенте. При изменении кода на сервере, нужно убедиться, что старый клиент на старом коде будет корректно работать и на новом сервере. Мы должны это предусматривать, но в тот раз упустили. Я хорошо запомнил это чувство, когда смотришь, как ошибки на сервере падают, падают...
Под капотом серверной разработки
У нашего сервера очень тонкий стек. Он построен так: чистый .NET, ASP.NET и MS SQL Server. Никаких сложных и долгих entity-фреймворков, всё происходит просто и быстро. Наши серверы обрабатывают 16 тысяч запросов в секунду и 140 миллионов внутриигровых битв в день.
Когда работаешь с высоконагруженной системой, должен понимать на уровень глубже, знать все узкие места и понимать, как всё устроено внутри платформы. На небольших проектах я не задумывался, как работает какой-нибудь сборщик мусора. А на таких проектах, как Raid: Shadow Legends, даже он может работать долго — мы увидели это, когда собрали аналитику. Я не знал, что такое возможно: в .NET сборщик мусора реализован автоматически и тебе не нужно за ним следить.
Глубокое знание системы
По большей части мы используем проверенные технологии. Запрос в нашу базу данных в среднем выполняется до 10 миллисекунд. Современные фреймворки могут работать в 10, во 100 раз дольше, и это всегда потенциальные риски. Даже если на первый взгляд фреймворк работает классно, неизвестно, что будет при нагрузке в миллионы пользователей: например, скорости выполнения операции с применением сторонней библиотеки при наших нагрузках может не хватить.
У нас нет табу на новые технологии, но сначала мы их тщательно тестируем. В аутсорс-компаниях, в которых я работал, мы чаще использовали свежие фреймворки. Это тоже было круто: успевать за трендами, быть в курсе всех последних ангуляров и реактов. Но я думаю, что для разработчика не так важно знать новые фреймворки — их можно быстро выучить. Важнее уметь решать нестандартные задачи. Чем глубже ты понимаешь работу системы, тем больше у тебя экспертизы.
Для нашего проекта иногда выгоднее написать кастомное решение. Например, мы сами запилили сериализатор JSON: в плане производительности было неэффективно использовать third-party фреймворки. Они сложные, и у них объемный функционал: валидация данных, сбор аналитики, диагностика проблем. Но нас интересовала только одна задача, которую нужно было выполнять максимально быстро: сериализовать модель данных в JSON-строку и обратно. Использовать свой простой инструмент для нас оказалось в несколько раз эффективнее.
Задачи, которые невозможно загуглить
Я думаю, что большая часть проблем, с которыми сталкивается серверный программист в геймдеве, связаны не с особенностями системы, а с бизнес-задачами. Когда я был начинающим фулстек-разработчиком, я постоянно гуглил: как добавить что-то на страничку, как в вебе что-то посчитать, как в ангуляре что-то реализуется. А здесь — чистый .NET. Да, я могу погуглить, как Apple реализует какой-то API, но это всё.
У меня был таск на сохранение прогресса игроков без привязанного ID. Что, если игрок на
Сложность заключалась не в техническом исполнении, а в поиске решения. На других наших проектах не было такого функционала, мы придумывали всё с нуля. Поскольку это офлайн-игра, нам нужно было придумать, как сохранять данные до следующего интернет-подключения. В итоге мы решили использовать Google Drive или iCloud. Когда пользователь устанавливал игру, в облачном хранилище автоматически создавался токен. Без подключения к интернету данные хранились на телефоне. Как только подключение появлялось, данные синхронизировались с облаком. Если игра удалялась, мы теряли токен на сервере, но он сохранялся в облачном хранилище. При повторной установке игры мы проверяли токен и предлагали игроку выбор: восстановить прогресс или играть заново.
Но возникла еще одна проблема: оказалось, что токен мог прилетать с драйва не сразу. Google Drive работает рандомно, iCloud стабильнее, но всё равно токен мог не прийти или не записаться. У нас был сервис, который постоянно крутился в цикле и проверял, есть токен или нет. Google синхронизировал токен каждые 24 часа: получается, в течение суток прогресс игрока мог быть недоступен. Пользователь мог скачать игру заново, получить двадцатый уровень. А потом токен обнаруживался, подтягивался с драйва и у пользователя оказывалось два прогресса. В таком случае мы показывали игроку оба прогресса: заработанный уровень и монеты в каждом. Игрок сам выбирал, какой прогресс сохранить, а второй мы удаляли.
Для меня геймдев — это технический вызов. На мой взгляд, если ты кайфуешь от игр, это не значит, что будешь более крутым разработчиком. Главное, чтобы тебе нравилось решать именно такие задачи.
Полезные ресурсы
Разобраться в высоконагруженных системах, игровой и мобильной разработке мне помогли несколько книг и курсов. Если вам тоже интересно, велкам :)
Что послушать:
- Мини-конференции CLRium — канал с конференциями по .NET. Про устройство платформы .NET: выделение памяти, сборка мусора, потоки, реализация внутренних механизмов, многопоточность, оптимизация и многое другое. Будет интересно тем, кто хочет копнуть чуть глубже;
- Brackeys — канал о геймдеве, по нему я начинал учить Unity;
- Unit Testing for C# Developers — курс для начинающих по юнит-тестам на C#;
- React Native — The Practical Guide — курс, который я прошел, чтобы «потрогать» мобильную разработку. Было настолько интересно, что на протяжении месяца я вставал в 6 утра, чтобы смотреть уроки.
Что почитать:
- «CLR via C#. Программирование на платформе Microsoft .NET», Джеффри Рихтер;
- «C# для профессионалов. Тонкости программирования», Джон Скит;
- «Эффективная работа с унаследованным кодом», Майкл Физерс;
- «Приемы объектно-ориентированного проектирования. Паттерны проектирования», Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес;
- «Unity в действии. Мультиплатформенная разработка на C#», Джозеф Хокинг;
- «Высоконагруженные приложения. Программирование, масштабирование, поддержка», Мартин Клеппман.
29 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів