
Отрефакторим наш код
Создадим под это дело новую ветку: STEP_10, в которую запишем все последние изменения до MVP. Рефакторинг — это изменение кодовой базы без изменения ее поведения. Что хочется изменить? В самом начале термином “статья” на проекте я выбрал слово article и пока не начал работать с клиентом Javarush API для статей, это было логично. Но в Javarush API используют термин post. И я думаю, что хорошо будет перейти на их стандарт, поэтому первым делом переименуем везде с article на post. Что будет нашей гарантией, что все осталось также? Гарантией будут наши тесты, которые мы написали. Именно теперь они нам понадобятся. Начнем изменения с БД. В таблице group_sub, нужно переименовать поле lastArticleId в lastPostId. Это очень просто, потому что у нас уже настроен Flyway и для того, чтобы обновить поле, нужно всего добавить еще одну миграцию, в которой мы выполним ALTER TABLE операцию. Создадим новую, третью, миграцию: V00003__rename_last_article_id.sql в котором будет:
ALTER TABLE group_sub CHANGE COLUMN last_article_id last_post_id INT;
Эту миграцию нужно поместить в тоже место, где лежат и две предыдущие.
Далее нужно переименовать имя переменной в сущности GroupSub с lastArticleId на lastPostId. Если работа идет через IDEA, то провести переименование очень просто, нужно воспользоваться горячей клавишей: shift + F6, когда курсор находится на имени класса/метода/поля, тогда среда разработки позволяет переименовать все места, где используется это поле.
Также переименует геттеры и сеттеры для этого поля.Это полезная вещь и должна быть в арсенале каждого разработчика.
Я уверен, что такой же функционал есть и у эклипса, но подсказать не могу, я им не пользуюсь.
@Column(name = "last_article_id")
private Integer lastArticleId;
в
@Column(name = "last_post_id")
private Integer lastPostId;
Далее при помощи поиска по всему проекту (ctrl+shift+f) найдем все места, где есть упоминания Article:
класс FindNewArticlesJob -> FindNewPostsJob
класс FindNewArticleService -> FindNewPostsService
метод FindNewArticleService#findNewArticles -> FindNewPostsService#findNewPosts
класс FindNewArticleServiceImpl -> FindNewPostsServiceImpl
проперти bot.recountNewArticleFixedRate -> bot.recountNewPostFixedRate
метод JavaRushGroupClient#findLastArticleId -> JavaRushGroupClient#findLastPostId
метод FindNewPostsJob#findNewArticles -> FindNewPostsJob#findNewPosts
И остальные места, где внутренние методы, где комментарии.

- метод CommandContainer#retrieveCommand -> CommandContainer#findCommand
- все джавадоки с retrieve в find.
/**
* Service for sending messages via telegram-bot.
*/
public interface SendBotMessageService {
/**
* Send message via telegram bot.
*
* @param chatId provided chatId in which would be sent.
* @param message provided message to be sent.
*/
void sendMessage(Long chatId, String message);
/**
* Send messages via telegram bot.
*
* @param chatId provided chatId in which would be sent.
* @param message collection of provided messages to be sent.
*/
void sendMessage(Long chatId, List<String> message);
}
Теперь принимает интерфейс не String chatId, а Long chatId.
Обновляем и реализацию, ставим просто chatId.toString() в необходимом поле:
sendMessage.setChatId(chatId.toString());
Далее идем в класс TelegramUser и меняем тип переменной chatId с String на Long:
@Id
@Column(name = "chat_id")
private Long chatId;
В TelegramUserRepostiry меняем в наследуемом интерфейсе также со String на Long:
/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, Long> {
List<TelegramUser> findAllByActiveTrue();
List<TelegramUser> findAllByActiveFalse();
}
Обновляем метод CommandUtils#getChatId, чтобы он не приводил к строке:
/**
* Get chatId from {@link Update} object.
*
* @param update provided {@link Update}
* @return chatID from the provided {@link Update} object.
*/
public static Long getChatId(Update update) {
return update.getMessage().getChatId();
}
И во всех местах, где используется chatId, убираем приведение к строке. Там, где методы принимают String chatId, меняем тип на Long. Кстати, пока менял приведение к строке нашел, что утилитный метод getChatId(update) не везде используется, так что обновил и те места.
Последний этап — нужно обновить тип поля в таблице tg_user. Для этого создадим четвертую миграцию V00004_change_chat_id_type_to_long.sql:
ALTER TABLE tg_user MODIFY chat_id INT;
После всех этих обновлений пришло время запустить тесты :D
В результате упал только один тест, могло быть и хуже. Оказалось, что падал тест из-за того, что JUnit позволяет компилировать сравнение разных типов при assert:
Последние приготовления перед выходом в свет стабильной версии
Теперь, когда уже написан весь код, который планировался, можно сделать последние приготовления. Обновим версию в приложении на стабильную 1.0.0:
<version>1.0.0</version>
и добавим описание в RELEASE_NOTES:
Создаем наш первый релиз: v1.0
Весь код, который мы планировали уместить в MVP, готов, и теперь нужно подвести черту — создать релиз. Что такое релиз? Это опять калька из английского слова release, которое в нашем случае означает выход новой версии продукта. Для этого у GitHub в репозитории есть секция Releases, в которой как раз будут храниться релизы. Только их нужно создавать.

