현재 개발자 사이드 프로젝트 팀 매칭을 하고
매칭한 팀끼리 멘토링 받을 수 있는 플랫폼을 제작하고 있습니다
개요
오늘은 팀의 세부사항을 보여주는 API를 제작하였다
팀의 전체 내용을 보여줘야 하다 보니 꽤 많은 내용의 데이터를 전송해주어야 했다
피그마를 보고 "팀 멤버 DTO", "기여한 멘토링 DTO"는
나중에 메인페이지/팀원, 메인페이지/멘토링을 만들때도
카드 형식으로 똑같이 쓰일수 있을것 같아 따로 클래스로 만들어 놓았다.
그러다보니....?
{
"title": "Team Example",
"description": "This is a sample team.",
"leaderID": 12345,
"teamUserCardList": [
{
"profileImageURL": "https://example.com/user1.jpg",
"memberLevel": "골드5",
"nickname": "User1",
"position": {
"positionName": "백엔드",
"level": "중수"
},
"score": 4.8,
"like": 50,
"stacks": [
"Java",
"Spring",
"JavaScript"
],
"role": "백엔드",
"approve": "Approved"
},
{
"profileImageURL": "https://example.com/user2.jpg",
"memberLevel": "실버2",
"nickname": "User2",
"position": {
"positionName": "프론트엔드",
"level": "초보"
},
"score": 3.5,
"like": 30,
"stacks": [
"Python",
"Django",
"React"
],
"role": "프론트엔드",
"approve": "Pending"
}
],
"meetingSpot": {
"onOffline": "Offline",
"city": "Seoul",
"detailSpot": "Central Park"
},
"mentoringList": [
{
"thumbnailURL": "https://example.com/mentoring1.jpg",
"title": "Mentoring 1",
"position": {
"positionName": "백엔드",
"level": "카카오 3년차"
},
"mentorProfileURL": "https://example.com/mentor1.jpg",
"mentorNickname": "Mentor1",
"score": 5.0,
"like": 100
},
{
"thumbnailURL": "https://example.com/mentoring2.jpg",
"title": "Mentoring 2",
"position": {
"positionName": "프론트엔드",
"level": "구글 10년차"
},
"mentorProfileURL": "https://example.com/mentor2.jpg",
"mentorNickname": "Mentor2",
"score": 4.0,
"like": 80
}
],
"stacks": [
"Java",
"Spring",
"JavaScript",
"Python",
"Django",
"React"
]
}
이러한 괴랄한 DTO가 만들어졌다.
아이디어
그래서 이걸 어떻게 프론트로 보내줄까 고민을 했고 떠오른 생각은 2가지였다.
1. 리포지토리에서 queryDSL로 쿼리를 날릴때 잘 select 하면 복잡한 정보를 DTO로 한번에 슥 가져올수 있지 않을까?
2. 객체 안에 정보들을 일단 다 가져오고 서비스단에서 응답 DTO에 끼워 맞춰도 되지 않을까?
시도
리포지토리에서 queryDSL로 쿼리를 날릴때 잘 select 하면
복잡한 정보를 DTO로 한번에 슥 가져올수 있지 않을까?
@Override
public TeamDetailResponse findTeamDetailByTeamID(Long teamID) {
TeamDetailResponse content = queryFactory
.select(Projections.bean(TeamDetailResponse.class, team.title,
team.description,
team.leaderID,
//"teamUserCardList"
Projections.list(Projections.bean(TeamUserCardResponse.class,
teamUser.user.pictureUrl,
teamUser.user.userLevel,
teamUser.user.name,
//"position"
Projections.bean(Position.class,
teamUser.user.position,
teamUser.user.positionLevel),
teamUser.user.reviewAverage,
teamUser.user.likes,
//"stacks"
Projections.list(
teamUser.user.userTagList),
teamUser.role,
teamUser.approve
)),
Projections.bean(MeetingSpot.class,
team.onOffline,
team.city,
team.detailSpot),
Projections.list(Projections.bean(MentoringCardResponse.class,
mentoringTeam.mentoring.thumbnailURL,
mentoringTeam.mentoring.title,
//"position"
Projections.bean(Position.class,
mentoringTeam.mentoring.user.position,
mentoringTeam.mentoring.user.positionLevel),
mentoringTeam.mentoring.user.pictureUrl,
mentoringTeam.mentoring.user.name,
mentoringTeam.mentoring.reviewAverage,
mentoringTeam.mentoring.likes
)),
Projections.list(team.teamTagList)
))
.from(team)
.leftJoin(teamUser).fetchJoin().on(teamUser.id.eq(teamID))
.leftJoin(mentoringTeam).fetchJoin().on(mentoringTeam.id.eq(teamID))
.where(team.id.eq(teamID))
.fetchOne();
return content;
}
첫번째 시도만에 성공하였다..!
첫번째 리팩토링
객체 안에 정보들을 일단 다 가져오고 서비스단에서 응답 DTO를 만들어주는 방식으로 변경 하게 되었다.
리팩토링 이유
DB에서 필요한 정보만 DTO에 맞게 싹 select 하여 값을 가져오면 성능 상 더 좋을 것이라고 생각했는데 어쩌피 DB에 접근하는 횟수는 같아서 성능 차이가 얼마 없었고 만들다 보니 DTO 특성상 변화가 잦았고 이 변화가 컨트롤러, 서비스, 리포지토리 단까지 모두 전파되었다.
그래서 repository단에선 Entity를 파라미터로 받아 모든 정보를 가져오고 서비스 레이어에서 이러한 정보를 DTO에 맞게 로직으로 풀어주는 방식으로 리팩토링 하였다.
리팩토링 후 장점
이렇게 하니 repository가 DTO에 종속 되지 않아 다른 API를 만들때 해당 쿼리를 재사용도 할수 있어서 좋았다.
두번째 리팩토링
상세페이지의 정보들을 한방쿼리로 다 가져왔다가 컴포넌트 단위로 API를 쪼개었다
리팩토링 이유
난 한방쿼리로 모든 정보를 가져오면 네트워크를 덜 타서 성능상 좋을것 같았다. 하지만 Join이 덕지덕지 붙어 있는것을 보고 무언가 잘못됨을 느꼈다.
1. DTO가 변경 될때도 저 복잡한 DTO를 손봐야 했기 때문에 유지 보수 하기가 어려웠다.
2. 내가 만든 Join이 덕지덕지 붙은 쿼리는 상세페이지를 불러올때 말고는 사용할 일이 없었다.
3. 조인이 많이 걸리면 그것도 그만큼 DB에 부하를 주었다.
'기술적 고민 > Side Match' 카테고리의 다른 글
[SW마에스트로] 팀원-팀원 상호 평가 API를 만들면서 하는 고민 (0) | 2023.09.12 |
---|---|
[SW마에스트로] 프로젝트 중 설계한 예외 처리 아키텍쳐 (0) | 2023.08.29 |
[SW마에스트로] 프로젝트 삭제를 어떻게 구현해야 할까? (0) | 2023.07.28 |
[SW마에스트로] ERD 설계 중 하는 고민 (0) | 2023.07.21 |
[SW마에스트로] AWS 미리 짚어보기 - 초급 (0) | 2023.05.03 |