Взгляд изнутри: архитектура нового клиента LoL

  • Hexagun

    Hexagun «Глобальный ньюсмейкер» Отдел редакции

    image.jpg

    Привет! Меня зовут Эндрю Маквей, я архитектор программного обеспечения в Riot Games.

    ейчас мы находимся на последних стадиях переработки клиента League of Legends, рабочее название которого – "обновленный клиент LoL". В этой статье я опишу программную архитектуру обновления, назову причины некоторых изменений и расскажу об ограничениях, с которыми мы столкнулись, работая с текущим клиентом. Путешествие к финальной архитектуре было крайне захватывающим с технической точки зрения, и я рад поделиться с вами подробностями!

    ЗАЧЕМ МЕНЯТЬ КЛИЕНТ?

    Первая версия клиента, появившаяся в 2008 году, была создана на основе интерфейса Adobe AIR, которая использовала для обмена данными с нашими серверами сессионный сетевой протоколRTMP. Эта платформа служила нам верой и правдой: она предлагала богатую мультимедийную среду, позволявшую создать анимацию и эффекты, которые нельзя было реализовать в HTML того времени. Кроме того, она была кроссплатформенной и простой в освоении, что значительно упрощало работу команды, дающей указания художникам и дизайнерам.

    А теперь перемотаем время на 2015 год, когда три проблемы, связанные с AIR-клиентом, встали наиболее остро. Эти проблемы (наряду с многими другими) решает наша новая архитектура.

    ПРОБЛЕМА №1: HTML5 – СТАНДАРТИЗИРОВАННАЯ, ШИРОКО РАСПРОСТРАНЕННАЯ ПЛАТФОРМА

    Связка HTML5 и JavaScript стала мощной платформой для создания настольных клиентских приложений. В ее использовании есть масса преимуществ: тут и стандартизированные рабочие процессы, и инструменты для разработки, и множество талантливых разработчиков. Мы хотим по полной раскрыть потенциал этой платформы и воспользоваться всеми медиа-возможностями, которые она предоставляет.

    image.png

    ПРОБЛЕМА №2: ИГРОКИ ХОТЯТ ОСТАВАТЬСЯ НА СВЯЗИ КАК В ИГРЕ, ТАК И ВНЕ ЕЕ

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

    image (1).png

    РОБЛЕМА №3: КОМАНДА РАЗРАБОТЧИКОВ RIOT ХОЧЕТ РАБОТАТЬ В ГАРМОНИИ

    League (как и Riot) сильно выросла с 2008 года – тогда мы и представить не могли, что над клиентом будет работать такое количество команд, каждая из которых будет добавлять что-то свое. Первоначальная кодовая база была создана небольшой сплоченной группой людей, что повлекло за собой недостаток автономности и независимости от размера функционала, который рос как на дрожжах.

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

    image (2).png

    ШАГИ НАВСТРЕЧУ ПОТРЯСАЮЩЕЙ АРХИТЕКТУРЕ

    Есть целый ряд способов решить эти проблемы – к примеру, мы потратили немало времени на реорганизацию существующего кода AIR, когда еще хотели остаться на текущей (устаревшей) платформе. Однако, изучив это вариант, мы поняли, что справиться с проблемами выше можно и другим способом, более надежным и мощным – полностью сменив платформу. Мы решились на это, даже несмотря на опасности переписывания, ведь преимущества этого решения в долгосрочной перспективе перевешивали все риски.

    Мы начали все с нуля и выбрали в качестве интерфейса Chromium Embedded Framework (CEF)Благодаря этому у нас в руках оказался мощнейший браузерный компонент, обладающий всеми преимуществами HTML5, который мы с легкостью могли изменять.

    Сейчас вы узнаете, как мы пришли к нашей окончательной архитектуре.

    ШАГ ПЕРВЫЙ: МИРОМ ПРАВИТ JAVASCRIPT!

    Нашей первоначальной идеей было сделать все на JavaScript.

    image (5).jpg
    Приняв решение строить пользовательский интерфейс на HTML и JavaScript, мы захотели пойти дальше и реализовать на JavaScript еще и бизнес-логику и коммуникации, чтобы упростить и унифицировать архитектуру. (Подобное единообразие интерфейса и служб лежит в основе многих платформ – например, node.js)

    Таким образом, мы создали на C++ простую библиотеку с минимумом функций, позволявшую JavaScript делать удаленные вызовы посредством протокола RTMP и обрабатывать асинхронные ответы. Мы решили не отказываться от RTMP, так как он прекрасно подходит для задач нашего уровня и потому что мы не хотели одновременно со сменой клиента менять коммуникационный протокол.

    По результатам внутреннего прототипирования мы решили использовать фреймворк ember.js для нашего одностраничного приложения, а ember-orbit выбрали в качестве уровня данных.

    Что могло пойти не так при использовании столь прямолинейной технологии? Как оказалось, много чего.

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

    Эта архитектура решила проблему №1, а вот перед проблемами №2 и №3 она оказалась бессильна. А еще, внутренний опрос разработчиков показал, что их продуктивность снизилась по сравнению с временами, когда они работали над AIR-клиентом. Упс.

    ШАГ ВТОРОЙ: МЫ ЗАНОВО ОТКРЫЛИ ВЕБ-ПРИЛОЖЕНИЯ (СДЕЛАВ ИХ НАСТОЛЬНЫМИ)!

    Нашим следующим шагом стала реализация микрослужб на C++. Целью было представить асинхронный игровой протокол в виде набора REST-ресурсов.

    Мы начали думать, из чего состоят обычные веб-приложения, и поняли, что нам не хватает промежуточного звена. И тогда мы создали слой микрослужб (который по-прежнему работал на компьютере игрока), представленных протокол RTMP в виде REST-ресурсов. Это было сделано, чтобы избавиться от излишней асинхронности в JavaScript. Чтобы обрабатывать события в пользовательском интерфейсе, мы использовали технологию WebSockets. Слой микрослужб получил название "фундамент".

    image (2).jpg

    Ниже изображен Swagger UI с ресурсами фундамента, отвечающими за обновление клиента. Эта конструкция сильно упростила код JavaScript, позволив использовать стандартные методы веб-разработки.

    image (3).jpg

    У этой архитектуры есть еще одно преимущество: при сворачивании клиента интерфейс CEF (и виртуальные машины JavaScript) перестает использоваться – работает лишь фундамент. Это возможно благодаря тому, что фундамент хранит исходное состояние – весь пользовательский интерфейс можно воссоздать с помощью GET-запросов. Фундамент занимает в памяти всего около 20 МБ, что примерно равняется размеру нескольких картинок с котиками из интернета. Отныне никому не нужно будет закрывать клиент после попадания в игру (как делают некоторые игроки, чтобы освободить память).

    Это позволило нам еще ближе продвинуться к созданию "всегда доступного" клиента, что решало проблему №2. Фундамент может показывать сообщения (приглашения в игру или предложения дружбы) в области уведомлений, даже работая в фоновом режиме.

    ШАГ ТРЕТИЙ: ОПЯТЬ НА ТЕ ЖЕ ГРАБЛИ...

    Следующим шагом необходимо было сделать архитектуру расширяемой.

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

    Чтобы было понятнее, насколько важна расширяемость, я использую аналогию. Представьте, что десятерых писателей попросили написать одну книгу. Предположим, что над каждой главой они будут работать вместе (например, все они будут писать вторую главу под названием "LoL для новичков"). И это будет ужасно, ведь каждый из них будет менять предложения, написанные другим. Разумнее было бы поручить каждому писателю писать свою главу (например, один пишет пятую главу, "Таланты", а второй – шестую, "Руны"), позволив им работать независимо друг от друга. Разумеется, при этом нельзя забывать о том, что главы должны быть связаны между собой.

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

    Мне много раз доводилось работать над расширяемыми архитектурами, поэтому я прекрасно знаю, с какой легкостью они решают проблему пересечения разработчиков. Чтобы лишний раз не усложнять нашу архитектуру, мы выбрали простой и проверенный временем инструмент расширяемости – систему плагинов. Плагин – это независимый модуль для владения, разработки, тестирования и развертывания. Каждый плагин должен поддерживать семантическое версионирование и указывать, от каких плагинов или их версий он зависит, чтобы архитектура всегда оставалась прозрачной. Ко всему этому мы добавили график зависимостей, который помогает определить, какие плагины подключены..

    Таким образом, пользовательский интерфейс вместе с сопутствующим функционалом вошел в плагин front-end (FE), а коммуникационная логика C++ (хоть это и не самое точное название) – в плагин back-end (BE). И заметьте, оба типа плагинов уживаются друг с другом в обновленном клиенте LoL – мы используем термины "front-end" и "back-end" только потому, что архитектура имитирует типичную связку клиент-сервер, даже если при этом она входит в состав одного-единственного настольного приложения.

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

    image (4).jpg

    В процессе перехода на новую архитектуру нам пришлось распотрошить монолитный уровень данных JavaScript. Мы использовали ember-orbit, чтобы поддерживать единый связный граф объектов, представляющих наши ресурсы REST. И это было одним из главных источников головной боли – разные команды получали доступ к данным друг друга с помощью объектных ссылок, а не служебных вызовов. Такой уровень совместной работы нам был явно не нужен.

    Поэтому мы отказались от Orbit, а вместо него начали использовать простой кэш ресурсов под управлением плагинов front-end. Благодаря этому мы избавились от излишней сложности.

    ШАГ ЧЕТВЕРТЫЙ: СПРОСИТЕ N РАЗРАБОТЧИКОВ НА JAVASCRIPT ОБ ИХ ЛЮБИМОМ MVC-ФРЕЙМВОРКЕ, И ПОЛУЧИТЕ N+1 ОТВЕТОВ.

    Мы позволили каждой команде выбрать свой фреймворк JavaScript.

    Теперь у нас была более производительная архитектура, а команды, создающие функционал, стали работать быстрее и обзавелись четким разделением обязанностей.

    Тем не менее у нас возникла проблема. Некоторым командам не нравился Ember.js, и они хотели использовать веб-компоненты напрямую. У других команд были написаны свои собственные веб-приложения, использующие другие фреймворки, и они хотели внедрить их в новый клиент.

    С неохотой, но мы пошли разработчикам навстречу и сделали правило "Ember.js для всего" необязательным. Последствия отказа от Ember как от единственного встроенного фреймворка были не из легких.

    Поворотный момент наступил, когда мы поняли, что в такой огромной компании, как Riot, невозможно заставить всех разработчиков использовать даже одну и ту же версию Ember. Это стоило нам немалых трудов, но в итоге мы изменили архитектуру клиента таким образом, чтобы каждый из плагинов мог использовать свой собственный фреймворк – фреймворки JavaScript стали привязаны к плагинам front-end.

    Заметьте, что ключевое слово здесь "мог". WВ большинстве случаев мы по-прежнему используем Ember, но теперь это перестало быть жесткой технической необходимостью.

    ИТОГОВАЯ АРХИТЕКТУРА

    Спроектированная архитектура обновленного клиента теперь решает все три фундаментальные проблемы. Это движок, который дает возможность нескольким командам самостоятельно внедрять новый функционал HTML5 без ненужной зависимости, используя вспомогательную коммуникационную инфраструктуру, позволяющую игрокам всегда оставаться на связи. Этому способствует как движок хостинга микрослужб C++, так и веб-приложения JavaScript, плагины к которым подключаются индивидуально и динамически – в зависимости от прав конкретного игрока.

    Мы вновь провели опрос разработчиков и обнаружили, что продуктивность увеличилась на 15% и эта цифра быстро растет. Отлично!

    image (4).jpg

    Один из разработчиков сказал, что мы создали "настольный банк данных". Я же считаю, что новый клиент очень похож на Atom – расширяемый текстовый редактор от Github, основанный на CEF и созданный с помощью фреймворка Electron. В самом начале работы я и подумать не мог, что все закончится именно этим.

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


     
    ArtemDrowMag и iFirelife нравится это.
