Итак, к чему привел рефакторинг с хранимок на EntityFramework и что конкретно придется делать прежде чем двигаться дальше.
Из-за этого перехода невероятно сильно пострадала производительность. Если раньше действия по боям отрабатывали почти мгновенно, то теперь они могут занимать даже секунды. Не могу сказать, что это неожиданность, EF известен своей невысокой производительностью ради удобства использования в коде, но не думал, что разница будет настолько огромной.
Прямо сейчас на руках проблема вставки и вынимания суперчипов в бою, эта операция была мгновенной, а сейчас начала занимать 5-10-15 секунд, из-за чего игрок, попытавшийся улучшить свои статы на последних секундах боя, уснул и проиграл недавно прошедший клановый турнир. В принципе отчасти сам виноват, такие попытки затаймить бой и преподнести сюрприз команде противника нередко заканчиваются засыпаниями, но случай подсветил вполне реальную проблему, с которой будет невозможно запустить 3д-версию, да и сейчас в PvP боях это будет сильно мешать, поэтому не стоит откладывать в долгий ящик.
Что же конкретно произошло? В принципе ничего неожиданного: исполнение логики в базе давало очень быстрый доступ к данным в комбинации с мощными оптимизациями и кешированием от SQL Server, о которых разработчику за пределами индексов и адекватно написанных запросов думать было не нужно, оно просто работало очень хорошо, потому что SQL Server кучу работы делал под капотом. Переход на EF добавил уровень сети для чтения и записи данных, сериализацию/десериализацию, а также полное отсутствие кеша и прочих оптимизаций, которые теперь придется накручивать сверху вручную.
Вот какой кейс сейчас на руках:
- вставка суперчипа в бою приводит к пересчету статов игрока и всех его клонов
- в пересчете статов учитываются инъекции, которые как раз часто применяются на турнирах и которых один игрок может употребить до 401шт
- чтобы посчитать статы необходимо загрузить данные из порядка 15 таблиц с данными об игроке, во всех из них может быть только одна запись кроме... таблицы с инъекциями, там будет в пределе 401 запись
- и... все то же самое нужно повторить для всех клонов
Соответственно мы получаем два мультипликатора - инъекции и кол-во клонов на поле боя, что приводит к загрузке 416 записей из базы на каждого персонажа на карте, а это выборка из базы, пересылка данных по сети, десериализация, потом еще цикл O(n) по инъекциям, когда раньше благодаря простой агрегации данных на уровне SQL Server оба эти мультипликатора не роляли совсем, ну и сохранение посчитанных данных в базу, где опять сериализация, пересылка по сети и только потом сама запись.
Из-за этого перехода невероятно сильно пострадала производительность. Если раньше действия по боям отрабатывали почти мгновенно, то теперь они могут занимать даже секунды. Не могу сказать, что это неожиданность, EF известен своей невысокой производительностью ради удобства использования в коде, но не думал, что разница будет настолько огромной.
Прямо сейчас на руках проблема вставки и вынимания суперчипов в бою, эта операция была мгновенной, а сейчас начала занимать 5-10-15 секунд, из-за чего игрок, попытавшийся улучшить свои статы на последних секундах боя, уснул и проиграл недавно прошедший клановый турнир. В принципе отчасти сам виноват, такие попытки затаймить бой и преподнести сюрприз команде противника нередко заканчиваются засыпаниями, но случай подсветил вполне реальную проблему, с которой будет невозможно запустить 3д-версию, да и сейчас в PvP боях это будет сильно мешать, поэтому не стоит откладывать в долгий ящик.
Что же конкретно произошло? В принципе ничего неожиданного: исполнение логики в базе давало очень быстрый доступ к данным в комбинации с мощными оптимизациями и кешированием от SQL Server, о которых разработчику за пределами индексов и адекватно написанных запросов думать было не нужно, оно просто работало очень хорошо, потому что SQL Server кучу работы делал под капотом. Переход на EF добавил уровень сети для чтения и записи данных, сериализацию/десериализацию, а также полное отсутствие кеша и прочих оптимизаций, которые теперь придется накручивать сверху вручную.
Вот какой кейс сейчас на руках:
- вставка суперчипа в бою приводит к пересчету статов игрока и всех его клонов
- в пересчете статов учитываются инъекции, которые как раз часто применяются на турнирах и которых один игрок может употребить до 401шт
- чтобы посчитать статы необходимо загрузить данные из порядка 15 таблиц с данными об игроке, во всех из них может быть только одна запись кроме... таблицы с инъекциями, там будет в пределе 401 запись
- и... все то же самое нужно повторить для всех клонов
Соответственно мы получаем два мультипликатора - инъекции и кол-во клонов на поле боя, что приводит к загрузке 416 записей из базы на каждого персонажа на карте, а это выборка из базы, пересылка данных по сети, десериализация, потом еще цикл O(n) по инъекциям, когда раньше благодаря простой агрегации данных на уровне SQL Server оба эти мультипликатора не роляли совсем, ну и сохранение посчитанных данных в базу, где опять сериализация, пересылка по сети и только потом сама запись.
🤯5🥰2❤1
Решений у этой проблемы несколько, но стратегически мне нужно получить скалируемый горизонтально бой, поэтому я решил пойти по пути кеширования. Этот слон огромен, но его можно есть по частям:
- Сначала я отключу прямое взаимодействие контроллера боя с дата сервисом и сделаю между ними новый уровень абстракции, который будет работать через кеш. Введение новой сущности посередине поможет мне легко понять когда вся работа завершена - в этот момент можно будет разорвать зависимость контроллера на дата сервис через Dependencies. В результате мы будем лениво загружать данные в кеш и читать всегда из него, но писать в базу не перестанем.
- Потом я уберу мгновенную запись в базу при совершении действия - в этот момент данные в кеше и в базе разойдутся и кеш станет главным источником правды, а сохранение в базу будет происходить редко, например в конце раунда или даже боя, причем параллельно и не мешая самому бою в моменте. Это сменит роль БД на просто долгосрочное хранилище, когда все операции с боем будут происходить в памяти, что во-первых будет очень быстро, во-вторых скоуп кеша - конкретный бой, а значит не будет проблем с локами в базе при использовании одних и тех же таблиц для хранения данных разных боев.
- Ну и финальным этапом можно будет это все вынести в отдельный сервис, завернуть в контейнер и написать диспетчер, который будет поднимать в облаке контейнеры с сервисом расчета боев по мере роста нагрузки. Вот с этим уже можно будет смело запускаться на широкую аудиторию.
Прямо сейчас я займусь первой задачей и сделаю ее только частично - закеширую часть данных, перечитывание которых приводит к основным тормозам. Это позволит мне в моменте решить проблему с турнирами и заложить фундамент к долгосрочной цели, но при этом не уйти на месяцы разработки забросив 3D версию на Unreal Engine. Кроме того эту задачу потом можно делегировать, по протоптанной дорожке идти намного проще чем придумывать решение самому. Ну, конечно если будет кому...
- Сначала я отключу прямое взаимодействие контроллера боя с дата сервисом и сделаю между ними новый уровень абстракции, который будет работать через кеш. Введение новой сущности посередине поможет мне легко понять когда вся работа завершена - в этот момент можно будет разорвать зависимость контроллера на дата сервис через Dependencies. В результате мы будем лениво загружать данные в кеш и читать всегда из него, но писать в базу не перестанем.
- Потом я уберу мгновенную запись в базу при совершении действия - в этот момент данные в кеше и в базе разойдутся и кеш станет главным источником правды, а сохранение в базу будет происходить редко, например в конце раунда или даже боя, причем параллельно и не мешая самому бою в моменте. Это сменит роль БД на просто долгосрочное хранилище, когда все операции с боем будут происходить в памяти, что во-первых будет очень быстро, во-вторых скоуп кеша - конкретный бой, а значит не будет проблем с локами в базе при использовании одних и тех же таблиц для хранения данных разных боев.
- Ну и финальным этапом можно будет это все вынести в отдельный сервис, завернуть в контейнер и написать диспетчер, который будет поднимать в облаке контейнеры с сервисом расчета боев по мере роста нагрузки. Вот с этим уже можно будет смело запускаться на широкую аудиторию.
Прямо сейчас я займусь первой задачей и сделаю ее только частично - закеширую часть данных, перечитывание которых приводит к основным тормозам. Это позволит мне в моменте решить проблему с турнирами и заложить фундамент к долгосрочной цели, но при этом не уйти на месяцы разработки забросив 3D версию на Unreal Engine. Кроме того эту задачу потом можно делегировать, по протоптанной дорожке идти намного проще чем придумывать решение самому. Ну, конечно если будет кому...
👍3🤯3🔥2
Занявшись серверным кодом снова поймал себя на мысли, что программирование в 3D движках и "настоящее" программирование отличаются примерно как управление автомобилем в большом городе и машинкой в парке аттракционов. Я, наверное, сейчас поймаю волну хейта от разработчиков на Unity и UE, но думаю для расширения кругозора тех, кто следит за каналом в целях понимания как создается действительно масштабный проект, затрагивающий далеко не только движок, небольшое углубление в то, насколько сильно может отличаться работа разных программистов, будет как минимум интересно.
Я начал программировать в школе с Turbo Basic и почти сразу довольно сильно углубился в Pascal. Это процедурные языки и они сформировали мышление вида "программный код - это простыня текста, где переиспользуемые куски можно выносить в функции и вызывать с разными параметрами. Выполняется сверху вниз, максимум с отвлечением на процедуры, находящиеся в других модулях.".
Дальше познакомился с Visual Basic, Delphi и C++ (MFC). Это уже ООП и я отлично помню свое первое впечатление - "нифига себе сколько кода надо написать, чтобы отработало одно простейшее действие! Зачем все так переусложнять?". Почему придумано именно так стало понятно только на первой работе, где я уже столкнулся с C# и поработал с действительно большим проектом.
Следующим откровением стало многопоточное программирование, в котором уже нужно думать не только о логике своего кода, но и о том, как она поведет себя когда используемые в нем объекты будут параллельно использоваться этим же или другим кодом из других потоков.
Ну и SQL, где мыслить нужно не процедурами или объектами, а таблицами, в которых может быть очень много данных, и связями между ними, тоже стал чем-то новым не смотря на уже достаточно богатый к тому времени опыт.
Программирование в 3D движках - это очень усеченное ООП, в котором 80% кода выполняет простейшие манипуляции свойствами различных игровых объектов, и мыслить здесь нужно... кадрами. Я выше описывал принцип работы движков, почитайте кто пропустил, но если очень коротко - движок стремится отрисовать как можно больше кадров в секунду и выполняет ваш код в каждом из них. Функции, которые пишет программист на движке, при хорошо сделанной и оптимизированной игре выполняются +-60 раз в секунду и именно об этом нужно всегда помнить создавая код. Многопоточность, конечно, есть, но она максимально скрыта от разработчика. Например если нужно отправить запрос по сети - это делается внутри одного кадра, а потом, спустя сотни или тысячи кадров мы просто получим callback, который в еще одном кадре поменяет какие-то свойства, с которыми в свою очередь уже работает тот самый код, вызываемый в каждом кадре, двигающий объекты по сцене, отслеживающий коллизии, меняющий кадры анимаций и т.п..
В отдельную категорию я бы еще выделил шейдеры. Это понять программисту, привыкшему работать с логическими операторами, в принципе сложно, потому что логики там, как правило, нет из-за очень высокой ее дороговизны при выполнении. Код шейдера выполняется на GPU, поэтому там в 99% случаев исключительно математические операторы, а логика достигается за счет параметризации и использования математических операторов внутри шейдера, т.е. если вам нужно условие типа IF, чтобы покрасить что-то в, например, красный или зеленый цвет - достигаться это будет, например, за счет умножения красного или зеленого каналов на 0 или 1, в зависимости от входящего или вычисленного значения другой переменной. С прямым назначением, вроде получения более светлого пикселя при попадании на него света или более темного если он находится дальше источника света, конечно, все попроще - мы просто умножаем цвет предмета на цвет света в этой конкретной точке.
Я начал программировать в школе с Turbo Basic и почти сразу довольно сильно углубился в Pascal. Это процедурные языки и они сформировали мышление вида "программный код - это простыня текста, где переиспользуемые куски можно выносить в функции и вызывать с разными параметрами. Выполняется сверху вниз, максимум с отвлечением на процедуры, находящиеся в других модулях.".
Дальше познакомился с Visual Basic, Delphi и C++ (MFC). Это уже ООП и я отлично помню свое первое впечатление - "нифига себе сколько кода надо написать, чтобы отработало одно простейшее действие! Зачем все так переусложнять?". Почему придумано именно так стало понятно только на первой работе, где я уже столкнулся с C# и поработал с действительно большим проектом.
Следующим откровением стало многопоточное программирование, в котором уже нужно думать не только о логике своего кода, но и о том, как она поведет себя когда используемые в нем объекты будут параллельно использоваться этим же или другим кодом из других потоков.
Ну и SQL, где мыслить нужно не процедурами или объектами, а таблицами, в которых может быть очень много данных, и связями между ними, тоже стал чем-то новым не смотря на уже достаточно богатый к тому времени опыт.
Программирование в 3D движках - это очень усеченное ООП, в котором 80% кода выполняет простейшие манипуляции свойствами различных игровых объектов, и мыслить здесь нужно... кадрами. Я выше описывал принцип работы движков, почитайте кто пропустил, но если очень коротко - движок стремится отрисовать как можно больше кадров в секунду и выполняет ваш код в каждом из них. Функции, которые пишет программист на движке, при хорошо сделанной и оптимизированной игре выполняются +-60 раз в секунду и именно об этом нужно всегда помнить создавая код. Многопоточность, конечно, есть, но она максимально скрыта от разработчика. Например если нужно отправить запрос по сети - это делается внутри одного кадра, а потом, спустя сотни или тысячи кадров мы просто получим callback, который в еще одном кадре поменяет какие-то свойства, с которыми в свою очередь уже работает тот самый код, вызываемый в каждом кадре, двигающий объекты по сцене, отслеживающий коллизии, меняющий кадры анимаций и т.п..
В отдельную категорию я бы еще выделил шейдеры. Это понять программисту, привыкшему работать с логическими операторами, в принципе сложно, потому что логики там, как правило, нет из-за очень высокой ее дороговизны при выполнении. Код шейдера выполняется на GPU, поэтому там в 99% случаев исключительно математические операторы, а логика достигается за счет параметризации и использования математических операторов внутри шейдера, т.е. если вам нужно условие типа IF, чтобы покрасить что-то в, например, красный или зеленый цвет - достигаться это будет, например, за счет умножения красного или зеленого каналов на 0 или 1, в зависимости от входящего или вычисленного значения другой переменной. С прямым назначением, вроде получения более светлого пикселя при попадании на него света или более темного если он находится дальше источника света, конечно, все попроще - мы просто умножаем цвет предмета на цвет света в этой конкретной точке.
👏3🤯3😱2👍1
Кстати, я много раз упоминал о том, как мне не нравится работать с блюпринтами в UE и, честно говоря, сейчас, работая над серверной частью, получаю огромное удовольствие именно от работы с кодом, но блюпринты очень круто облегчают понимание и работу именно с шейдерами, где в противном случае мозг ломается очень быстро. При программировании шейдера путем написания кода, мыслить нужно цветом каждого конкретного пикселя и комбинацией математических операций, которые приведут к желаемому результату.
👍5👏3🔥1
Игрок всегда врёт.
Об этом всегда должен помнить разработчик любой многопользовательской игры. Не смотря на то, что это абсолютно очевидная аксиома, которая является правдой не только в играх, а вообще в любых клиент-серверных приложениях, открытых для публичного использования, даже в своей профессиональной деятельности я очень часто встречал непонимание этого момента со стороны опытных программистов.
Речь идет о том, что разрабатывая бэкенд, доступный для публичного использования, программист должен всегда по умолчанию считать клиента скомпрометированным, потому что если этого не делать - он 100% будет реально скомпрометирован, и очень быстро. Если вы когда-то публиковали даже просто сайт в интернете - знаете, что его почти сразу начинают сканировать сотни ботов, которые ищут уязвимости. Это видно в логах веб сервера и, как правило, логах приложения, потому что они генерят тонны невалидных реквестов, что приводит к ошибкам выполнения.
Применительно к играм это означает, что мы:
- от игрока на входе можем принимать только действия, но не данные (за исключением базовых - имя и прочее)
- каждое действие валидируем, сначала на уровне ролей - залогинен ли игрок, разрешен ли конкретно этому игроку доступ к конкретно этому функционалу
- потом на адекватность, например может ли игрок иметь доступ к функционалу, находясь в определенной локации или бою
- и, самое сложное, проверяем на реализуемость действия человеком, а не ботом
Если этого не делать, а принимать, например, на входе от игрока кол-во игровой валюты, которое у него есть, считая "ну это же значение, переданное ранее с сервера и потом посчитанное на клиенте моим же кодом", количество хп, статы или не проверять допустимость операции, опираясь лишь на ограниченность игрока вашим интерфейсом - вас очень быстро сломают, что приведет к быстрой гибели проекта. В любой многопользовательской игре с элементами пвп главным принципом является равность условий для всех игроков, если заведется хоть один жук, который стал "равнее", потому что пошел в обход интерфейса и накрутил себе чего-нить через прямые запросы к серверу - остальные очень быстро это поймут и проголосуют ногами.
Отслеживание ботов - самый сложный случай, потому что полностью достоверно отличить игрока от бота почти невозможно. Вообще все игры без исключения автоматизируются, а те, которые предлагают возможность заработка реальных денег постоянно гибнут именно из-за этого - люди создают целые фермы из телефонов или компьютеров, стремящиеся максимально быстро и эффективно отфармить такой проект, в итоге обычные игроки разбегаются и фермеры играют только с такими же, из-за чего пропадает приток новых средств и зарабатывать и самим фермерам становится не с кого. Я знаю, что поверх веб версии Genesyx тоже написана куча ботов, и немало игроков из-за этого ушли в бан. Полностью вылечить эту чуму невозможно, но очень важно следить за тем, чтобы она не превышала разумные пределы и как минимум вычищать совсем уж неадекватные случаи - когда игрок качается круглосуточно без остановок например, или кликает слишком быстро, или ходит по маршрутам, не предусмотренным интерфейсом и т.п..
Удался кликбейт? 😁
Об этом всегда должен помнить разработчик любой многопользовательской игры. Не смотря на то, что это абсолютно очевидная аксиома, которая является правдой не только в играх, а вообще в любых клиент-серверных приложениях, открытых для публичного использования, даже в своей профессиональной деятельности я очень часто встречал непонимание этого момента со стороны опытных программистов.
Речь идет о том, что разрабатывая бэкенд, доступный для публичного использования, программист должен всегда по умолчанию считать клиента скомпрометированным, потому что если этого не делать - он 100% будет реально скомпрометирован, и очень быстро. Если вы когда-то публиковали даже просто сайт в интернете - знаете, что его почти сразу начинают сканировать сотни ботов, которые ищут уязвимости. Это видно в логах веб сервера и, как правило, логах приложения, потому что они генерят тонны невалидных реквестов, что приводит к ошибкам выполнения.
Применительно к играм это означает, что мы:
- от игрока на входе можем принимать только действия, но не данные (за исключением базовых - имя и прочее)
- каждое действие валидируем, сначала на уровне ролей - залогинен ли игрок, разрешен ли конкретно этому игроку доступ к конкретно этому функционалу
- потом на адекватность, например может ли игрок иметь доступ к функционалу, находясь в определенной локации или бою
- и, самое сложное, проверяем на реализуемость действия человеком, а не ботом
Если этого не делать, а принимать, например, на входе от игрока кол-во игровой валюты, которое у него есть, считая "ну это же значение, переданное ранее с сервера и потом посчитанное на клиенте моим же кодом", количество хп, статы или не проверять допустимость операции, опираясь лишь на ограниченность игрока вашим интерфейсом - вас очень быстро сломают, что приведет к быстрой гибели проекта. В любой многопользовательской игре с элементами пвп главным принципом является равность условий для всех игроков, если заведется хоть один жук, который стал "равнее", потому что пошел в обход интерфейса и накрутил себе чего-нить через прямые запросы к серверу - остальные очень быстро это поймут и проголосуют ногами.
Отслеживание ботов - самый сложный случай, потому что полностью достоверно отличить игрока от бота почти невозможно. Вообще все игры без исключения автоматизируются, а те, которые предлагают возможность заработка реальных денег постоянно гибнут именно из-за этого - люди создают целые фермы из телефонов или компьютеров, стремящиеся максимально быстро и эффективно отфармить такой проект, в итоге обычные игроки разбегаются и фермеры играют только с такими же, из-за чего пропадает приток новых средств и зарабатывать и самим фермерам становится не с кого. Я знаю, что поверх веб версии Genesyx тоже написана куча ботов, и немало игроков из-за этого ушли в бан. Полностью вылечить эту чуму невозможно, но очень важно следить за тем, чтобы она не превышала разумные пределы и как минимум вычищать совсем уж неадекватные случаи - когда игрок качается круглосуточно без остановок например, или кликает слишком быстро, или ходит по маршрутам, не предусмотренным интерфейсом и т.п..
Удался кликбейт? 😁
❤6🔥3🥰1🤯1🗿1
Media is too big
VIEW IN TELEGRAM
Прощупывал вопрос локализации еще на старте проекта, теперь могу поделиться реальным опытом.
1. Все классно сделано в редакторе UE, можно делать локализацию на любом этапе разработки.
2. Процесс фактического добавления переведенного текста работает через одно место:
- Куча лишних кнопок (редактировать текст, считать слова, компилировать текст)
- Каждая запускает внешние процессы, которые постоянно зависают, приходится перезапускать UE, искать и убивать зависшие процессы
- Логи очень длинные и не дают никакой вменяемой инфы по причинам проблем
3. Львиную часть самого перевода можно сделать через ИИ: экспортируем ключи в *.op файл, скармливаем Deepseek, получаем назад такой же файл с переводом, импортируем в движок.
4. Но проверять и дорабатывать вручную все равно придется - ИИ совершает глупые ошибки (Ирвинг где-то переведен как Irving, где-то - Irgving) и недостаточно хорошо работает со смысловым развитием (например "козел" в контексте брани переведен в лоб как "goat").
Запись с экрана телефона.
1. Все классно сделано в редакторе UE, можно делать локализацию на любом этапе разработки.
2. Процесс фактического добавления переведенного текста работает через одно место:
- Куча лишних кнопок (редактировать текст, считать слова, компилировать текст)
- Каждая запускает внешние процессы, которые постоянно зависают, приходится перезапускать UE, искать и убивать зависшие процессы
- Логи очень длинные и не дают никакой вменяемой инфы по причинам проблем
3. Львиную часть самого перевода можно сделать через ИИ: экспортируем ключи в *.op файл, скармливаем Deepseek, получаем назад такой же файл с переводом, импортируем в движок.
4. Но проверять и дорабатывать вручную все равно придется - ИИ совершает глупые ошибки (Ирвинг где-то переведен как Irving, где-то - Irgving) и недостаточно хорошо работает со смысловым развитием (например "козел" в контексте брани переведен в лоб как "goat").
Запись с экрана телефона.
🔥3⚡1❤1👍1🥰1
Рефакторинг - тот самый случай, когда тратишь кучу времени для того, чтобы получить на выходе полное отсутствие функциональных изменений, но при этом это и есть лучший ожидаемый результат.
Суть рефакторинга заключается в улучшении именно нефункциональных вещей - миграции на новую технологию, повышения производительности и т.п., поэтому конечная цель - все работает как и раньше в функциональном плане, но на новом коде.
Добиваться этого лучше всего через автоматическое тестирование: сначала покрываем переписываемый функционал автотестами, убеждаемся, что они затрагивают все ключевые моменты функционала и работают на старом коде, потом переписываем код и снова добиваемся работы тестов.
Программисты обычно очень не любят писать тесты, но в долгосроке они всегда окупают себя сполна. Благодаря Мише тесты у меня есть.
А насколько автоматическое тестирование распространено в играх на движках? Там же в основном гуй, плюс проекты подолгу не поддерживаются, наверное не самая лучшая трата времени.
Суть рефакторинга заключается в улучшении именно нефункциональных вещей - миграции на новую технологию, повышения производительности и т.п., поэтому конечная цель - все работает как и раньше в функциональном плане, но на новом коде.
Добиваться этого лучше всего через автоматическое тестирование: сначала покрываем переписываемый функционал автотестами, убеждаемся, что они затрагивают все ключевые моменты функционала и работают на старом коде, потом переписываем код и снова добиваемся работы тестов.
Программисты обычно очень не любят писать тесты, но в долгосроке они всегда окупают себя сполна. Благодаря Мише тесты у меня есть.
А насколько автоматическое тестирование распространено в играх на движках? Там же в основном гуй, плюс проекты подолгу не поддерживаются, наверное не самая лучшая трата времени.
🔥6❤2👍2🥰1
За последние пару недель существенно продвинулся с кешированием боев, на текущий момент сделано процентов 70 из запланированного.
В процессе возникает много технических моментов, о которых можно было бы здесь рассказать, но не знаю насколько вам будет интересно. Поставьте огонь этому посту если чуть более чем совсем поверхностные технические вопросы вам интересны, если наберется хотя бы 10 - буду иногда о них писать.
А сегодня хотел бы продолжить тему тестирования. После окончания моей основной карьеры, где был многоуровневый и сложный процесс тестирования, т.к. мы разрабатывали финансовый софт для очень больших дядек, довелось поработать в российской компании, которая разрабатывает свои собственные сервисы. Сказать, что там тестирования нет совсем - значит не сказать ничего. Но я бы не поднимал эту тему если бы так было только в одной отдельно взятой компании. Как вам нравится то, что каждый день на телефон прилетают десятки обновлений приложений? Если бы еще у нас по прежнему все нормально работало через Google Play, как раньше, может не раздражало бы, а с тем, как с обновлениями работает RuStore... я перешел на запуск обновлений вручную раз в неделю. А дальше заезжаешь на какую-нибудь редко используемую заправку, открываешь приложение, а там - обновись, чтобы получить QR-код для накопления баллов. И все бы ничего, но ты посреди леса с очень плохим интернетом.
И это прямое следствие современного подхода к тестированию. Большинство разработчиков и компаний, дабы избавиться от сложных процессов, перешли на модель continuous delivery - это когда изменений вносится минимум и они сразу идут в релиз и выливаются на площадку, буквально каждый день. Поскольку изменений всегда мало - они не могут сломать очень много, а если и сломают - локализовать и починить проблему или откатиться на предыдущую версию можно быстро и просто. Хороший подход, кроме того, что существенно расхлябывает разработчиков и ведет к постоянным обновлениям, которые могут сыграть с вами злую шутку в неудачный момент.
Значит ли это, что классический подход с долгой разработкой мажорных версий, автоматическим тестированием и долгим релиз и апгрейд циклом ушел в прошлое? Нет. Представьте себе что произойдет если профессиональному участнику фондового рынка какой-нибудь джун выльет малейшее изменение, где случайно ошибся в одной точке и в результате трейдер совершит сделку на миллион вместо 100 долларов.
В Genesyx сейчас подход гибридный. С одной стороны это всего лишь игра, никто не потеряет деньги и не умрет если выйдет билд с багом, но с другой - я сейчас работаю с самым ядром проекта, где изменение одной строчки может разломать всю боевую систему в множестве мест, плюс есть очень много взаимосвязанных вещей, например если что-то закешировал, но где-то что-то другое обновляет данные в обход кеша - рабочего билда не получится пока все не сделано в комплексе, а в итоге набегает очень много изменений. В этом плане наличие автоматического (спасибо, Миша) и ручного (спасибо, Антон) тестирования очень сильно выручает и помогает как минимизировать кол-во циклов апгрейда, так и увеличить скорость релиза. Тем не менее я все равно разбиваю работу на сущности, итеративно переезжающие в кеш, и потихоньку выливаю изменения на прод, после тестирования, чтобы они параллельно обкатывались в боевых условиях и не копились пока я работаю над следующей сущностью в отдельном бранче.
А вы видели в современных мобильных играх с серверной частью вот это "Проходит обновление, завершится через 40 минут"? А через 40 минут - еще час двадцать, потом еще 15 минут... Что они делают все это время? И речь же не про инди-игры, а про вполне себе нормально зарабатывающие.
В процессе возникает много технических моментов, о которых можно было бы здесь рассказать, но не знаю насколько вам будет интересно. Поставьте огонь этому посту если чуть более чем совсем поверхностные технические вопросы вам интересны, если наберется хотя бы 10 - буду иногда о них писать.
А сегодня хотел бы продолжить тему тестирования. После окончания моей основной карьеры, где был многоуровневый и сложный процесс тестирования, т.к. мы разрабатывали финансовый софт для очень больших дядек, довелось поработать в российской компании, которая разрабатывает свои собственные сервисы. Сказать, что там тестирования нет совсем - значит не сказать ничего. Но я бы не поднимал эту тему если бы так было только в одной отдельно взятой компании. Как вам нравится то, что каждый день на телефон прилетают десятки обновлений приложений? Если бы еще у нас по прежнему все нормально работало через Google Play, как раньше, может не раздражало бы, а с тем, как с обновлениями работает RuStore... я перешел на запуск обновлений вручную раз в неделю. А дальше заезжаешь на какую-нибудь редко используемую заправку, открываешь приложение, а там - обновись, чтобы получить QR-код для накопления баллов. И все бы ничего, но ты посреди леса с очень плохим интернетом.
И это прямое следствие современного подхода к тестированию. Большинство разработчиков и компаний, дабы избавиться от сложных процессов, перешли на модель continuous delivery - это когда изменений вносится минимум и они сразу идут в релиз и выливаются на площадку, буквально каждый день. Поскольку изменений всегда мало - они не могут сломать очень много, а если и сломают - локализовать и починить проблему или откатиться на предыдущую версию можно быстро и просто. Хороший подход, кроме того, что существенно расхлябывает разработчиков и ведет к постоянным обновлениям, которые могут сыграть с вами злую шутку в неудачный момент.
Значит ли это, что классический подход с долгой разработкой мажорных версий, автоматическим тестированием и долгим релиз и апгрейд циклом ушел в прошлое? Нет. Представьте себе что произойдет если профессиональному участнику фондового рынка какой-нибудь джун выльет малейшее изменение, где случайно ошибся в одной точке и в результате трейдер совершит сделку на миллион вместо 100 долларов.
В Genesyx сейчас подход гибридный. С одной стороны это всего лишь игра, никто не потеряет деньги и не умрет если выйдет билд с багом, но с другой - я сейчас работаю с самым ядром проекта, где изменение одной строчки может разломать всю боевую систему в множестве мест, плюс есть очень много взаимосвязанных вещей, например если что-то закешировал, но где-то что-то другое обновляет данные в обход кеша - рабочего билда не получится пока все не сделано в комплексе, а в итоге набегает очень много изменений. В этом плане наличие автоматического (спасибо, Миша) и ручного (спасибо, Антон) тестирования очень сильно выручает и помогает как минимизировать кол-во циклов апгрейда, так и увеличить скорость релиза. Тем не менее я все равно разбиваю работу на сущности, итеративно переезжающие в кеш, и потихоньку выливаю изменения на прод, после тестирования, чтобы они параллельно обкатывались в боевых условиях и не копились пока я работаю над следующей сущностью в отдельном бранче.
А вы видели в современных мобильных играх с серверной частью вот это "Проходит обновление, завершится через 40 минут"? А через 40 минут - еще час двадцать, потом еще 15 минут... Что они делают все это время? И речь же не про инди-игры, а про вполне себе нормально зарабатывающие.
🔥16❤4🥰2👍1👏1
Огней набрали, значит буду иногда погружаться в технические детали глубже чем обычно.
Ну и давайте, наконец, подведем итоги прошедшего года и наметим следующие шаги.
- Блог начался 23 августа 2024 года в очень прокрастинирующем состоянии, его основной целью было возродить процесс разработки.
- Изначальной идеей было восстановление знаний по существующему проекту в Unity, перевод его на рельсы Android и доработка с последующим запуском игры.
- Спустя недолгое время стал очевидным неприятный факт - проект в Unity настолько устарел и развален, что проще начать все сначала.
- По совету Олега и небольшого ресерча было принято решение делать проект на Unreal Engine вместо Unity и процесс стартовал.
- Ровно год назад я уже завершал перенос первой сцены из Unity в Unreal Engine.
- На текущий момент полностью готова первая сцена, на ее основе почти полностью готов туториал, сделано поле боя, перенесено множество моделей персонажей и оружия, найдено решение по совмещению анимаций, разработанных под разные скелеты, опробованы эффекты, и это все работает на телефоне под Android.
Ну и давайте, наконец, подведем итоги прошедшего года и наметим следующие шаги.
- Блог начался 23 августа 2024 года в очень прокрастинирующем состоянии, его основной целью было возродить процесс разработки.
- Изначальной идеей было восстановление знаний по существующему проекту в Unity, перевод его на рельсы Android и доработка с последующим запуском игры.
- Спустя недолгое время стал очевидным неприятный факт - проект в Unity настолько устарел и развален, что проще начать все сначала.
- По совету Олега и небольшого ресерча было принято решение делать проект на Unreal Engine вместо Unity и процесс стартовал.
- Ровно год назад я уже завершал перенос первой сцены из Unity в Unreal Engine.
- На текущий момент полностью готова первая сцена, на ее основе почти полностью готов туториал, сделано поле боя, перенесено множество моделей персонажей и оружия, найдено решение по совмещению анимаций, разработанных под разные скелеты, опробованы эффекты, и это все работает на телефоне под Android.
🔥4👏1
Много это или мало?
Однозначно можно было сделать больше. 4 месяца я не занимался проектом совсем, да и начиная с января фокус сместился на другое хобби и работе с Genesyx я стал уделять существенно меньше времени.
Но...
Во-первых с нуля был изучен новый движок и пройден основной путь по созданию сцены со всеми необходимыми сущностями, объектами, анимациями, эффектами и скриптами, необходимыми для разработки всего проекта. Сейчас уже можно утверждать, что в зоне неизвестного осталось процентов 10 функционала.
Во-вторых, что самое главное, проект полноценно вернулся к разработке. Больше не стоит вопрос "делать или нет", скорее "делать это или то". В этом огромна заслуга блога и всех вас, кто проявил к нему интерес и неустанно поддерживал меня на этом пути.
Масштабы проекта были понятны изначально, как и то, что добиться здесь успеха с текущим размером команды будет очень непросто, и в какой-то момент мне казалось, что все движется слишком медленно и, возможно, стоит прекратить. Но, как говорится, все познается в сравнении.
В этот момент мне помог Антон - он просто скинул ссылки на пару других команд, которые тоже занимаются инди-разработкой и знаете что?
- В первой команде 15 человек, они работают над проектом 5 лет и на текущий момент... их прогресс сопоставим с моим. Сделано прям совсем чуть-чуть больше.
- В другой команде 1 человек, тоже работает над проектом 5 лет и сделано суммарно раза в 2 больше.
Не оправдания ради, а мотивации для...
Однозначно можно было сделать больше. 4 месяца я не занимался проектом совсем, да и начиная с января фокус сместился на другое хобби и работе с Genesyx я стал уделять существенно меньше времени.
Но...
Во-первых с нуля был изучен новый движок и пройден основной путь по созданию сцены со всеми необходимыми сущностями, объектами, анимациями, эффектами и скриптами, необходимыми для разработки всего проекта. Сейчас уже можно утверждать, что в зоне неизвестного осталось процентов 10 функционала.
Во-вторых, что самое главное, проект полноценно вернулся к разработке. Больше не стоит вопрос "делать или нет", скорее "делать это или то". В этом огромна заслуга блога и всех вас, кто проявил к нему интерес и неустанно поддерживал меня на этом пути.
Масштабы проекта были понятны изначально, как и то, что добиться здесь успеха с текущим размером команды будет очень непросто, и в какой-то момент мне казалось, что все движется слишком медленно и, возможно, стоит прекратить. Но, как говорится, все познается в сравнении.
В этот момент мне помог Антон - он просто скинул ссылки на пару других команд, которые тоже занимаются инди-разработкой и знаете что?
- В первой команде 15 человек, они работают над проектом 5 лет и на текущий момент... их прогресс сопоставим с моим. Сделано прям совсем чуть-чуть больше.
- В другой команде 1 человек, тоже работает над проектом 5 лет и сделано суммарно раза в 2 больше.
Не оправдания ради, а мотивации для...
🔥9👏6
Какие ожидания не оправдались.
Во-первых я пришел к выводу, что блогерство - не мое :). Правда не понимаю тех, кому делать это регулярно в кайф, для меня это скорее работа, дополнительная к самой разработке, и иногда необходимость что-то написать в блог борется с необходимостью что-то сделать по проекту. Это не значит, что блог закрывается, но раньше я стремился писать один пост в день, теперь буду это делать реже, отдавая больше времени под саму разработку.
Во-вторых все мои предыдущие хобби-проекты всегда очень быстро находили единомышленников, которые присоединялись к процессу и сильно ему помогали. Начиная разработку я писал о том, что ожидаю, что это произойдет и здесь, но почему-то нет... Не поверю, что Genesyx 3D - менее интересный проект, чем все, что было до него, скорее у всех вокруг появилось слишком много возможностей потратить время веселее и работа на энтузиазме больше никому не нужна. Да и самих похожих начинаний развелось очень много, зайди в любое сообщество по геймдеву - везде раздел о поиске работы пестрит объявлении о присоединении к проекту на энтузиазме. Стоит ли говорить о том, что подавляющее их большинство ничем не заканчивается? Прекрасно понимаю почему от этого уже тошнит, но хочу также сказать вот что...
- Я не из тех, кто начинает что-то не планируя это довести до результата.
- Да, в силу разных причин прогресс идет медленнее чем мог бы, но он идет уже 15(!) лет, имеет результат в продакшене, коммерческий успех и через Genesyx уже прошло не одно поколение игроков.
- Как много разработчиков с форумов начинают проект, имея уже готовый успешный проект, 15 лет опыта в почти всех аспектах гейм дева и 25 лет опыта разработки, от очень мелкой до огромной, за спиной?
Во-первых я пришел к выводу, что блогерство - не мое :). Правда не понимаю тех, кому делать это регулярно в кайф, для меня это скорее работа, дополнительная к самой разработке, и иногда необходимость что-то написать в блог борется с необходимостью что-то сделать по проекту. Это не значит, что блог закрывается, но раньше я стремился писать один пост в день, теперь буду это делать реже, отдавая больше времени под саму разработку.
Во-вторых все мои предыдущие хобби-проекты всегда очень быстро находили единомышленников, которые присоединялись к процессу и сильно ему помогали. Начиная разработку я писал о том, что ожидаю, что это произойдет и здесь, но почему-то нет... Не поверю, что Genesyx 3D - менее интересный проект, чем все, что было до него, скорее у всех вокруг появилось слишком много возможностей потратить время веселее и работа на энтузиазме больше никому не нужна. Да и самих похожих начинаний развелось очень много, зайди в любое сообщество по геймдеву - везде раздел о поиске работы пестрит объявлении о присоединении к проекту на энтузиазме. Стоит ли говорить о том, что подавляющее их большинство ничем не заканчивается? Прекрасно понимаю почему от этого уже тошнит, но хочу также сказать вот что...
- Я не из тех, кто начинает что-то не планируя это довести до результата.
- Да, в силу разных причин прогресс идет медленнее чем мог бы, но он идет уже 15(!) лет, имеет результат в продакшене, коммерческий успех и через Genesyx уже прошло не одно поколение игроков.
- Как много разработчиков с форумов начинают проект, имея уже готовый успешный проект, 15 лет опыта в почти всех аспектах гейм дева и 25 лет опыта разработки, от очень мелкой до огромной, за спиной?
❤4🔥3👍2🤔2
На текущий момент я могу сказать, что команда состоит из двух человек - меня и Антона. Антон выполняет роль комьюнити менеджера, очень сильно помогает с тестированием и другими мелкими вещами. В этот блог вы тоже, скорее всего, попали по его объявлению где-то в интернете.
Также Миша и Олег сделали невероятно много для проекта, сейчас больше занимаются своими делами, но время от времени помогают когда обращаюсь.
И на этом, пожалуй, все. Несколько человек порывались подключиться и меня невероятно мотивирует то, что блог вызывает такое желание, но, к сожалению, дальше первой задачи пока никто не продвинулся - по факту бросаем не начав...
Я рассуждал о том, какого размера должна быть команда, чтобы этот проект двигался быстро в начале блога и это... минимум 15 человек, все разных профессий, по одному из каждой.
Чуть больше года назад в этом блоге был один подписчик, сейчас нас 227, при том, что раскруткой никто не занимался, большинство - люди, интересующиеся геймдевом. Если вам нравится то, чем я занимаюсь, вы хотели бы попробовать себя в большом проекте, который с высокой вероятностью будет запущен, при этом получить менторство от опытного профессионала - не сдерживайте себя :). Я не учитель и лекций не обещаю, но если вы уже что-то умеете и хотите это развить на реальном проекте, получив четкие направления, задачи и инструкции - вам ко мне.
Также Миша и Олег сделали невероятно много для проекта, сейчас больше занимаются своими делами, но время от времени помогают когда обращаюсь.
И на этом, пожалуй, все. Несколько человек порывались подключиться и меня невероятно мотивирует то, что блог вызывает такое желание, но, к сожалению, дальше первой задачи пока никто не продвинулся - по факту бросаем не начав...
Я рассуждал о том, какого размера должна быть команда, чтобы этот проект двигался быстро в начале блога и это... минимум 15 человек, все разных профессий, по одному из каждой.
Чуть больше года назад в этом блоге был один подписчик, сейчас нас 227, при том, что раскруткой никто не занимался, большинство - люди, интересующиеся геймдевом. Если вам нравится то, чем я занимаюсь, вы хотели бы попробовать себя в большом проекте, который с высокой вероятностью будет запущен, при этом получить менторство от опытного профессионала - не сдерживайте себя :). Я не учитель и лекций не обещаю, но если вы уже что-то умеете и хотите это развить на реальном проекте, получив четкие направления, задачи и инструкции - вам ко мне.
👍3🔥2🤝1
На последок напомню (уже писал ранее) почему в этом проекте (пока) нет денег.
Основная моя занятость сейчас - инвестиционная. И, разумеется, среди знакомых есть люди, готовые "вложиться в любое твое начинание". Но именно по той причине, по которой они хотят вложиться, я и не хочу привлекать инвестиции. Из-за моей гиперответственности любые внешние инвестиции в проект сразу станут кабалой на шее, а я не для того всю жизнь работал, чтобы получить новую работу в подарок. Для меня принципиально то, чтобы проект оставался в зоне хобби и можно было бы делать действительно интересную игру, не заботясь о ее финансовой составляющей.
Но это абсолютно не означает, что проект будет сугубо альтруистическим и не станет успешным коммерчески. Практика показывает, что за хороший продукт люди готовы платить сами и, разумеется, им будет предоставлена такая возможность. Доходы будут направляться на профессиональную помощь в доработке, излишки - делиться между теми, кто стоял у основ, соразмерно их вкладу. А там, глядишь, это может вырасти и в полноценную компанию.
Скорее всего мне в любом случае придется нанимать профессионалов своего дела на финальных этапах для того, чтобы вычистить глубокие ньюансы, на изучение которых у меня не хватает терпения в процессе, а релизиться с ними стыдно. Готов это делать, но на текущий момент мне хотелось бы собрать единомышленников, для которых разработка игры - не меньшее удовольствие чем поход в бар или поездка на море. На таком подходе можно сделать очень много и, зачастую, лучше тех, кто сейчас клепает посредственные вытаскивалки денег из населения пачками.
Если вы один из следующих специалистов и вам интересно поучаствовать - пишите, для следующих ролей найдется неспешное занятие на свободное время прямо сейчас:
- .NET разработчик + SQL (доработка бэкенда)
- Unreal Engine разработчик (блюпринты)
- Моделлер (создание 3д-моделей и текстур)
- Аниматор (создание анимаций, риг персонажей)
- Animation programmer (правильная интеграция анимаций в UE)
- Тестировщик
- UI/UX
- Technical artist (освещение, шейдеры и т.п.)
- Sound designer (звуки, музыка)
- Гейм дизайнер (баланс, экономика и т.п.)
- Нарративный дизайнер (туториалы, квесты, ЛОР)
- Маркетолог
- Дизайнер эффектов
Основная моя занятость сейчас - инвестиционная. И, разумеется, среди знакомых есть люди, готовые "вложиться в любое твое начинание". Но именно по той причине, по которой они хотят вложиться, я и не хочу привлекать инвестиции. Из-за моей гиперответственности любые внешние инвестиции в проект сразу станут кабалой на шее, а я не для того всю жизнь работал, чтобы получить новую работу в подарок. Для меня принципиально то, чтобы проект оставался в зоне хобби и можно было бы делать действительно интересную игру, не заботясь о ее финансовой составляющей.
Но это абсолютно не означает, что проект будет сугубо альтруистическим и не станет успешным коммерчески. Практика показывает, что за хороший продукт люди готовы платить сами и, разумеется, им будет предоставлена такая возможность. Доходы будут направляться на профессиональную помощь в доработке, излишки - делиться между теми, кто стоял у основ, соразмерно их вкладу. А там, глядишь, это может вырасти и в полноценную компанию.
Скорее всего мне в любом случае придется нанимать профессионалов своего дела на финальных этапах для того, чтобы вычистить глубокие ньюансы, на изучение которых у меня не хватает терпения в процессе, а релизиться с ними стыдно. Готов это делать, но на текущий момент мне хотелось бы собрать единомышленников, для которых разработка игры - не меньшее удовольствие чем поход в бар или поездка на море. На таком подходе можно сделать очень много и, зачастую, лучше тех, кто сейчас клепает посредственные вытаскивалки денег из населения пачками.
Если вы один из следующих специалистов и вам интересно поучаствовать - пишите, для следующих ролей найдется неспешное занятие на свободное время прямо сейчас:
- .NET разработчик + SQL (доработка бэкенда)
- Unreal Engine разработчик (блюпринты)
- Моделлер (создание 3д-моделей и текстур)
- Аниматор (создание анимаций, риг персонажей)
- Animation programmer (правильная интеграция анимаций в UE)
- Тестировщик
- UI/UX
- Technical artist (освещение, шейдеры и т.п.)
- Sound designer (звуки, музыка)
- Гейм дизайнер (баланс, экономика и т.п.)
- Нарративный дизайнер (туториалы, квесты, ЛОР)
- Маркетолог
- Дизайнер эффектов
👍7😁4👎1🔥1
Ну вот и первые результаты рефакторинга подъехали. Уже на проде. Кто играет - вы знаете куда писать баги :).
Конечно же я в итоге увлекся, не смог вовремя остановиться и сделал существенно больше чем требовалось для ускорения конкретно ситуации с микрочипами. Задача полного переноса боев в память теперь уже выглядит очень понятной, достаточно безопасной и... процентов на 70 выполненной.
Конечно же я в итоге увлекся, не смог вовремя остановиться и сделал существенно больше чем требовалось для ускорения конкретно ситуации с микрочипами. Задача полного переноса боев в память теперь уже выглядит очень понятной, достаточно безопасной и... процентов на 70 выполненной.
🔥7👍3👏1
Пора признать, что я погряз в переносе боя в память и, по совместительству, исправлении багов в веб-версии настолько, что в этом году красивых картинок с прогрессом по 3D-версии уже точно показать не смогу.
Борьба с перфекционизмом кажется все более глупой, не смотря на локальные успехи, стратегически я в ней явно проигрываю. Но нельзя также не подчеркнуть и то, что было сделано действительно огромное дело. Эту задачу можно смело назвать той самой лягушкой, которую нужно съесть на завтрак, иначе мысль о том, что ее все равно придется когда-то есть не даст вам покоя в течение всего дня. Моя лягушка еще не доедена, но уже имеет явно выраженный вкус куриных бедер, каждый подход к которым скорее сопровождается приятными эмоциями. Надеюсь вы поняли о чем я.
Новая версия отработала две недели на основном сервере без проблем, баги после переработки вылезают только в самых экзотических местах при глубоком тестировании, но, конечно же, Антон мне также постоянно подгоняет что-то из старенького, на что тоже сложно закрывать глаза, поэтому вся работа пока идет в этом направлении.
Почему же в итоге, не смотря на сознательное решение делать минимальное количество работы по задаче, сделано было намного больше? В моем случае - как будто бы этот путь оказался быстрее и правильнее, по двум причинам:
1. Зачастую при попытке решить задачу не целиком, а частично, приходится строить костыли вокруг решения одного конкретного кейса. Если идти таким путем - сложно системно выявить где конкретно эти костыли нужно втыкать, в основном определяется это только опытным путем: собрали билд, потестили, нашли проблему, пофиксили, снова собрали билд и т.п.. Во-первых оценить сходимость такого процесса очень сложно, во-вторых втыкание костылей зачастую создает непонятный код, на который вы сами через год будете смотреть с недоумением, в-третьих - все эти костыли при полноценном решении задачи нужно будет убирать, соответственно решая одну задачу сегодня вы создаете себе больше работы в будущем. Ну и как, понимая это, можно продолжать решать задачу частично?
2. Tip of the iceberg. Об этом в следующем посте.
Борьба с перфекционизмом кажется все более глупой, не смотря на локальные успехи, стратегически я в ней явно проигрываю. Но нельзя также не подчеркнуть и то, что было сделано действительно огромное дело. Эту задачу можно смело назвать той самой лягушкой, которую нужно съесть на завтрак, иначе мысль о том, что ее все равно придется когда-то есть не даст вам покоя в течение всего дня. Моя лягушка еще не доедена, но уже имеет явно выраженный вкус куриных бедер, каждый подход к которым скорее сопровождается приятными эмоциями. Надеюсь вы поняли о чем я.
Новая версия отработала две недели на основном сервере без проблем, баги после переработки вылезают только в самых экзотических местах при глубоком тестировании, но, конечно же, Антон мне также постоянно подгоняет что-то из старенького, на что тоже сложно закрывать глаза, поэтому вся работа пока идет в этом направлении.
Почему же в итоге, не смотря на сознательное решение делать минимальное количество работы по задаче, сделано было намного больше? В моем случае - как будто бы этот путь оказался быстрее и правильнее, по двум причинам:
1. Зачастую при попытке решить задачу не целиком, а частично, приходится строить костыли вокруг решения одного конкретного кейса. Если идти таким путем - сложно системно выявить где конкретно эти костыли нужно втыкать, в основном определяется это только опытным путем: собрали билд, потестили, нашли проблему, пофиксили, снова собрали билд и т.п.. Во-первых оценить сходимость такого процесса очень сложно, во-вторых втыкание костылей зачастую создает непонятный код, на который вы сами через год будете смотреть с недоумением, в-третьих - все эти костыли при полноценном решении задачи нужно будет убирать, соответственно решая одну задачу сегодня вы создаете себе больше работы в будущем. Ну и как, понимая это, можно продолжать решать задачу частично?
2. Tip of the iceberg. Об этом в следующем посте.
👍4🔥2😱1
Tip of the iceberg.
Концепция "tip of the iceberg" (вершина айсберга) очень проста и максимально логична, но почему-то я никогда не слышал о ней в российском сегменте, даже от очень популярных тренеров по успешному успеху.
Заключается она в простой идее - если вы решаете какую-то задачу и знаете, что где-то рядом есть похожие - надо решать и их тоже, и лучше сразу.
На простом примере: если сгнило яблоко на кухне и вы знаете, что у вас также лежит яблоко в комнате - нужно не просто выбросить то, что сгнило на кухне, имеет смысл сразу проверить не сгнило ли то, что в комнате, а также на всякий случай проверить детскую, ведь там может оказаться не только яблоко, но и кожура от банана, полная мусорка, гора грязной посуды на столе и запиханные между кроватью и стеной грязные носки. Потому что решаем мы не проблему сгнившего на кухне яблока, а проблему запаха в квартире.
В моей ситуации этот принцип нужно было применять на каждом шагу, ведь если в одном месте, например, не обновился рейт персонажа в бою после определенного действия - скорее всего он не обновится и где-то в другом случае. Поэтому решая проблему пересчета рейта я сразу искал в каких еще случаях он пересчитывается и закрывал все такие кейсы, а не только найденный.
Не смотря на простоту и логичность подхода "tip of the iceberg", очень многие применяют его в реальной жизни, сами того не осознавая, но крайне мало кто применяет его в работе. Я не знаю почему, но надеюсь этот пост заставит кого-то об этом задуматься и в итоге сделает наш мир немного лучше.
Концепция "tip of the iceberg" (вершина айсберга) очень проста и максимально логична, но почему-то я никогда не слышал о ней в российском сегменте, даже от очень популярных тренеров по успешному успеху.
Заключается она в простой идее - если вы решаете какую-то задачу и знаете, что где-то рядом есть похожие - надо решать и их тоже, и лучше сразу.
На простом примере: если сгнило яблоко на кухне и вы знаете, что у вас также лежит яблоко в комнате - нужно не просто выбросить то, что сгнило на кухне, имеет смысл сразу проверить не сгнило ли то, что в комнате, а также на всякий случай проверить детскую, ведь там может оказаться не только яблоко, но и кожура от банана, полная мусорка, гора грязной посуды на столе и запиханные между кроватью и стеной грязные носки. Потому что решаем мы не проблему сгнившего на кухне яблока, а проблему запаха в квартире.
В моей ситуации этот принцип нужно было применять на каждом шагу, ведь если в одном месте, например, не обновился рейт персонажа в бою после определенного действия - скорее всего он не обновится и где-то в другом случае. Поэтому решая проблему пересчета рейта я сразу искал в каких еще случаях он пересчитывается и закрывал все такие кейсы, а не только найденный.
Не смотря на простоту и логичность подхода "tip of the iceberg", очень многие применяют его в реальной жизни, сами того не осознавая, но крайне мало кто применяет его в работе. Я не знаю почему, но надеюсь этот пост заставит кого-то об этом задуматься и в итоге сделает наш мир немного лучше.
🔥7👍1
Как эффективно работать с багами когда их много.
Сегодня пост из рубрики капитана Очевидность, но я заметил, что очевидно это далеко не всем и не всегда.
Мне досталось множество багов в наследство после перехода на Entity Framework и Антон начал ими буквально бомбардировать, а-ля "ты же вот в это области как раз чинишь - почини еще и это". А там среди этой кучи есть и реально важные вещи, и не очень важные сами по себе, но указывающие на более важные симптомы, и действительно не важные.
Я уже сказал, что в моих планах нет чинить вообще все, надо в какой-то момент снова перефокусироваться на 3D, так как же построить систему, при которой я верну проект к состоянию, соответствующему моим стандартам качества, но при этом не буду чинить вообще все?
Ответ на поверхности - надо расставить приоритеты и починить только важное. Но как это сделать когда багов очень много?
Таск трекеры обычно предлагают 4 уровня приоритетов: 0 - Critical, 1 - High, 2 - Medium, 3 - Low.
Как принимается решение какую цифру из четырех поставить и достаточно ли такой классификации?
Когда у вас всего 4 уровня приоритетов, но куча багов - получится очень много каждого приоритета и дальше не понятно в каком порядке с ними работать внутри одного приоритета, поэтому для себя я решил делать это немного иначе.
Во-первых я буду использовать Rank, а не приоритет, и число от 0 до 100, а не от 0 до 4, при этом 0 - совсем не важное (скорее всего никогда не будет исправлено - это нормально, в любом живом проекте всегда есть куча багов, не ошибается только тот, кто ничего не делает), 100 - бросаем все и занимаемся только этой задачей.
Во-вторых определю критерии оценки. В моем случае:
- Приводит ли к зависанию боя/сервера (самые критичные)
- Насколько в целом мешает игрокам
- Нарушает ли баланс / создает несправедливость
- Как часто случается
- Имеет ли необратимые последствия
- Насколько сложный в решении (в моем случае даже очень мелкая и не важная вещь, как опечатка в тексте, будет иметь высокий приоритет, потому что если что-то можно починить за 2 минуты и забыть - лучше так и поступить, чем таскать такие баги бесконечно в списке)
- Если что-то похожее уже есть в очереди - вот этот конкретный баг более приоритетен чем тот или нет
Ну а дальше все просто - идем по списку, оцениваем каждый баг через призму этих критериев и проставляем цифру от 0 до 100. Дальше сортируем от большего к меньшему и работаем по списку сверху вниз.
При таком подходе в какой-то момент неизбежно возникнет ощущение, что занимаешься какой-то фигней и именно в этот момент надо будет остановиться, потому что ниже гарантированно находится еще большая фигня.
Останутся ли низкоприоритетные баги навсегда в бэклоге? Возможно. Но вообще такие вещи отлично подходят для онбординга новичков, потому что с одной стороны вероятность сломать что-то важное минимальна, с другой - с помощью таких багов новый разработчик может потрогать разные части проекта и быстро с ним познакомиться. Но это, конечно, только при условии расширения команды.
Сегодня пост из рубрики капитана Очевидность, но я заметил, что очевидно это далеко не всем и не всегда.
Мне досталось множество багов в наследство после перехода на Entity Framework и Антон начал ими буквально бомбардировать, а-ля "ты же вот в это области как раз чинишь - почини еще и это". А там среди этой кучи есть и реально важные вещи, и не очень важные сами по себе, но указывающие на более важные симптомы, и действительно не важные.
Я уже сказал, что в моих планах нет чинить вообще все, надо в какой-то момент снова перефокусироваться на 3D, так как же построить систему, при которой я верну проект к состоянию, соответствующему моим стандартам качества, но при этом не буду чинить вообще все?
Ответ на поверхности - надо расставить приоритеты и починить только важное. Но как это сделать когда багов очень много?
Таск трекеры обычно предлагают 4 уровня приоритетов: 0 - Critical, 1 - High, 2 - Medium, 3 - Low.
Как принимается решение какую цифру из четырех поставить и достаточно ли такой классификации?
Когда у вас всего 4 уровня приоритетов, но куча багов - получится очень много каждого приоритета и дальше не понятно в каком порядке с ними работать внутри одного приоритета, поэтому для себя я решил делать это немного иначе.
Во-первых я буду использовать Rank, а не приоритет, и число от 0 до 100, а не от 0 до 4, при этом 0 - совсем не важное (скорее всего никогда не будет исправлено - это нормально, в любом живом проекте всегда есть куча багов, не ошибается только тот, кто ничего не делает), 100 - бросаем все и занимаемся только этой задачей.
Во-вторых определю критерии оценки. В моем случае:
- Приводит ли к зависанию боя/сервера (самые критичные)
- Насколько в целом мешает игрокам
- Нарушает ли баланс / создает несправедливость
- Как часто случается
- Имеет ли необратимые последствия
- Насколько сложный в решении (в моем случае даже очень мелкая и не важная вещь, как опечатка в тексте, будет иметь высокий приоритет, потому что если что-то можно починить за 2 минуты и забыть - лучше так и поступить, чем таскать такие баги бесконечно в списке)
- Если что-то похожее уже есть в очереди - вот этот конкретный баг более приоритетен чем тот или нет
Ну а дальше все просто - идем по списку, оцениваем каждый баг через призму этих критериев и проставляем цифру от 0 до 100. Дальше сортируем от большего к меньшему и работаем по списку сверху вниз.
При таком подходе в какой-то момент неизбежно возникнет ощущение, что занимаешься какой-то фигней и именно в этот момент надо будет остановиться, потому что ниже гарантированно находится еще большая фигня.
Останутся ли низкоприоритетные баги навсегда в бэклоге? Возможно. Но вообще такие вещи отлично подходят для онбординга новичков, потому что с одной стороны вероятность сломать что-то важное минимальна, с другой - с помощью таких багов новый разработчик может потрогать разные части проекта и быстро с ним познакомиться. Но это, конечно, только при условии расширения команды.
🔥3👍1🤔1🤯1
О важности правильного именования в коде.
Очень много книг и статей написано на тему coding guidelines, не буду здесь повторять прописные истины, это все можно найти в интернете, лучше покажу на простом примере как несоблюдение простых рутинных вещей может приводить к реальным проблемам.
Я все ещео своих баранах на примере кеширования, уж извините. Игрок сообщил о проблеме неправильного обновления рейта персонажа при надевании и снятии вещей в случае если он находится в заявке на бой. Для незнакомых с механикой игры, она следующая - один игрок создает заявку на бой, другие принимают, когда набирается нужное кол-во игроков или истекает таймер ожидания, бой начинается.
Так вот признак нахождения персонажа в бою оказался достаточно лукавой штукой. Дело в том, что в общем случае этот признак определяется заполненным параметром BattleID у персонажа. Но это именно идентификатор боя, а сам бой может находиться в статусах создан/в процессе/завершен. Когда бой в процессе - к игрокам применяется ряд ограничений во избежание откровенных сливов (прокачка одного персонажа за счет другого) и решения прочих шишек, набитых за историю существования проекта (это, кстати, отдельная тема для довольно большой серии постов). Но эти ограничения не нужны пока игрок не в бою.
В моем случае в методах надевания и снятия вещей - спагетти-код, что не мудрено, он же был перенесен из хранимок, где изначально был написан в процедурном стиле, и было бы странно ожидать, что он будет сразу и отрефакторен - такой подход имел бы крайне плохую сходимость. А когда код тянется на несколько экранов, а ты в этот момент переписываешь, по сути, ядро, конечно не будешь каждый такой метод читать от начала до конца и вникать что он делает. Это и сыграло со мной злую шутку.
Флаг признака нахождения игрока в бою назывался isInBattle (локальная переменная), такое именование очень распространено в проекте в целом и означает оно обычно то, что у игрока заполнено поле BattleID. Но в случае с этими конкретными сценариями к признаку добавлялось еще одно условие - что бой уже находится в процессе: Player.BattleID!=null && Battle.RefBattleStateID==(int)RefBattleStateEnum.InProgress, но переменная называлась также, как и везде. Разумеется я, увидев знакомое название переменной, сразу сделал вывод о ее функции, не копаясь дальше как конкретно она присваивается.
В итоге вышло так, что опираясь на неоднозначное название переменной я включил все ограничения боя для игроков, находящихся в заявке на бой. А решение здесь простое - именовать все максимально однозначно, например в моем случае простое переименование переменной в isInStartedBattle уже точно не даст повторить подобную ошибку. Самое смешное - скорее всего я так и назвал эту переменную изначально, и при переносе имя было просто сохранено. А почему это могло произойти? Потому что работая с конкретной хранимкой в базе данных и работая с .NET проектом мы мыслим совсем разными категориями, поэтому то, что сейчас кажется очевидно неправильным, тогда и в том контексте казалось, и было, вполне правильным.
P.S.: И да, я знаю, что по уму такие вещи должны быть вообще реализованы единожды внутри модели и не вычисляться в каждом отдельном методе. С текущими ограничениями я просто не готов делать еще и эту работу.
Очень много книг и статей написано на тему coding guidelines, не буду здесь повторять прописные истины, это все можно найти в интернете, лучше покажу на простом примере как несоблюдение простых рутинных вещей может приводить к реальным проблемам.
Я все еще
Так вот признак нахождения персонажа в бою оказался достаточно лукавой штукой. Дело в том, что в общем случае этот признак определяется заполненным параметром BattleID у персонажа. Но это именно идентификатор боя, а сам бой может находиться в статусах создан/в процессе/завершен. Когда бой в процессе - к игрокам применяется ряд ограничений во избежание откровенных сливов (прокачка одного персонажа за счет другого) и решения прочих шишек, набитых за историю существования проекта (это, кстати, отдельная тема для довольно большой серии постов). Но эти ограничения не нужны пока игрок не в бою.
В моем случае в методах надевания и снятия вещей - спагетти-код, что не мудрено, он же был перенесен из хранимок, где изначально был написан в процедурном стиле, и было бы странно ожидать, что он будет сразу и отрефакторен - такой подход имел бы крайне плохую сходимость. А когда код тянется на несколько экранов, а ты в этот момент переписываешь, по сути, ядро, конечно не будешь каждый такой метод читать от начала до конца и вникать что он делает. Это и сыграло со мной злую шутку.
Флаг признака нахождения игрока в бою назывался isInBattle (локальная переменная), такое именование очень распространено в проекте в целом и означает оно обычно то, что у игрока заполнено поле BattleID. Но в случае с этими конкретными сценариями к признаку добавлялось еще одно условие - что бой уже находится в процессе: Player.BattleID!=null && Battle.RefBattleStateID==(int)RefBattleStateEnum.InProgress, но переменная называлась также, как и везде. Разумеется я, увидев знакомое название переменной, сразу сделал вывод о ее функции, не копаясь дальше как конкретно она присваивается.
В итоге вышло так, что опираясь на неоднозначное название переменной я включил все ограничения боя для игроков, находящихся в заявке на бой. А решение здесь простое - именовать все максимально однозначно, например в моем случае простое переименование переменной в isInStartedBattle уже точно не даст повторить подобную ошибку. Самое смешное - скорее всего я так и назвал эту переменную изначально, и при переносе имя было просто сохранено. А почему это могло произойти? Потому что работая с конкретной хранимкой в базе данных и работая с .NET проектом мы мыслим совсем разными категориями, поэтому то, что сейчас кажется очевидно неправильным, тогда и в том контексте казалось, и было, вполне правильным.
P.S.: И да, я знаю, что по уму такие вещи должны быть вообще реализованы единожды внутри модели и не вычисляться в каждом отдельном методе. С текущими ограничениями я просто не готов делать еще и эту работу.
🔥5😁3❤2👌1