JavaRush /Java блог /Random UA /Рефакторний і ретроспективний - "Java-проект від А до Я"
Roman Beekeeper
35 рівень

Рефакторний і ретроспективний - "Java-проект від А до Я"

Стаття з групи Random UA
Всім привіт, дорогі друзі. Це остання стаття в нашій серії зі створення Java-проекту від А до Я. Сьогодні поговоримо про те, що добре відрефакторити, а також обговоримо результат нашої роботи і поговоримо про плани на майбутнє проекту CodeGymTelegramBot. "Java-проект від А до Я": Рефакторим та ретроспективним - 1

Відрефакторимо наш код

Створимо під цю справу нову гілку: 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, коли курсор знаходиться на імені класу / методу / поля, тоді середовище розробки дозволяє перейменувати всі місця, де використовується це поле. Це корисна річ і повинна бути в арсеналі кожного розробника. Я впевнений, що такий самий функціонал є й у екліпса, але підказати не можу, я ним не користуюся. "Java-проект від А до Я": Рефакторим та ретроспективним - 2тому перейменуємо
@Column(name = "last_article_id")
private Integer lastArticleId;
в
@Column(name = "last_post_id")
private Integer lastPostId;
Далі за допомогою пошуку по всьому проекту (ctrl+shift+f) знайдемо всі місця, де є згадки Article: "Java-проект від А до Я": Рефакторим та ретроспективним - 3Видно з малюнка, що ми ще маємо імена класів і методів зі словом 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

  • І решта місць, де внутрішні методи, де коментарі.

Також у нас є BPMN модель, в якій описаний процес пошуку нових статей. Його міняти ми будемо через спеціальну програму CamundaModeler, через неї та формую нову картинку в README. В результаті отримаємо: "Java-проект від А до Я": Рефакторим та ретроспективним - 4Ще хочу привести до одного виду пошук чогось. На даний момент у мене використовується два дієслова: find і retrieve . Хочу перейменувати все retrieve на find :
  • метод CommandContainer#retrieveCommand -> CommandContainer#findCommand
  • всі джавадоки з retrieve в find .