Комментарии
  1. codyyy
    ставь лукас, если ничего не понял DansGame
    Wotand, 4ubuk, Darknessxt и 23 другим нравится это.
  2. kasperg4
    понял только, то что будут делать еще и другие игры
    "Кроме того, мы стремимся быть студией нескольких игр"
    J_Jackdaws, Wani, FunFunFun и 4 другим нравится это.
  3. Darknessxt
    Графики, таблицы, непонятные термины, спс рито, я все понял! Даже читать не стал....
    Сларнак, Lovelas11, Dan1204 и 3 другим нравится это.
  4. Kombala
    Не верьте ему! Это обман, чтобы заработать классы!
    QQmore и iFirelife нравится это.
  5. ma3uk
    Очень и очень плохая идея, в будущем это будет кашей из 100500 фреймворков и чистого JS, раз уж взялись всё писать на Ember, то лучше бы и продолжали.
    sonlix, MeldInPeace, JazzJam и 2 другим нравится это.
  6. eriks0n
    Как я понял, они создали движок для создания и изменения самого клиента, а не сам клиент. Ну что сказать, молодцы. Если столько сил было потрачено на это, то что будет, если они будут делать новый движок для игры?!
    QQmore нравится это.
  7. Danet
    А где кнопка скачать?????????
    QQmore нравится это.
  8. KandiDrot
    Карточная, скорее всего. У них уже была такая задумка вроде.
  9. ronnar
    Ты не правильно понял. Перевожу на понятный язык: "Мы переделываем клиент на js. Получается довольно клёво."
    Остальное, по большому счету, описание причин того или иного шага - например, у меня создалось впечатление, что они сделают лобби лольца тонким клиентом. Довольно удобное решение, на самом-то деле. Или то что они разводят у себя зоопарк фреймворков(хз, может быть у них команды работают настолько изолировано, что это пофиг).
  10. Фокс
    очень много намеков на то, что это будет файтинг
  11. melkir
    Их программисты знают с++? А я-то думал, что они школьный паскаль только осваивают
  12. justas
    Они поставили как минимум неправильные задачи перед новым клиентом.
    ПРОБЛЕМА №1: HTML5 – СТАНДАРТИЗИРОВАННАЯ, ШИРОКО РАСПРОСТРАНЕННАЯ ПЛАТФОРМА.
    ПРОБЛЕМА №2: ИГРОКИ ХОТЯТ ОСТАВАТЬСЯ НА СВЯЗИ КАК В ИГРЕ, ТАК И ВНЕ ЕЕ.РОБЛЕМА №3: КОМАНДА РАЗРАБОТЧИКОВ RIOT ХОЧЕТ РАБОТАТЬ В ГАРМОНИИ.
    ------------------------------------------------------------------------------------------------------------------
    Я если честно вообще не понял как они эти проблемы получили, они новый клиент пишут или секту запиливают? :omglux:
    MeldInPeace, Tulshe, Dan1204 и ещё 1-му нравится это.
  13. Slashuurr
    Что же , возможно ЧМ этого сезона уже будет играться на новом клиенте . И это неплохо .
  14. GalioTasher
    Где мои тусовые скины?
  15. Furylon
    Если оставить клиент работать в фоновом режиме минут на 10+, то потом, найдя и гру, при загрузке чемпионов будет выпадать ошибка, что соединение потеряно, и придется перезагружать клиент. Поэтому, если я уверен, что в ближайшие мин 10 я не буду играть, я вырубаю клиент, и апотом снова включаю, а если получилось, что он простоял мин 10+, то приходиться его перезагрузить сразу. что бы не начинать игра 4 на 5 )
    JazzJam и Dan1204 нравится это.
  16. Minuano
    Recall: Heroes of the League
    Tulshe и Dan1204 нравится это.
  17. DeepMeInside
    рито плиз оставьте это уже хомякам, сделайте новую мобу:yoba::relax:
  18. joze3000
    Впринципе все это было ожидаемо, html5 сильно расширил свои функции, многие вангуют что в ближайшее время многие платформы будут переведены под эту основу -_-
    sonlix нравится это.
  19. Паровой Каток
    MMORPG :tsmile:
    С ежегодной перепилкой всего, что можно :tsmile:х2
    С огромным количеством лотерееподобных конкурсов для выкачки денег :tsmile:х5
    С завязанными на донате обязательными для игры плюхами :tsmile:х10
    С гриндом почище корейских игр :tsmile:х20
    Во вселенной Лиги Легенд :tsmile:х50
    С "хорошим балансом", опять таки завязанном на донате :tsmile:х100
    С маунтами, которых фиг достанешь и с "илитными" супермаунтами за донат :tsmile:х500
    С непроработаными и багнутыми наглухо обязательными квестами :tsmile:х999
    И на русском языке :tsmile:хAllods Online
  20. Sytrus
    А Рито случайно не объясняли, почему, по их мнению, лаунчер и сама игра не могут быть одним целым, как это сделано в других моба?
    Karleos и Tulshe нравится это.
  21. undeadbus
    Почему на русском борде есть, а на английской нет? Мне, например, очень интересно узнать подробности.
    --- добавлено: 30 май 2016 ---
    Это интересный вопрос.
  22. fantom79022
    Это то, что они описывали во второй проблеме
    Игроки закрывают лаунчер, чтобы он не жрал их оперативку. Они хотят, чтобы лаунчер был всегда включен и был максимально легким, чтобы его не нужно было выключать
    если совместить лаунчер и клиент - он будет весить куда больше, что наоборот усугубит вторую проблему
  23. undeadbus
    Нет, такого точно не может быть. Я просто программист, и решение разделять программу на два приложения, потому что какая-то часть программы тяжеловата для памяти, и поэтому игроки должны ее закрывать, кажется мне адским адом :awesome:
  24. Nash Fletcher
    Очень много гемора - тут пришлось бы переписывать и игру - встраивать туда лаунчер, повылезали бы баги и прочее.
    Когда (и если) лол будет переходить на новый движок тогда мб и совместят.

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

    Скорее всего перевод с какого-нибудь редита

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

    Мало того,что довольно много рассказали о технической стороне, так готовы больше рассказать,что радует.
    MeldInPeace нравится это.
  26. Ginez0n
    http://ru.leagueoflegends.com/ru/client-update/article/eb150672-c904-42f5-b5b6-b195f25b9772
  27. AngeuT
    Сколько лет вы работаете программистом и в какой области? Некоторые очереди могут длиться и 20 минут. Одно дело когда у юзера свернут тяжеловесный толстый клиент за браузером, в котором он зависает вк, а другое, когда он в момент переключается алт+таб на легковесный тонкий клиент, чтобы моментально принять игру.
  28. Nash Fletcher
    https://engineering.riotgames.com/news/architecture-league-client-update
    гспди тыж боже мой, пора понять что вся инфа по лиге, неважно про клиент или чампов или игру или *любое_другое_слово* в первую очередь появляется на языке-носителе создателей.
    Ру рито и здешние новости - это только ПЕРЕВОД
  29. DezOx
    Поскорей бы :)