Skip to content

[이윤섭] sprint6#202

Open
jonasInDark wants to merge 28 commits intocodeit-bootcamp-spring:이윤섭from
jonasInDark:sprint6
Open

[이윤섭] sprint6#202
jonasInDark wants to merge 28 commits intocodeit-bootcamp-spring:이윤섭from
jonasInDark:sprint6

Conversation

@jonasInDark
Copy link
Copy Markdown
Collaborator

@jonasInDark jonasInDark commented Mar 11, 2026

회고

  • User, Channel 에 관한 기능들까지 구현했습니다.
    사실 구현만 했고 테스트는 못해봤습니다.
  • Channel 관련 api 구현 중 최근 메세지 생성 시간도 함께 가져와야 했습니다.
    구현 중 N+1 문제를 마주했고 해결 방법을 위해 많은 시간을 사용했습니다.
    가장 쉬운 방법으로 Fetch Join 이 있습니다.
    연관된 모든 entity 를 함께 가져옵니다.
    하지만 pagination 을 사용할 수 없기에 다른 방법을 찾아봤습니다.
    QueryDSL 에 대해 공부했습니다.
    Join sql 을 native 가 아닌 java code 로 구현할 수 있어서 편리합니다.
    예를 들어 entity field 를 refactoring 할 때 안전합니다.
-- 내가 원하는 query
select c.*, max_created_at
from channels c
left join (select channel_id, max(created_at) as max_created_at
           from messages
           group by channel_id) as m on c.id = m.channel_id;
-- AI 가 추천한 query
select c.*, (select max(created_at)
             from messages m
             where c.id = m.channel_id)
from channels c;

전자는 messages table 를 먼저 group by 하고 channels 와 join 합니다.
index 를 많이 활용하므로 데이터가 많은 경우 성능이 더 좋습니다.
후자는 channel_id 마다 messages table 의 channel_id 와 비교 후 max_created_at 을 계산합니다.
데이터가 적다면 전자 보다 성능이 더 좋다라고 AI 가 말합니다.
전자를 QueryDSL 로 구현하고 싶었지만 하지 못했고 jdbcTemplate 으로 할 수 있다고 합니다.
성능도 더 좋습니다.
거기까지는 너무 멀리가는 것 같아 여기서 마무리 했습니다.

  • 전반적으로 제가 구현한 결과물은 매우 미완성이지만 이번 과제를 통해 많이 배웠습니다.
    추후 시간이 된다면 반드시 마무리할 예정입니다.
  • 과제를 하면서 AI 에게 많은 질문을 했습니다.
    더 좋은 방법은 없는지, 중복된 구조를 줄일 수 없는지, 적절한 이름 추천, ...
    많은 도움을 받았지만 대부분 제가 만든 코드이며 어떻게 동작하는지 알고 있습니다.
    이번 과제만 그런 것이 아니라 이전부터 그렇게 해왔습니다.
    감사합니다.

+ misc: modify docker-compose.yml, application-dev.yml
- init jpa entity: UserV2, UserStatusV2, ChannelV2, BinaryContentV2, MessageV2, ReadStatusV2
- UserServiceDto: init UserDto, UserUpdateDto, UserCreateDto, UserUniquenessDto, UserResponse
- GlobalMapperConfig: init
- BaseMapper: init
- UserMapper: init
- UserService: command -> dto
- BasicUserService: remove IdGenerator
- BasicUserService: suspending 'find' because not including api specs
- BasicUserService: convert entity <-> dto using mapper
- BasicDomainService: update
- BaseMapper: update
- BaseEntity: update
- BaseUpdatableEntity: update
- dto: ChannelServiceDto split by self and several requestDto
- Channel: update with jpa
- ChannelMapper: init
- ChannelService: refactoring
- BasicChannelService: update corresponding to jpa repository
- ChannelController: update using mapper
- Message: add update, constructor
- MessageServiceDTO: split by requestDto and dto
- MessageMapper: init
- BasicMessageService: update using mapper, dto
- MessageController: mapper used to convert several parameter into one dto
- BinaryContent: add constructor
- BinaryContentServiceDto: init requestDto, dto
- BinaryContentMapper: init
- BasicBinaryContentService: using mapper
- BinaryContentController:
… and init mapper

- ReadStatus: add constructor, update
- ReadStatusServiceDTO: split by requestDto and dto
- ReadStatusMapper: init
- ReadStatusRepository: add features about userId and channelId
- BasicReadStatusService: update using mapper
- ReadStatusController: convert requestDto to ReadStatusDto
- AuthServiceDTO: change annotation
- UserRepository: add feature for auth
- BasicAuthService: update login
- AuthController: add Valid annotation
…entity

- BasicUserStatusService: remove create, find, findAll, delete
- UserStatusMapper: init
- UserStatus: add constructor, update
- UserStatusServiceDTO: update
- BinaryContentController: add download feature
- User: add constructor
- UserDto: add constructor
- UserFindRequest: removed
- UserMapper: update toResponse, remove toDtoFrom*Request
- UserService: remove extends DomainService
- BasicUserService: add transaction
- UserController: remove mappers
@jonasInDark jonasInDark added the 미완성🛠️ 스프린트 미션 제출일이지만 미완성했습니다. 죄송합니다. label Mar 11, 2026
- build.gradle: add dependencies analysis, openfeign.QueryDSL
- docker-compose.yml: db port 5432 -> 5433
To retrieve the 'lastMessageAt' of a 'channel', the associated 'Message' must be retrieved.
This process causes the 'N+1 problem'.
A simple solution would be to use a 'fetch join'.
However, 'QueryDSL' was chosen to further improve performance.
Querying a single 'Channel' alone used 2 'Query's.

If this method were applied to query multiple 'Channels', it would generate N+N 'Query's, so a different approach was used to resolve this.

Consequently, it was concluded that using 'Native SQL' is the best option.
- APIExceptionAdvice: rename handleIdNotFound -> handleAPIException
- APIExceptionAdvice: add handleIncorrectInput
- ErrorCode: add PRIVATE_CHANNEL_CANT_BE_UPDATED
- TimeConverter: change LocalDateTime(deprecated) to LocalDate
- update entity: Message, ReadStatus, UserStatus
- update dto: BinaryContentServiceDTO, MessageServiceDTO, UserStatusServiceDTO
- TimeMapper(util mapper): init
- update: GlobalMapperConfig, BinaryContentMapper, ReadStatusMapper, UserMapper, UserStatusMapper
- dto: change LocalDateTime to LocalDate
- controller: renaming
@jonasInDark jonasInDark requested a review from jaeyeon518 March 15, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

미완성🛠️ 스프린트 미션 제출일이지만 미완성했습니다. 죄송합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant