Пет-проект, который пока не умер

Представьте, что вы решили завести маленький пет-проект. Вернее даже не вы решили, а вас попросила матушка помочь с одной рутинной задачей, которая возникает в ее браузерной игре. Вам увиделось множество вещей, которые можно автоматизировать и оптимизировать в процессе, который может занимать до 6 часов непрерывного и утомительного труда в день, и так родился проект.

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

0. Суть задачи

Cуть задачи: имеется браузерная игра, в которой нужно строить свой город, нападать на монстров и других игроков, грабить корованы и развиваться. В игре очень развита система кланов и вообще социальное взаимодействие. Каждый раз, когда игрок нападает на очередной склеп (цитадель и прочие зиккураты), он, помимо получения награды, приносит сундук всем своим соклановцам. А другие игроки в специальной вкладке в игре могут этот сундук собрать и получить ресурсы. И вот эта механика настолько важна, что игроки готовы по 6 часов в день тратить на подсчет, кто сколько сундуков принес, какие нормы и планы выполнил и какого качества были сундуки. Глубоко погружаться не буду, но игроки, которые занимаются подсчетом сундуков, имеют целую неофициальную должность в клане (казначеи) и без средств автоматизации игра превращается в полноценную и очень рутинную работу.

af20fa7954e809dc4e94277f3a3f0b3b.png

1. Вопрос мотивации

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

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

Старайтесь как можно скорее сделать mvp и кому-нибудь показать. Это приведет хотя бы одного клиента, и если он начнет пользоваться вашим проектом на постоянной основе, то возможно будет писать и мотивировать вас на продолжение проекта. У меня же на создание самой первой версии mvp ушло пару недель (3 марта я решил делать проект, 7 марта начало и первое тестирование, 15 марта сайт с регистрацией, 20 марта было готово mvp). Здесь все как с письмами родственникам, подарками на новый год — лучше уж хоть что-то, чем ничего.

Делегируйте часть работы. Мне повезло, что жена увлеклась дизайном и помогла мне с визуальной частью сайта (сам я в дизайне полный 0, могу его только преподавать). Да, это не спасет проект от смерти, даже про потерянные деньги и время иногда проще забыть, чем тянуть мертворожденного питомца, но облегчит работу и ускорит создание mvp. Также самую скучную и неприятную часть в разработке я делегировал своему стажеру, который за очень скромное и условное денежное вознаграждение, а также за бесценный опыт, наводил порядок в моем творческом беспорядке (говнокоде) и подключал типы в тайпскрипте.

Тешьте себя иллюзиями, что вот-вот, осталось совсем чуть-чуть и миллионы посыпятся вам на голову. Да, со временем это разочаровывает, приходит понимание, что до миллионов как до Blu-ray dial-up-ом, но позволяет сделать ещё вон ту важную фичу, без которой нельзя пускать пользователей, а с ней точно можно. Так я уже несколько раз переделывал функционал отчета и дважды менял фреймворк для таблиц (это не самые приятные задачи, но без этого не видать миллионов)

Стикеры, задачи, таск-трекеры, доска в миро и объясните кому-нибудь что вы планируете сделать и почему это важно и круто. Я веду, и не потому что так надо, а потому что иначе вообще не реально.

2. Вопрос архитектуры

Самое первое архитектурное решение задачи предложил барыга из соседнего клана. За 5000 рублей он настраивает «программу для подсчета сундуков». На деле это был автокликер, который делает скриншот сундука (имя игрока и тип сундука) и сохраняет все это дело в папку. Пользователь этой «программы» должен просто открыть клиент игры, запустить автокликер и ждать, пока откроются все сундуки. Скорость открытия зависит от мощности компьютера пользователя, ну и блокирует использование компьютера. Затем эти скриншоты переводятся в текст при помощи OCR (ссылку на пиратскую версию ocr «программист» заботливо скинул), текст вставляется в таблицу, VBA скриптом разбивается на 2 столбца, а в соседней таблице формулами формируется сводная таблица… 

К слову, открывать сундуки нужно каждый день, а отчёты нужны раз в неделю. Количество сундуков зависит от размера клана и активности игроков, в клане у мамы было примерно 5000 сундуков в неделю и из-за этого подхода терялось около 100 сундуков. По разным причинам: то сдвинется окно и собьется место скриншота, то механически удалятся нужные скриншоты, то прочитается что-то не так (имя игрока, например), а поиск и исправление таких ошибок муторное, то имя игрока в сводной таблице не соответствует имени из скриншота…

e527bfec461112dfc19a625837fc5cb6.png

Но даже такое костыльное решение работало и экономило кучу времени. 6 часов ручного труда превращались в час времени ежедневно и пару часов в конце недели.

У меня сгорело от того, что за такую «работу» человек попросил реальные деньги. И ведь моя мама же не первая, кто у него купил это решение! Но вариантов у меня было не очень много. Исследование исходного кода страницы с игрой, анализ http запросов и вебсокетов не дали результатов. Я не настолько продвинутый хакер, чтобы дешифровать все же зашифрованные ответы сервера, сама игра рисуется в теге canvas, так что не имеет даже html элементов (опыт автоматизации подобных игр имеется, если будет интересно — комментируйте, я расскажу). Нужно реально запускать реальный браузер и делать скриншоты. 