Далі хочеться вирішити поле chatId . Спираючись на доку з телеграма , можемо сказати, що це числове значення. Тому я думаю, буде гарним тоном зробити також і в додатку. У базі даних воно стоїть як рядкове значення. Зробабо ми це тому, що з якоїсь причини в нашій бібліотеці роботи з ботом під час надсилання повідомлень chatId був саме рядковим. Поміняємо все так, щоб конвертувати в рядок саме на той момент. Насамперед оновлюємо інтерфейс SendBotMessageService :
/**
* 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: "Java-проект від А до Я": Рефакторим та ретроспективним - 5Як тільки я замість String.valueOf(i + 1) зробив Long.valueOf(i + 1) , то тест почав працювати, як очікується. Тепер потрібно переконатися, що бот запускається та працює, як очікується. Спробую додати передплату, переглянути список передплат і видалити одну з них. Думаю, цього вистачить для того, щоб перевірити на smoke test. Поклацав усе, що міг, усе працює. Це добре, отже, рефакторинг пройшов саме так, як я хотів — змінився код, але зміни ніяк не вплинули на поведінку бота. Ми провели непоганий рефакторинг щодо проекту. Привели до спільного знаменника терміни та прибрали плутанину з типом змінної chatId .

Останні приготування перед появою стабільної версії

Тепер, коли вже написано весь код, який планувався, можна зробити останні приготування. Оновимо версію у додатку на стабільну 1.0.0 :
<version>1.0.0</version>
і додамо опис у RELEASE_NOTES:
# Release Notes ## 1.0.0 Implemented all the logic, planned up to MVP: * User can subscribe on group of posts * an inactive bot and do not receive notifications * User can restart getting notifications * Admin has ability to see bot statistics
Всі ці пункти я взяв із README.md, думаю вони якраз опишуть результат роботи, яка була зроблена за ці 8 місяців. Наступний етап – створюємо коміт, у ньому я дублюю дані з RELEASE_NOTES. Отримаємо ПР з останніми змінами: STEP_10: v1.0.0 .

Створюємо наш перший реліз: v1.0

Весь код, який ми планували вмістити в MVP, готовий, і тепер треба підбити межу — створити реліз. Що таке реліз? Це знову калька з англійського слова release, яке означає вихід нової версії продукту. Для цього у GitHub в репозиторії є секція Releases , в якій зберігатимуться релізи. Тільки їх треба творити. "Java-проект від А до Я": Рефакторим та ретроспективним - 6Смержемо останній пулл-реквест і створимо свій перший реліз на основі останнього комміту в main гілці. Переходимо та створюємо новий реліз та заповнюємо даними: "Java-проект від А до Я": Рефакторим та ретроспективним - 7Все, можна натискати Publish Release. І все, тепер у нас є наш перший реліз програми. Настав час і для ретроспективи.

Що далі з ботом?

Звичайно, хочеться, щоб бот почав розвиватися за рахунок спільноти. Щоб молоді розробники пропонували свої ідеї щодо реалізації нової функціональності. Але тут насильно мабой не будеш, поки таких немає, і я посильно розвиватиму його. Є кілька напрямків, які цікаві для мене:
  • Створити джобу для щоденного збору та збереження статистики бота, щоб можна було відстежити у часі його розвиток.

  • Налаштувати роботу з бекапами, загалом ідея описана у попередній статті.

  • Подумати над унітаризацією підходу у створенні телеграм бота для отримання повідомлень про нові статті. В ідеалі (хоча я не знаю, чи вийде таке) зробити так, щоб був опублікований Spring boot стартер, який вимагав би налаштування бази даних, бота та реалізації інтерфейсів роботи для отримання даних про статті, а інше робила б ця бібліотека. Подивимося що з цього може вийти, тут треба добре подумати.

  • Розширити статистику для всіх за авторами: скільки статей, кількість переглядів статей, яка оцінка статей. Із зрозумілих причин JavaRush не є блогом для написання статей, і тому такого функціонала в нього просто немає. А мені як автору це цікаво. За допомогою робота можна створити продуману статистику і вести її.

  • Реалізувати обробку винятків так, щоб було зрозуміло, що сталося.

  • Виділити окремо Java-бібліотеку із JavaRush API client.

  • Додати GitHub action, який би створював реліз автоматично щоразу, коли оновлюється гілка main.

  • Додати передплату на конкретного автора, а не на групу статей.

  • Поліпшити UI подання бота. Замість потворних команд створити красиві кнопки, які б допомогли приємніше та елегантніше керувати ботом.

  • Так як інформація про нові статті може бути цікава ще якимось каналам (як мінімум у мене є такий інтерес до моїх статей і мого телеграм-каналу), то добре додати можливість боту відправляти повідомлення про нові статті безпосередньо в якийсь канал, а не лише в особистих повідомленнях.

  • Вивчити досвід ботів, які працюють у групах та подивитися, що можна зробити з цим у нашому випадку. Я впевнений, що є закриті групи людей, які вивчають Java, яким було б цікаво отримувати повідомлення про нові статті.

Це не всі ідеї, які були у мене під час роботи над проектом, а ті, які я встиг записати, поки вони не зникли)) Якщо є ідеї, пишіть у коментарях, я із задоволенням поговорю про них.

Ретроспектива (замість закінчення)

Я часто повторюю це слово останні кілька статей. Що це означає? Для мене в рамках цієї серії це подивитися на те, що я хотів зробити і що за ці 8 місяців вийшло. Було чимало коментарів на тему того, що все це класно, бодай автор зробив це до кінця: "Java-проект від А до Я": Рефакторим та ретроспективним - 8"Java-проект від А до Я": Рефакторим та ретроспективним - 9"Java-проект від А до Я": Рефакторим та ретроспективним - 10Тепер уже можна сказати, що так, я таки завершив. Чи думав я, що це буде тааак довго? Ні, не думав. Очікував, що зроблю до початку 2021 року. Але я зрозумів, що треба розповісти і про бази даних, які вийшли на цілу серію статей, і про багато технологій. І це розтягнулося. Хоча можу сказати, що і результатом та обсягом роботи задоволений. Я бачу людей, які навчаються на цьому, висловлюють свою подяку і це мотивує мене йти далі. Що це дало мені? Насамперед розуміння, що такі проекти можна брати і вони мають інтерес. Я завжди з великим задоволенням читаю коментарі до статей та в міру сил відповідаю на них. Звичайно, я став досвідченішим і в написанні статей, і в написанні додатків, тому що процес розгортання програми зажадав від мене вдосконалення моїх навичок. Так, я знав що я хочу зробити у підсумку, я знав що це реально. І все одно потрібен час вивчення реалізації моїх ідей. У процесі написання цієї серії захотілося якось систематизувати свої матеріали в одному місці і для цього я створив свійтелеграм-канал , в якому вже понад 400 передплатників. Для мене це шикарний результат. Новий напрямок розвитку. Тепер є розуміння, куди зростати далі. Також у процесі народився новий продукт, яким вже користуються люди і я зокрема Javarush Telegram Bot . Так, поки що лише 26 активних користувачів. Але я вірю, що це буде затребувано і кількість користувачів зростатиме. Чим гарний цей проект? Його ще розвивати та розвивати. Студенти з JavaRush, які хочуть відточити свої навички, змогли б пропонувати новий функціонал та реалізовувати його. А я керуватиму цим проектом і проводитиму Code Review всіх змін. Фіналізуємо те, що планувалося та що вийшло:
  • Головною метою проекту було написання додатка з базою даних, в якому було б налаштовано роботу з розгортання та управління. Ця мета точно досягнута.

  • Строки розробки зрушабо і були проблеми з виходом статей. Були моменти, коли не було статей за 2-3 тижні.

  • Цілком налаштували роботу з БД, додали Flyway.

  • Описали роботу з Maven у кількох статтях.

  • Поговорабо про Docker. Не так багато і детально, як хотілося б, але все ж таки.

  • Баш скрипти ми теж торкнулися, у нас на цьому налаштований запуск всього розгортання.

  • За плануванням проекту можна сказати, що все пройшло максимально реалістично. Лише кілька завдань було додано у процесі написання.

Що не зробабо?
  • Цілком не розглянули порівняння двох рішень — Flyway та Liquibase.

  • Якось побіжно поговорабо про Lombok'e. То тільки на практиці і все. Хотілося б більше.

  • Мало приділабо час для UniRest рішення.

Може, я щось упустив? Пишіть у коментарях. Дякую всім, хто брав активну участь у процесі розвитку цього проекту. Чекаю від вас відгуку про те, що в результаті вийшло. Поки я писав цю серію, у мене накопичилося багато цікавих тем, про які я б хотів поговорити, так що скоро будемо писати своє резюме на GitHub ! До зустрічі)

Список всіх матеріалів серії на початку цієї статті.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