JavaRush /Java Blog /Random EN /Refactoring and retrospective - "Java project from A to Z...

Refactoring and retrospective - "Java project from A to Z"

Published in the Random EN group
Hello everyone, dear friends. This is the last article in our series on creating a Java project from A to Z. Today we will talk about what would be good to refactor, as well as discuss the result of our work and talk about plans for the future of the CodeGymTelegramBot project. "Java project from A to Z": Refactoring and retrospective - 1

Let's refactor our code

Let's create a new branch for this case: STEP_10, in which we will write down all the latest changes before the MVP. Refactoring is changing the codebase without changing its behavior. What do you want to change? At the very beginning, I chose the word article as the term “article” on the project, and until I started working with the Javarush API client for articles, it was logical. But the Javarush API uses the term post . And I think it would be good to switch to their standard, so the first thing we do is rename everything from article to post. What will be our guarantee that everything remains the same? The guarantee will be our tests that we have written. Now we need them. Let's start with the database. In the group_sub table, you need to rename the lastArticleId field to lastPostId. This is very simple because we already have Flyway configured and in order to update the field, we just need to add one more migration in which we will perform an ALTER TABLE operation. Let's create a new, third, migration: V00003__rename_last_article_id.sql which will be:
ALTER TABLE group_sub CHANGE COLUMN last_article_id last_post_id INT;
This migration needs to be placed in the same place as the previous two. Next, you need to rename the variable name in the GroupSub entity from lastArticleId to lastPostId. If the work goes through IDEA, then renaming is very simple, you need to use the hot key: shift + F6, when the cursor is on the class / method / field name, then the development environment allows you to rename all the places where this field is used. It will also rename the getters and setters for this field. This is a useful item and should be in every developer's arsenal. I'm sure that the eclipse has the same functionality, but I can't tell you, I don't use it. "Java project from A to Z": Refactoring and retrospective - 2so rename
@Column(name = "last_article_id")
private Integer lastArticleId;
V
@Column(name = "last_post_id")
private Integer lastPostId;
Next, using the search throughout the project (ctrl + shift + f), we will find all the places where there are mentions of Article: "Java project from A to Z": Refactoring and retrospective - 3It can be seen from the figure that we still have class and method names with the word Article. They also need to be renamed to Post. We use the already known command shift + F6 for them:
  • class FindNewArticlesJob -> FindNewPostsJob

  • class FindNewArticleService -> FindNewPostsService

  • method FindNewArticleService#findNewArticles -> FindNewPostsService#findNewPosts

  • class FindNewArticleServiceImpl -> FindNewPostsServiceImpl

  • property bot.recountNewArticleFixedRate -> bot.recountNewPostFixedRate

  • method CodeGymGroupClient#findLastArticleId -> CodeGymGroupClient#findLastPostId

  • method FindNewPostsJob#findNewArticles -> FindNewPostsJob#findNewPosts

  • And other places where internal methods, where comments.

We also have a BPMN model that describes the process of searching for new articles. We will change it through a special program CamundaModeler, through it I form a new picture in the README. As a result, we get: "Java project from A to Z": Refactoring and retrospective - 4I also want to bring the search for something to one form. At the moment I have two verbs: find and retrieve . I want to rename all retrieve to find :
  • method CommandContainer#retrieveCommand -> CommandContainer#findCommand
  • all javadocs with retrieve in find .
