Відрефакторимо наш код
Створимо під цю справу нову гілку: 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: Видно з малюнка, що ми ще маємо імена класів і методів зі словом Article. Їх теж потрібно перейменувати на Post. Використовуємо відому команду shift+F6 для них:
-
клас FindNewArticlesJob -> FindNewPostsJob
-
клас FindNewArticleService -> FindNewPostsService
-
метод FindNewArticleService#findNewArticles -> FindNewPostsService#findNewPosts
-
клас FindNewArticleServiceImpl -> FindNewPostsServiceImpl
-
проперти bot.recountNewArticleFixedRate -> bot.recountNewPostFixedRate
-
метод CodeGymGroupClient#findLastArticleId -> CodeGymGroupClient#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: Як тільки я замість String.valueOf(i + 1) зробив Long.valueOf(i + 1) , то тест почав працювати, як очікується. Тепер потрібно переконатися, що бот запускається та працює, як очікується. Спробую додати передплату, переглянути список передплат і видалити одну з них. Думаю, цього вистачить для того, щоб перевірити на smoke test. Поклацав усе, що міг, усе працює. Це добре, отже, рефакторинг пройшов саме так, як я хотів — змінився код, але зміни ніяк не вплинули на поведінку бота. Ми провели непоганий рефакторинг щодо проекту. Привели до спільного знаменника терміни та прибрали плутанину з типом змінної chatId .
Останні приготування перед появою стабільної версії
Тепер, коли вже написано весь код, який планувався, можна зробити останні приготування. Оновимо версію у додатку на стабільну 1.0.0 :<version>1.0.0</version>
і додамо опис у RELEASE_NOTES:
Створюємо наш перший реліз: v1.0
Весь код, який ми планували вмістити в MVP, готовий, і тепер треба підбити межу — створити реліз. Що таке реліз? Це знову калька з англійського слова release, яке означає вихід нової версії продукту. Для цього у GitHub в репозиторії є секція Releases , в якій зберігатимуться релізи. Тільки їх треба творити. Смержемо останній пулл-реквест і створимо свій перший реліз на основі останнього комміту в main гілці. Переходимо та створюємо новий реліз та заповнюємо даними: Все, можна натискати Publish Release. І все, тепер у нас є наш перший реліз програми. Настав час і для ретроспективи.Що далі з ботом?
Звичайно, хочеться, щоб бот почав розвиватися за рахунок спільноти. Щоб молоді розробники пропонували свої ідеї щодо реалізації нової функціональності. Але тут насильно мабой не будеш, поки таких немає, і я посильно розвиватиму його. Є кілька напрямків, які цікаві для мене:-
Створити джобу для щоденного збору та збереження статистики бота, щоб можна було відстежити у часі його розвиток.
-
Налаштувати роботу з бекапами, загалом ідея описана у попередній статті.
-
Подумати над унітаризацією підходу у створенні телеграм бота для отримання повідомлень про нові статті. В ідеалі (хоча я не знаю, чи вийде таке) зробити так, щоб був опублікований Spring boot стартер, який вимагав би налаштування бази даних, бота та реалізації інтерфейсів роботи для отримання даних про статті, а інше робила б ця бібліотека. Подивимося що з цього може вийти, тут треба добре подумати.
-
Розширити статистику для всіх за авторами: скільки статей, кількість переглядів статей, яка оцінка статей. Із зрозумілих причин JavaRush не є блогом для написання статей, і тому такого функціонала в нього просто немає. А мені як автору це цікаво. За допомогою робота можна створити продуману статистику і вести її.
-
Реалізувати обробку винятків так, щоб було зрозуміло, що сталося.
-
Виділити окремо Java-бібліотеку із JavaRush API client.
-
Додати GitHub action, який би створював реліз автоматично щоразу, коли оновлюється гілка main.
-
Додати передплату на конкретного автора, а не на групу статей.
-
Поліпшити UI подання бота. Замість потворних команд створити красиві кнопки, які б допомогли приємніше та елегантніше керувати ботом.
-
Так як інформація про нові статті може бути цікава ще якимось каналам (як мінімум у мене є такий інтерес до моїх статей і мого телеграм-каналу), то добре додати можливість боту відправляти повідомлення про нові статті безпосередньо в якийсь канал, а не лише в особистих повідомленнях.
-
Вивчити досвід ботів, які працюють у групах та подивитися, що можна зробити з цим у нашому випадку. Я впевнений, що є закриті групи людей, які вивчають Java, яким було б цікаво отримувати повідомлення про нові статті.
Ретроспектива (замість закінчення)
Я часто повторюю це слово останні кілька статей. Що це означає? Для мене в рамках цієї серії це подивитися на те, що я хотів зробити і що за ці 8 місяців вийшло. Було чимало коментарів на тему того, що все це класно, бодай автор зробив це до кінця: Тепер уже можна сказати, що так, я таки завершив. Чи думав я, що це буде тааак довго? Ні, не думав. Очікував, що зроблю до початку 2021 року. Але я зрозумів, що треба розповісти і про бази даних, які вийшли на цілу серію статей, і про багато технологій. І це розтягнулося. Хоча можу сказати, що і результатом та обсягом роботи задоволений. Я бачу людей, які навчаються на цьому, висловлюють свою подяку і це мотивує мене йти далі. Що це дало мені? Насамперед розуміння, що такі проекти можна брати і вони мають інтерес. Я завжди з великим задоволенням читаю коментарі до статей та в міру сил відповідаю на них. Звичайно, я став досвідченішим і в написанні статей, і в написанні додатків, тому що процес розгортання програми зажадав від мене вдосконалення моїх навичок. Так, я знав що я хочу зробити у підсумку, я знав що це реально. І все одно потрібен час вивчення реалізації моїх ідей. У процесі написання цієї серії захотілося якось систематизувати свої матеріали в одному місці і для цього я створив свійтелеграм-канал , в якому вже понад 400 передплатників. Для мене це шикарний результат. Новий напрямок розвитку. Тепер є розуміння, куди зростати далі. Також у процесі народився новий продукт, яким вже користуються люди і я зокрема Javarush Telegram Bot . Так, поки що лише 26 активних користувачів. Але я вірю, що це буде затребувано і кількість користувачів зростатиме. Чим гарний цей проект? Його ще розвивати та розвивати. Студенти з JavaRush, які хочуть відточити свої навички, змогли б пропонувати новий функціонал та реалізовувати його. А я керуватиму цим проектом і проводитиму Code Review всіх змін. Фіналізуємо те, що планувалося та що вийшло:-
Головною метою проекту було написання додатка з базою даних, в якому було б налаштовано роботу з розгортання та управління. Ця мета точно досягнута.
-
Строки розробки зрушабо і були проблеми з виходом статей. Були моменти, коли не було статей за 2-3 тижні.
-
Цілком налаштували роботу з БД, додали Flyway.
-
Описали роботу з Maven у кількох статтях.
-
Поговорабо про Docker. Не так багато і детально, як хотілося б, але все ж таки.
-
Баш скрипти ми теж торкнулися, у нас на цьому налаштований запуск всього розгортання.
-
За плануванням проекту можна сказати, що все пройшло максимально реалістично. Лише кілька завдань було додано у процесі написання.
-
Цілком не розглянули порівняння двох рішень — Flyway та Liquibase.
-
Якось побіжно поговорабо про Lombok'e. То тільки на практиці і все. Хотілося б більше.
-
Мало приділабо час для UniRest рішення.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