[글의 의도]
1월 30일, 야놀자 패캠 부트캠프를 수료했다. 취업 준비를 하면서 블로그 글을 쓰기 위해 주제를 고민하던 중 최근 파이널 프로젝트에서 많이 사용했고, 개인 프로젝트에서 한번 더 고민한 DTO에 대해 글을 쓰려고 한다.
[DTO의 형태]
파이널 프로젝트는 FE + BE가 함께 진행하며 개발을 했으므로 나는 API Server만 개발을 했다. 따라서 FE로 어떤 값을 어떻게 보내야 편하게 사용할 수 있을지 고민을 팀원들과 했었다. 그 중 고민이 되었던게 DTO의 형태였다. 값을 어떻게 내려보낼지 고민하기 전에 DTO의 이름도 관련이 있으니 먼저 살펴보자
[ 자연스럽게 사용하게 된 DTO의 네이밍 ]
미니 프로젝트, 토이 프로젝트를 진행하면서 팀원분들의 코드로 어깨 넘어 배운 DTO 명명법은 어미에 --Response를 붙이는 형식이었다. 아마 --DTO라고 대문짝만하게 안 붙여도 현업에서는 다 DTO임을 알고 사용한다고 그랬던 것 같다. 그렇게 나도 사용을 하고있었다.
[ List<DTO> vs 단일 객체 DTO]
파이널 프로젝트 진행 중, 코드 리뷰를 진행하면서 한 팀원 분의 DTO가 나와 다른 형태임을 발견했다. 다음 상황을 살펴보자
- Controller에서 전체 게시글 조회 요청에 대한 응답을 주는 상황
public record PostsResponse(
String title,
String content,
String author
){
}
public List<PostsResponse> getPosts(){
}
보통 List 형식의 응답을 내릴 때 나는 위와 같은 방식으로 record를 작성 했던 것 같다. 하지만 팀원분은 List로 담아서 내리면 PostsResponse를 여러 개 응답한다는 느낌을 받아서 아래와 같은 형식으로 사용하셨다.
public record PostsResponse(
List<Post> postList
){
private record Post(
String title,
String content,
String author
){
}
}
public PostsResponse getPosts(){
}
두 방식의 큰 차이는 내부 클래스(record)를 사용하냐 VS 안하냐의 차이인 것 같다. 어떤 것이 더 나은 방향인지 미리 말하자면 2번째 방식이 더 나을 것이다. 이유를 알아보자.
[ 가독성 VS 확장성 ]
첫 번째 방법의 경우 장점은 가독성이라고 말할 수 있을 것 같다. 보통 다른 사람이 작성한 메서드를 볼 때 메서드 이름과, 반환 타입, 매개 변수 등 여러가지 요소를 고려하여 해당 메서드의 역할을 유추할 수 있다. 위 코드의 예시처럼 반환 타입을 List로 주게 되면 해당 기능은 여러 개를 응답한다고 직관적으로 유추할 수 있을 것 같다. 만약 Response만 딸랑 반환하게 되면 해당 Response를 직접 들어가서 봐야하는 조그만 수고가 있을 수 있다고 생각한다. 단점은 두 번째 방법의 특징을 나열하면서 알아보자.
두 번째 방법의 경우, 장점은 확장성이 열려있다는 점이다. 위 상황의 경우에는 Post 게시글 하나 만 응답을 주고 있다. 현재 상황에서는 문제가 없어보인다. 하지만 게시글로 끝나는 것이 아닌, 댓글, 태그, 이미지 등 추가적인 정보에 대한 확장이 열려있다. 두 번째 방법의 경우에는 간단하게 내부 레코드에 필드만 추가해주면 쉽게 확장이 가능하다. 반면에 첫 번째 방법의 경우 여러 부분의 수정을 피할 수 없을 것이다.
일반적으로 봤을 땐 특별한 상황이 아니라면 두 번째 방법이 좋아보이긴 한다. 하지만 첫 번째 방법을 사용하면, 게시글을 독립적으로 사용할 때 유용할 수 있다. 독립적으로 사용할 때 유용한 사항은 아래와 같다. (Chat GPT 참조)
개별 처리 필요: 클라이언트에서 게시글을 개별적으로 처리해야 하는 경우입니다.
예를 들어, 클라이언트가 각 게시글을 독립적으로 화면에 표시하거나,
각 게시글에 대해 별도의 연산을 수행해야 하는 경우
각 게시글을 독립적인 객체로 다루는 것이 유리합니다.
독립적인 데이터 변경: 게시글이 독립적으로 추가, 삭제, 수정되는 경우입니다.
각 게시글이 독립적인 객체로 관리되면, 특정 게시글에 대한 변경 사항만을 쉽게 반영할 수 있습니다.
세부 정보 요구: 각 게시글에 대한 세부 정보를 요구하는 경우입니다.
예를 들어, 게시글의 작성자, 작성 시간, 조회 수 등 추가 정보를 필요로 하는 경우,
이런 정보를 각 게시글 객체에 포함시킬 수 있습니다.
비동기 처리: 클라이언트가 비동기적으로 각 게시글을 처리해야 하는 경우입니다.
예를 들어, 웹 페이지에서 스크롤을 내릴 때마다 게시글을 하나씩 불러오는 '무한 스크롤' 기능을 구현하는 경우,
각 게시글을 독립적인 객체로 다루는 것이 효율적입니다.
[느낀 점]
멘토님이 말씀해주신 `진리의 회바회 팀바팀 사바사` 가 떠오르는 부분인 것 같다. 클라이언트 요청에 따라 정하자.
개발에는 정답이 없다. 아무리 잘나가는 기술이라도, 내게 주어진 환경에 맞지 않다면 필요가 없을 것이다. 코드를 작성하거나 기술을 사용할 때, 왜 필요한지 다른 방안은 없는지, 방안이 여러 개라면, 이들의 차이가 무엇인지 다시 생각해보는 습관을 가져보자.