Вопрос — где? На машине клиента можно было бы, но так, чтобы это не мешало пользоваться компьютером (в достаточной степени), но ещё и нужен стабильный выход в интернет и «коробочное решение», которое бы легко устанавливалось на компьютер клиента. На сервере тоже можно, это решает проблему выхода в интернет и использования компьютера, но накладывает ограничения на мощности сервера и безопасность передачи данных авторизации от игры «какому-то левому сайту».

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

3. Вопрос языка программирования

Я всегда придерживался идеи «не важно на чем, главное как», и считал, что выбор языка программирования не так уж важен. Особенно, когда нужно сделать что-то быстро. Лучше уж выбрать удобный инструмент, с которым уже знаешь как работать, чем что-то крутое, но с которым придется долго разбираться. Но опыт разработки этого проекта показал обратное и сейчас расскажу почему.

Сервер.

Ещё в теперь кажущимся таким далеким и беззаботным 2018 году, когда я только постигал азы программирования и осваивал профессии дата-саентиста и аналитика данных, в первом настоящем проекте мы с командой использовали легковесный веб-фреймворк Flask. Я сразу влюбился в этот фреймворк, а книга Miguel Grinberg и ее перевод на хабре «мега-учебник Flask» стала для меня «настольной». Это классный инструмент и я умею с ним работать, уже много успешных проектов было на нем запущено, он отлично подходит для создания прототипов. Но проблемы возникают при деплое приложения и вдруг выясняется, что использование встроенного сервера flask не рекомендуется для продакшена! У меня при длительной работе сервер просто зависал без видимой причины и ошибки и отвисал, если разок нажать ctrl+c в консоли и продолжал работать как ни в чем не бывало. Да, есть всякие wsgi, и вообще туториалы, как перевести, запустить, как завернуть в контейнер, настроить gunicorn…, но я-то в девопсы не записывался! В виду того, что на данный момент запущен сервер на моем домашнем компьютере (на windows 10, я на нем ещё и играю иногда), сервер запускается при помощи waitress. И тут, когда мне потребовалось использовать веб-сокеты, выяснилось, что wsgi их не поддерживает :) 

Учитывая, что фактически flask я использую только как api и вообще не использую jinja, я с тем же успехом мог бы написать сервер на fastApi, и сейчас я всерьез задумываюсь о том, чтобы переписать его. 

Выводы: не стоит использовать веб-фреймворки, которые проходят для прототипов, если есть шанс, что вы когда-нибудь будете это деплоить. Судя по количеству багов в Инстаграме, я не первый, кто наступил на эти грабли (напомню, что Инстаграм написан на django — «старшем брате» flask)

Клиент

Для клиентской части был выбран свежий vue3. На момент начала проекта у меня уже был год опыта работы с этим фреймворком второй версии и он меня всем устраивал. Устраивает и до сих пор, единственной проблемой остаётся поиск совместимых библиотек, из-за этого например сначала был выбран wave-ui в качестве библиотеки компонентов. Из нее мне нужна была только таблица, остальные библиотеки типа vuetify не были готовы к vue3 или имели страшные таблицы. Затем я осознал, что для отчета минималистичный вид таблиц мне не подходит и я перевел таблицу отчета на tabulator. 

4. Вопрос защиты от ботов (и других нерешаемых проблем)

Где-то через пару месяцев работа над проектом встала. Мой селениум не мог залогиниться, потому что разработчики игры подключили recaptcha, блокирующий подозрительные попытки входа. А я, как известно, очень подозрительный тип, захожу в инкогнито в headless браузере, с одного ip адреса, очень резко дергаю мышью и не мешкая ввожу логин и пароль, четкими движениями нажимая на один и тот же пиксель прямо в центре элемента.

Да и вообще, думаю, в каждом проекте найдется такая проблема-убийца. Блок, который никак не обойти не объехать. Поиск по форумам, стаковерфлоу, какие-то свои идеи и исследования на тему обхода самой свежей версии recaptcha не дали результатов. Я расстроился и стал думать, как бы теперь все это перенести на сторону клиента, отказаться от использования компьютера в момент открытия… короче, делаю автокликер, скриношты и ocr, возвращаюсь к корням, буду брать по 5000 рублей…

Впоследствии выяснилось, что я не первый, кому пришла идея коробочного решения на стороне клиента. Мама подогнала мои контакты другому игроку-казначею, и он рассказал, что запускает некую программу, которая тоже сама все считает и открывает, но на стороне клиента. В момент обсуждения моего проекта я его откопал, стряхнул пыль, запустил, чтобы показать, как он не работает и… все заработало. Оказалось, что защита от бота срабатывает в 50–70% случаев, и достаточно просто пару раз перезагрузить страницу, чтобы меня пустило.

Я осознаю, что это самое тонкое место моего проекта. В любой момент разработчики могут закрыть дыру окончательно и всё пойдёт прахом. У меня есть некоторые идеи, как можно было бы радикально решать вопрос со входом, но не хотелось бы до такого доводить.

7164e8e5b3bb00171a30d84d88f804dd.png

5. Вопрос монетизации

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

ba90f70cbeef36d11d46a679a3871c03.png

© Habrahabr.ru