Что дальше с ботом?
Конечно, хочется, чтобы бот начал развиваться за счет сообщества. Чтобы молодые разработчики предлагали свои идеи по реализации новой функциональности. Но здесь насильно мил не будешь, пока таких нет, и я буду посильно развивать его. Есть несколько направлений, которые интересны для меня:Создать джобу для ежедневного сбора и сохранения статистики бота, чтобы можно было отследить во времени его развитие.
Настроить работу с бэкапами, в целом идея описана в предыдущей статье.
Подумать над унитаризацией подхода в создании телеграм бота для получения уведомлений о новых статьях. В идеале (хотя я не знаю, получится ли такое) сделать так, чтобы был опубликованный Spring boot стартер, который бы требовал настройки базы данных, бота и реализации интерфейсов работы для получения данных о статьях, а остальное бы делала эта библиотека. Посмотрим что из этого может получиться, тут нужно хорошенько подумать.
Расширить статистику для всех по авторам: сколько статей, количество просмотров статей, какая оценка статей. По понятным причинам JavaRush не является блогом для написания статей, и поэтому такого функционала у него попросту нет. А мне, как автору, это интересно. При помощи бота можно создать продуманную статистику и вести ее.
Реализовать обработку исключений так, чтобы было пользователю было понятно, что произошло.
Выделить отдельно Java-библиотеку с JavaRush API client.
Добавить GitHub action, который бы создавал релиз автоматически каждый раз, когда обновляется ветка main.
Добавить подписку на конкретного автора, а не на группу статей.
Улучшить UI представление бота. Вместо уродливых команд создать красивые кнопки, которые бы помогли более приятно и элегантно управлять ботом.
Так как информация о новых статьях может быть интересна еще каким-то каналам (как минимум у меня есть такой интерес к моим статьям и моему телеграм-каналу), то хорошо бы добавить возможность боту отправлять сообщения о новых статьях напрямую в какой-то канал, а не только в личных сообщениях.
Изучить опыт ботов, которые работают в группах и посмотреть, что можно сделать с этим в нашем случае. Я уверен, что есть закрытые группы людей, изучающих Java, которым было бы интересно получать уведомления о новых статьях.
Ретроспектива (вместо окончания)
Я часто повторяю это слово уже последние несколько статей. Что это значит? Для меня в рамках этой серии — это посмотреть на то, что я хотел сделать и что за эти 8 месяцев получилось. Было немало комментариев на тему того, что все это классно, хоть бы автор сделал это до конца:


Главной целью проекта было написание приложение с базой данных, в котором была бы настроена работа по развертыванию и управлению. Эта цель точно достигнута.
Сроки разработки сдвинулись и были проблемы с выходом статей. Были моменты, когда не было статей по 2-3 недели.
Полностью настроили работу с БД, добавили Flyway.
Описали работу с Maven в нескольких статьях.
Поговорили о Docker. Не так много и детально, как хотелось бы, но все же.
Баш скрипты мы тоже затронули, у нас на этом настроен запуск всего развертывания.
По планированию проекта можно сказать, что все прошло максимально реалистично. Только несколько задач были добавлены в процессе написания.
Полностью не рассмотрели сравнение двух решений — Flyway и Liquibase.
Как-то вскользь поговорили о Lombok’e. Так только на практике и все. Хотелось бы больше.
Мало уделили время для UniRest решения.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