Next, I want to decide the chatId field . Based on the telegram dock , we can say that this is a numeric value. Therefore, I think it would be good practice to do the same in the application. It is stored in the database as a string value. We did this because, for some reason, in our bot library, when sending messages, chatId was exactly a string. Let's change everything so as to convert to a string exactly at that moment. First of all, we update the SendBotMessageService interface :
/**
* 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);
}
Now the interface accepts not String chatId , but Long chatId . We also update the implementation, just put chatId.toString() in the required field:
sendMessage.setChatId(chatId.toString());
Next, go to the TelegramUser class and change the type of the chatId variable from String to Long :
@Id
@Column(name = "chat_id")
private Long chatId;
In TelegramUserRepostiry we also change from String to Long in the inherited interface :
/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, Long> {
   List<TelegramUser> findAllByActiveTrue();
   List<TelegramUser> findAllByActiveFalse();
}
Update the CommandUtils#getChatId method to not result in a string:
/**
* 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();
}
And in all places where chatId is used , we remove the cast to the string. Where methods accept String chatId , change the type to Long . By the way, while changing the cast to the string, I found that the getChatId(update) utility method is not used everywhere, so I updated those places as well. The last step is to update the field type in the tg_user table . To do this, let's create the fourth migration V00004_change_chat_id_type_to_long.sql :
ALTER TABLE tg_user MODIFY chat_id INT;
After all these updates, it's time to run the tests :D As a result, only one test fell, it could have been worse. It turned out that the test crashed due to the fact that JUnit allows compiling a comparison of different types during assert: "Java project from A to Z": Refactoring and retrospective - 5As soon as I did Long.valueOf (i + 1) instead of String.valueOf( i + 1) , the test started working as expected. Now we need to make sure that the bot starts and works as expected. I'll try to add a subscription, see the list of subscriptions and delete one of them. I think this is enough to check for a smoke test. Poklatsal everything I could, everything works. This is good, so the refactoring went exactly as I wanted - the code changed, but the changes did not affect the behavior of the bot in any way. We did a good refactoring of the project. The terms were brought to a common denominator and the confusion with the type of the chatId variable was removed .

Final preparations before the release of the stable version

Now that all the code that was planned has already been written, we can make the final preparations. Let's update the version in the application to stable 1.0.0 :
<version>1.0.0</version>
and add a description to RELEASE_NOTES:
# Release Notes ## 1.0.0 Implemented all the logic, planned up to MVP: * User can subscribe on group of posts * User can view list of group subscriptions on which user subscribes * User can unsubscribe from group of posts * User can set an inactive bot and do not receive notifications * User can restart getting notifications * Admin has ability to see bot statistics
I took all these points from README.md, I think they will just describe the result of the work that has been done over these 8 months. The next step is to create a commit, in which I duplicate the data from RELEASE_NOTES. Get the PR with the latest changes: STEP_10: v1.0.0 .

Building our first release: v1.0

All the code that we planned to fit into the MVP is ready, and now we need to draw a line - create a release. What is a release? This is again a tracing paper from the English word release, which in our case means the release of a new version of the product. To do this, GitHub has a Releases section in the repository , in which releases will be stored. They just need to be created. "Java project from A to Z": Refactoring and retrospective - 6Let's merge the latest pull request and create our first release based on the latest commit in the main branch. Let's go and create a new release and fill it with data: "Java project from A to Z": Refactoring and retrospective - 7Everything, you can click Publish Release. And that's it, now we have our first release of the application. It's time for a retrospective.

What's next for the bot?

Of course, I want the bot to start developing at the expense of the community. For young developers to offer their ideas for implementing new functionality. But you won’t be forced to be nice here, as long as there are no such people, and I will develop it to the best of my ability. There are several areas that are of interest to me:
  • Create a job to collect and save bot statistics on a daily basis so that you can track its development over time.

  • Set up work with backups, in general, the idea is described in the previous article.

  • Think about unitarizing the approach in creating a telegram bot to receive notifications of new articles. Ideally (although I don’t know if this will work) to make it so that there is a published Spring boot starter that would require setting up a database, a bot, and implementing work interfaces to get data about articles, and this library would do the rest. Let's see what can come of this, we need to think carefully here.

  • Expand statistics for all by authors: how many articles, number of views of articles, what is the rating of articles. For obvious reasons, CodeGym is not a blog for writing articles, and therefore it simply does not have such functionality. And for me, as an author, this is interesting. With the help of a bot, you can create thoughtful statistics and maintain them.

  • Implement exception handling in a way that makes it clear to the user what happened.

  • Separate Java library with CodeGym API client.

  • Add a GitHub action that automatically creates a release each time the main branch is updated.

  • Add a subscription to a specific author, not a group of articles.

  • Improve the UI presentation of the bot. Instead of ugly commands, create beautiful buttons that would help to control the bot in a more pleasant and elegant way.

  • Since information about new articles may be of interest to some other channels (at least I have such interest in my articles and my telegram channel), it would be nice to add the ability for the bot to send messages about new articles directly to some channel, not just private messages.

  • Study the experience of bots that work in groups and see what can be done with this in our case. I'm sure there are closed groups of Java learners who would be interested in being notified of new articles.

These are not all the ideas that I had while working on the project, but those that I managed to write down before they disappeared)) If you have any ideas, write in the comments, I will be happy to talk about them.

Retrospective (instead of ending)

I've been repeating this word a lot over the past few articles. What does it mean? For me, within the framework of this series, it is to look at what I wanted to do and what happened during these 8 months. There were many comments on the topic that all this is cool, even if the author did it to the end: "Java project from A to Z": Refactoring and retrospective - 8"Java project from A to Z": Refactoring and retrospective - 9"Java project from A to Z": Refactoring and retrospective - 10Now we can already say that yes, I did finish it. Did I think it would be sooo long? No, I didn't. I expected to do before the beginning of 2021. But I realized that I need to talk about databases, which went to a whole series of articles, and about many technologies. And it stretched out. Although I can say that I am satisfied with the result and the volume of work. I see people who learn from it, express their gratitude, and this motivates me to go further. What did it give me? First of all, understanding that such projects can be taken on and they are of interest. I always read comments on articles with great pleasure and respond to them to the best of my ability. Of course, I became more experienced in both writing articles and writing applications, because the process of deploying the application required me to improve my skills. Yes, I knew what I wanted to do in the end, I knew that it was real. And it still took time to study the implementation of my ideas. In the process of writing this series, I wanted to somehow organize my materials in one place, and for this I created my owntelegram channel , which already has more than 400 subscribers. For me, this is a great result. New direction of development. Now there is an understanding of where to grow further. Also in the process, a new product was born that people already use, and I in particular - Javarush Telegram Bot . Yes, so far only 26 active users. But I believe that it will be in demand and the number of users will grow. What is good about this project? It is still to be developed and developed. Students from CodeGym who want to hone their skills would be able to propose new features and implement them. And I will lead this project and conduct a Code Review of all changes. We finalize what was planned and what happened:
  • The main goal of the project was to write a database application that would be configured to work on deployment and management. This goal has been definitely achieved.

  • The development deadlines shifted and there were problems with the release of articles. There were moments when there were no articles for 2-3 weeks.

  • Completely set up work with the database, added Flyway.

  • Described working with Maven in several articles.

  • We talked about Docker. Not as much and detailed as we would like, but still.

  • We also touched on bash scripts, we have set up the launch of the entire deployment on this.

  • According to the planning of the project, we can say that everything went as realistically as possible. Only a few tasks were added during the writing process.

What didn't they do?
  • We did not fully consider the comparison of two solutions - Flyway and Liquibase.

  • Somehow we casually talked about Lombok'e. So only in practice and all. I would like more.

  • Little time was spent on the UniRest solution.

Maybe I missed something? Write in the comments. Thanks to everyone who actively participated in the development of this project. I'm looking forward to your feedback on how it turned out. Feedback, so to speak) While writing this series, I have accumulated a lot of interesting topics that I would like to talk about, so we will soon write our summary on GitHub! See you)"Java project from A to Z": Refactoring and retrospective - 11

List of all materials in the series at the beginning of this article.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION