This post has been translated from Korean to English by Gemini CLI.
This article is a retrospective on my experiences while working on the project.
If you have any questions, please leave a comment or contact me at joyson5582@gmail.com!
Currently, our team is test-operating a project targeting prospective 7th-term students of Woowa Brothers Tech Course.
Code Review Matching Platform
The puzzle of development growth completed with CoReA: Code, Review, and You
CoReA (Code-Review-Area) is a mission code review matching platform.
We create 'growth together' through code reviews and mutual feedback.
- Repository Link: https://github.com/woowacourse-teams/2024-corea
- Site Link: https://code-review-area.com/
(This is the user growth rate. We have now exceeded 300 users! 🙇)
As such, I was able to have a valuable experience developing a project and welcoming users.
Now, I will write about what I felt while operating a service with such users.
It was very easy to develop features for a project with given requirements.
I just had to create a new package, and then create controller, service, and domain packages in it and add them.
However, I felt that additional requirements, which were not initially thought of as feature development, caused great difficulty.
Most of them are modifications and additions to existing code. It becomes very difficult if you don't have a good understanding of the code you need to work on.
And it's very busy. If before it was just feature development, now additional tasks such as server management, feature modification, and error handling have arisen.
On top of that, I also have to reflect feedback and develop desired features.
I felt this in many parts.
What I learned most meaningfully during Levels 1-2 was object-oriented code and clean code.
However, the project could not perfectly take care of this.
Requirements do not wait for development time.
Everyone knows that this is not the best, but if you make an RC (Request Change), you cannot meet the deadline.
This code continuously accumulates.
At some point, the next person in charge will not want to touch the code.
I asked the coaches and former reviewers about this, but the conclusion I reached was:
"It seems that we should tolerate a certain degree of dirtiness, but when the threshold approaches, the person who feels the dirtiness should refactor."
In particular, I think I had the thought,
Is it possible to do a pit stop, which is to stop all feature development and proceed?
Therefore, I also felt thatchanging a rolling wheel, which is to continuously develop a service with actual users, truly helps a developer's growth.
(Even for a single feature, I am more careful + pay attention to ensure that existing code does not cause problems.)
As I said above, Levels 1 and 2 were a series of object-oriented code.
I tried to write the code as object-oriented as possible in the project as well.
However, I felt some regret in several places while testing indexes + analyzing queries for DB performance improvement requirements.
public void participate() {
if (memberRole.isReviewer()) {
room.increaseReviewerCount();
return;
}
if (memberRole.isBoth()) {
room.increaseBothCount();
}
}(If you think there's another correct answer? There's no code without a story. 🥲)
I tried to make objects have variables that fit the object.
I thought, "It's natural for a room to have its own status, deadline, and development field (Android, backend, etc.)."
However, I felt great difficulty in improving the performance of such data through indexes. (Especially, there was no significant reduction. 😭)
Of course, I don't know if this can be clearly solved through entity separation and JOIN.
Ultimately, I felt that it was as important as object-orientation to consider how an entity would operate.
(To solve this, separating entities - domains like DDD might be a good method. ☺️)
Busy schedules led to insufficient testing and QA.
In fact, it might be more accurate to say that I failed to perform perfect tests on more complex features and added features, rather than just busy schedules.
This time, I realized that among the logics,
there was a logic that completed code review -> moved to the development feedback writing page for the corresponding target.
Here, the frontend caused an error where undefined occurred because it fetched a value from a wrong State, making it unable to render the page.
I checked for problems on the development server, but a problem occurred in conjunction with the logic that was added recently: If you don't leave feedback for the other person, it will be masked.
The most important problem occurs here.
This error was not detected by the project team members,


We found out after users submitted problems.
In particular, there might be users who encountered errors without directly contacting us. 😭😭 (I'm sorry,,)
Additionally, this is also a recent error where entities created when participating in a review room
caused NonUniqueResultException because only one person out of 394 had 3 duplicate entities.
(I haven't figured out the exact cause yet 🥲)

I checked the logs for this content, but there was no way to contact the user.
So, I informed them of the error reason + resolution plan via GitHub comments.
For these reasons, I felt the need for a clear and quick communication channel.
We used to receive contacts through Google Forms, but we felt that Google Forms were not suitable as a communication channel.
Currently, we have an open chat room for quick communication.
Before launching the service, my biggest fear was, What if the server crashes...?
To prepare for this, I even created a spare instance just in case and continuously monitored it after promotion.
Despite such worries, the server has not crashed yet. 🥲
To briefly explain the infrastructure,
it is load-balanced through ALB,
and consists of one small type and one micro type.
The DB is separated into Reader-Writer through RDS.
First, for heap memory,
Based on small

It approached an average of 30%.
Based on micro

It approached an average of 50-60%.

Requests also showed stable peaks, except for those using external APIs (login, review completion).
Even in load tests, Connection Timeout occurred due to too many requests, but no server crashes were found.
We haven't applied optimizations like indexing and caching yet.
As a result of index tests, when about 1 million data were inserted, we saw a performance improvement of about 3 seconds -> 0.5 seconds,
but there were many parts where I wondered if this was really necessary.
(Because 1 million data are not generated at once.)
(It seems okay to complete and launch the feature without too much fear ☺️)
This is a part I paid a lot of attention to. It was about improving developer productivity.
Developers actually don't just develop features. They do a lot of things in a project.
(In addition, I was buried in the mission requirements given by the coaches...)
In this way, I do a lot of internal/external development work.
So, I tried and made efforts to reduce the time spent on non-functional tasks in many areas.
I couldn't help but complain and repeat tasks like, "Isn't this unavoidable?" and "Do I have to do it again? It's too annoying."
I believe that repeated tasks waste team members' time and energy, and ultimately reduce project productivity.
Therefore, I tried and performed various tasks to improve developer productivity.At first, I also had thoughts like, Is it really necessary? and The return on effort is not good.
However, I think that all these things accumulated and became decisive tools that saved team members' time.
As a result of continuous efforts like this, I was able to work very efficiently in many areas.
(If you go into the contents, they are all things that can be sufficiently introduced within the team.)
+ It's also one of the advantages to hear positive feedback within the team. 🙂
Currently,

As such, we are creating a data dashboard that is easy for frontend developers to view.
This concludes a very long article.
I started this project in July and it's now nearing its end, and I've had a really fun and valuable experience.
What made me happiest was realizing how to do it in the real world from Level 2 onwards.
(In particular, finding precedents to see if email information is also recognized as personal information will be a very new experience. ☺️)
Among them, the biggest realization is that everything doesn't have to be perfect when launching a project.
When I first launched the service, I had many worries such as index optimization is not done... features are lacking... there is no monitoring alert system....
However, despite these worries, the project somehow works. (There are still many parts that need improvement and application.)
And, I felt that I could truly grow when creating a project with users.
Let's move forward to satisfy and make even one user happy! 🫡
Thank you again for reading this long article. 🙇♂️
This content is a brief reflection, so I left it as an appendix.
(It's really without any standards, purely my opinion.)
Our team used a domain package structure. (Each domain package owns service, controller, domain)
At first, I thought it would allow me to use the domain more completely and make the structure flexible. (Separation through inter-domain packages)
However, at some point, they became mixed, and some were located in one domain, and others in another.
From this perspective, I thought it might be a good idea to place all layers together. 🙂
(It's faster to find and you can simply use ambiguous concepts.)
As I said above, I don't think our current project has very beautiful code.
However, to solve this, "refactoring and redesign" inevitably takes time.
And, as feedback is received, features are modified and changed very frequently.
-> I'm still wondering how far to write beautiful code and how much time to spend.
Currently, entities have unnecessary columns.
public class Room extends BaseTimeEntity {
private int reviewerCount;
private int bothCount;
...
}This can be solved by count(*), but it's not an important value + I placed it because I didn't want to generate unnecessary queries.
public class MatchResult extends BaseTimeEntity {
@Enumerated(EnumType.STRING)
private ReviewStatus reviewStatus;
...
}This is solved by changing the Status without creating an entity called Review.
I think I need to learn more about these contents. 🥲
This is the end of the appendix~ If you have any opinions or thoughts about the appendix, please feel free to leave them 🫡