Разработка Telegram бота для подготовки к собеседованиям

от автора

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

Не люблю картинки сгенерированные AI - а ничего лучше не нашел

Не люблю картинки сгенерированные AI — а ничего лучше не нашел

Собесбот — это Telegram-бот для подготовки к собеседованиям для специалистов уровня Junior, Middle, а также для тех, у кого нет коммерческого опыта в IT. В этой статье я разберу принцип работы бота, почему я решил его сделать, и трудности, с которыми я столкнулся при разработке.

На данный момент есть оценка и рекомендации по: C#, Java, Kotlin и JavaScript. В целях добавить Python, конечно же.

Зачем?

Количество выпускников онлайн-школ продолжает расти, однако многие сталкиваются с трудностями при поиске первой работы в IT. Да и джунам, у которых есть небольшой опыт приходится несладко (статистики у меня нет, просто по общим наблюдениям в соц. сетях). У них встает резонный вопрос: Как подготовиться к собеседованию в IT? Хотелось сделать продукт, от которого будет польза при подготовки к собесам, но который бы обходился для меня минимумом затрат.

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

Почему именно бот в Telegram?

Как любой разработчик с опытом, я наслышан о кладбище пет-проектов. Люди начинают писать пет-проекты, которые так и остаются незаконченными. У меня таких есть тоже. Именно поэтому я какое-то время вообще избегал разработки своих проектов. Основная проблема, с которой я сталкиваюсь при разработке проектов — склонность к усложнению, углубление в детали, что в итоге приводит к потере мотивации. В этот раз мне очень хотелось углубиться в разработку. Но я решил пойти по пути наименьшего сопротивления. Один из моих страхов — это фронтенд-разработка. Поэтому я решил делать frontendless решение. К тому же, Telegram бот — удобный формат для пользователей. Не нужно скачивать мобильное приложение или открывать сайт. И с точки зрения разработки меньше шансов на оверинжинирить. К тому же опыт разработки Telegram ботов и желание применить AWS в реальном продукте также повлияли на мой выбор.

Все начиналось со скрипта

В 2021 году я сделал мини-курс по подготовке к собеседованиям. Это были 4 насыщенных вебинара, каждый из которых включал практические задания для закрепления материала. Мой первый продукт, в который я вложил много души. Возможно, именно после него я и выгорел. Запустил курс один раз, но дальше дело не пошло. В этом году я пересмотрел материалы курса и понял, что многие концепции остаются актуальными и полезными даже сейчас. В курсе был скрипт для генерации квизов с вопросами для собеседований на Google Forms. Он случайным образом собирал вопросы из большой базы вопросов с группировкой по областям. Готовые формы я скидывал участникам. У каждого был уникальный набор вопросов и на основании результата можно было определить какие области и навыки стоит подтянуть. На основе этого скрипта и родилась идея создания бота в Telegram для подготовки к собесам.

Принцип работы

Диаграмма работы бота

Диаграмма работы бота
  • Пользователь регистрируется в боте, указывает свою специализацию и уровень.

  • У него есть возможность определить свой уровень с помощью скринингов (доступно 9 специальностей).

  • Скрининг — это серия тестов в Google Forms. Обычно это от 14 до 17 тестов с 4-11 вопросами каждый. Вопросы охватывают определенную область знаний. Например, это может быть LINQ для C# .NET или Firebase для Android. Пользователю нужно ответить на вопросы, которые бывают разного типа: одиночный выбор, множественный выбор, сопоставление, или вопросы с коротким текстом.

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

  • По итогам скрининга бот создает разбивку по навыкам, показывая, какие области нужно подтянуть. Главная фича для новичков — это персональные рекомендации на основе результатов. Они включают статьи, видео, бесплатные курсы, код и документацию.

  • Также можно запросить мок-собеседование (пока доступно только по .NET) и карьерную консультацию. Я выступаю в роли ментора.

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

  • Навигация в боте происходит через inline-кнопки, и все взаимодействие строится по принципу «одно сообщение в момент времени». Это очень похоже на обычный SPA или мобильный клиент. Есть текущее View и мы можем переходить из него на другие.

    Примерно так выглядит список рекомендаций для кандидата с пробелами в C#, .NET CLI, NPM и async/await(подредактировал, чтобы уменьшить размер сообщения)

    Примерно так выглядит список рекомендаций для кандидата с пробелами в
    C#, .NET CLI, NPM и async/await
    (подредактировал, чтобы уменьшить размер сообщения)

Выбор стека

Для начала оговорюсь, что это мой первый бот в Telegram. Я никогда раньше работал с AWS. И первый раз нанял разработчика для совместной работы над своим проектом. Что оказалось не такой плохой идеей. Ну и в заключении, я выбрал Shift-right testing, чтобы не тратить время на интеграционные тесты и поскорее зарелизить бота.

Самый близкий мне язык и фреймворк это C# и ASP.NET Core. При выборе инфраструктуры руководствовался минимизацией затрат и масштабированием. Для взаимодействия с ботом выбрал вебхуки. Каждый Update обрабатывает ASP.NET Core приложение задеплоеное на AWS Lambda. В качестве БД Amazon DynamoDB. Выбор пал в пользу этих сервисов в силу больших лимитов во Free Tier и желания написать свой пет-проект на AWS. Выбрал GitHub как систему контроля версий и Notion в качестве трекера задач. Деплоил со своей машины.

Итого внешних зависимостей:

  • AWS Lambda

  • DynamoDB

  • Google Forms

  • Telegram API

Разработка

Разработка началась в мае 2024-го года. На протяжении всего лета я посвящал свободное время разработке этого бота. Первый бот был готов уже через 3 дня. Он повторял логику скрипта по генерации опросника . Как человек, в первый раз написавший бота в Telegram, да еще и в первый раз слепил что-то в AWS я безумно радовался.

Интеграция с Google Forms

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

Проблема №1

Если мы генерируем тесты в Google Forms из базы, то как избежать дублирования вопросов и при этом обеспечить откалиброванную подборку по сложности?

Решение: Я понимал, что риску попасть в ловушку усложнения. Решил не генерить тесты на лету, а заранее создавать наборы, сгруппированные по специализации. Но это пораждает новую проблему — по какому принципу группировать вопросы в тесте?

Также встал вопрос, насколько будет удобно пользователю переключаться между Google Forms и Telegram? Вместе с этим следующая проблема:

Проблема / Вопрос №2

А почему Google Forms, если Telegram дает возможность создавать квизы?

Ответ: К сожалению, в квизах можно использовать только вопросы с одиночным выбором. Нет сопоставлений, короткого текста и множественного выбора. Google Forms дает возможность удобного хранения и управления вопросами, их быструю и легку правку, а также просмотра статистики ответов. Отвечает принципам frontendless.

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

Проблема / Вопрос №3

Почему бы не сделать веб или мобильное приложение, где нет ограничений?

Ответ: Я старался избегать фронтенд-разработки, чтобы минимизировать риск попадания в ловушку избыточной сложности. Я решил не изучать новую технологию, чтобы не растягивать сроки разработки. К тому же, Telegram бот довольно удобный формат для пользователей — всегда под рукой и не надо скачивать.

Казалось, что разработка бота с использованием внешней зависимости в виде Google Forms — это гиблое дело. Но, следуя принципам frontendless приложений, чтобы не увеличивать срок разработки на изучение фронтенда и дизайн сайта, а быстрее выпустить MVP — я решил рискнуть.

Многие пользователи, особенно из мира IT любят оставлять минимум информации о себе. Соответственно,лучше не запрашивать дополнительные данные, например логин в Google аккаунт при ответе на вопросы в квизе. Скорее всего, это не самый приоритетный запрос, который стоило брать в разработку. Но я его взял.

Проблема №4

Как сопоставить ответы пользователя в форме без аутентификации в Google Forms?

Решение A: Копировать квиз для каждого пользователя и отдавать ссылку на уникальный квиз. Это решение полностью решает проблему. Однако это дополнительный запрос к API Google Forms для создания дубликата формы. Со временем бесполезных форм становится все больше и нужна будет периодическая чистка Google Drive.

Решение Б: Использовать prefillLink с предзаполненным поле в форме. Это текстовое поле содержит идентификатор квиза в базе данных, по которому мы сопоставляем ответы пользователя и квиз. Тоже решает проблему, однако не создает лишних форм, уменьшает запрос к Google Forms API, а еще мы получаем статистику ответов. Минус такого подхода: лишнее поле, очистив которое бот не сможет сопоставить ответы и придется проходить квиз заново.

Слоистая архитектура

Для своих сервисов я выбрал трехслойную архитектуру, основывающуюся на DAO, DTO и Rich Domain Model. Однако, несмотря на преимущества такого подхода, он добавил значительный оверхед, что привело к усложнению разработки. Каждый раз после нового запуска бота я тратил по несколько дней на его отладку. Одной из главных причин ошибок оказался некорректный маппинг, для которого я использовал Mapperly. Эта отличная библиотека значительно сэкономила мне время. Но из-за частых изменений в моделях и множества слоев — конечно я постоянно наступал на грабли.

Переход на микросервисы

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

  • Сам бот (там же сейчас и управление пользователями),

  • Сервис работы с квизами через Google Forms

  • Сервис оценки результатов скринингов

  • Сервис рекомендаций

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

Работа в паре

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

Денег у меня не было. Я не надеялся, что кто-то откликнется на работу без оплаты, но все-таки выложил объявление о поиске разработчика в чатики с вакансиями. Отозвались 10 человек, из которых 3 согласились работать без оплаты. Провел со всеми собеседования. Было особенно волнительно, в итоге отобрал одного джуна. Он не мог найти работу разработчиком больше года и готов был посвящать все свое время проекту. Круто, подумал я, хотя понимал, что как только он найдет работу его желание вкладываться куда-то еще упадет.

Мы проводили ежедневные звонки и синхронизировали статус задач. Вели задачи в Notion. В основном на звонках я рассказывал и объяснял скоуп задач. Для меня это был своеобразный метод утенка, а для него по сути менторская сессия и работа над проектом. Кроме того, даже сам факт присутствия у тебя в команде другого человека, с которым вы периодически созваниваетесь — хороший мотиватор (Accountability partner). Однако,

Проблема №5

Напарнику не хватает опыта быстро уловить суть, проще сделать самому, чем объяснить.

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

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

Трекинг задач в Notion

В Notion мы вели трехуровневую систему задач с разделением на эпики, фичи и что-то похожее на юзер стори. Использовали Kanban доску.

Проблема №6

Нужна приоритезация. Но в Notion нельзя легким кликом отправить задачу вверх колонки на доске.

Решение: реализовать приоритезацию на основе собственного приоритета задачи и ее родителя. Например, если эпик имеет приоритет 1. После умножения его приоритета на 100 все его задачи получают приоритет 100. Внутри этого эпика могут быть фичи и их приоритеты умножаются на 10. Это то, что пришло в голову и получилось слепить на коленке. Подход имеет свои минусы, но в большинстве случаев рабочий.

Библиотека для обработки событий от Telegram бота

Первые пару недель я изучал возможности Telegram API и разные решения для работы через вебхуки.

Взаимодействие Telegram-бота через вебхуки происходит следующим образом: бот регистрирует URL вебхука, на который Telegram отправляет каждое новое событие (объект update), например, сообщение пользователя или нажатие кнопки. Объект update содержит всю информацию о событии (ID чата, текст сообщения, данные о пользователе и т.д.).

К сожалению, не нашел готовых библиотек, упрощающих разработку с бота на .NET через вебхуки. Пришлось делать свою. Долго разбирался, какие существуют подходы, в итоге бросил, и реализовал следующую связку:

Любое взаимодействие с ботом, кроме /start происходит через нажатие кнопки из встроенного в сообщение меню и передачи callbackData. При этом слой View — это текст и кнопки у каждой из который свой callbackData. Команды содержат примитивные параметры, а их обработчики основную логику бота. Вроде бы рабочая схема, но на этапе отладки я узнал, что:

Проблема №7

В callbackData можно засунуть максимум 64 символа.

Решение: В качестве костыля я хэшировал данные, для уменьшения объема данных. По-хорошему можно сопоставить команду записи в БД через идентификатор, который умещается в callbackData. Но я решил взять это в технический долг.

Разобравшись с Telegram API я написал небольшую библиотеку, реализующую вышеуказанный процесс обработкий апдейтов от бота. Туда же добавил отображение сообщения об ошибке вместо зависания и подсчет запросов на нереализованные фичи. Если в боте, есть какая-либо нереализованная фича, то пользователь может “записаться” в лист ожидания и проголосовать за эту фичу. Самые популярные фичи можно в последующем приоритезировать. С этим проблем не было, но как правильно разработать навигацию?

Проблема №8

Если в callbackData нельзя хранить большие команды, то как реализовать команду “Назад”?

Решение: Здесь уже пришлось хранить команду в БД. После такой реализации усилилось желание переделать предыдущий костыль. Но смиренно я сдержался.

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

Проблема №9

Telegram API не дает удалить сообщения старше 48 часов отправленные ботом

Решение: Вместо удаления реализовал редактирование последнего сообщения. Идентификатор сообщения храню в базе данных.

Забегая вперед, скажу, что через пару месяцев это решение породило следующую проблему.

Проблема №10

С течением времени бот сползает вниз в списке чатов в Telegram, так как используется только одно сообщение для взаимодействия с пользователем и оно было создано давно.

Решение: Вернуть удаление. Но сделать его умнее. Если сообщение младше 48 часов, но старше 24 часов, то у нас еще есть окно для удаления и создания сообщения. Если же сообщение старше 48 часов — то заменяем текущее сообщение следующим текстом и добавляем новое. Этот метод я назвал мягким удалением.

Больше проблем при работе с Telegram API я не припомню. Разве что странный markdown, но будем считать это особенностью.

Метрики и воронки

Перед запуском бота и публикацией его в различные Telegram каналы и сообщества я сделал небольшой сервис для подсчета основных метрик. Мне было интересно сколько всего пользователей их разбивки по грейдам и специализациям. Самая важная для меня метрика — это количество завершенных скринингов, потому что завершенный скрининг приносит наибольшую ценность для того, кто готовиться к собеседованию в IT. Там и разбивка по скиллам и рекомендации. Для того, чтобы мотивировать людей на начало нового скрининга или прохождение уже начатого я реализовал небольшой сервис для “продвижения” людей в воронке.

Голосование за фичи встроено в бота

Голосование за фичи встроено в бота

Заключение

Через 4 месяца я уже достаточно подустал от разработки. Мне хотелось скорее его запустить. Я получил очень ценный опыт разработки своего MVP. И пусть он не монетизируется, но зато приносит людям пользу даже пока я сплю.

Ссылка на бота

Через пару недель после выпуска Собесбота я также решил создать группу в Telegram для джунов и стажеров, которые готовятся к собеседованиям в IT.

Вступайте в нашу группу в Telegram — там обсуждаем вопросы, связанные с подготовкой к собеседованиям, даем обратную связь и помогаем друг другу.


ссылка на оригинал статьи https://habr.com/ru/articles/850826/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *