이번에 mybatis 기반으로 구축 된 Legacy Project를 보게 되면서 정리하고 싶은 내용이 생겨 기록하고자 한다.
코드를 살펴보니.. 서버 내 각 계층에서 데이터의 전달 대부분이 Map으로 전달되고 있었다. 내가 처음 Spring과 Mybatis를 학습했을 땐 대부분 DTO를 이용하여 데이터를 전달하였던 기억이 나서 조금 의아했다. 일단 개인적인 의견으로는 Map을 사용하는것보단 DTO를 사용하는게 더 맞지않나 라는 생각이 들어 DTO를 사용해야 하는 이유를 중심으로 써보고자 한다.
첫번째 방법은 세가지 데이터를 담을 수 있는 DTO 객체를 이용하는것이다.
Member member = new Member();
member.setEmail(email);
member.setPassword(password);
member.setName(name);
두번째 방법은 Map을 이용하는 것이다.
Map<String, Object> memberMap = new HashMap<>();
memberMap.put("email", email);
memberMap.put("password", password);
memberMap.put("name", name);
meber를 던져주든, memberMap을 던져주든 원하는 데이터는 꺼내서 사용할 수 있기 때문에 두가지 방법 다 문제를 해결할 수 있다. 그러나 Map을 사용했을 때 단점을 얘기해보자면
소스를 분석하다보면 이 부분에서 어떤 데이터가 전달되고 있는지, 어떤 데이터를 담고 있는지 계속해서 추적하게 된다, DTO의 경우엔 내부에 필드를 갖고 있기 때문에 "이런 데이터를 갖고있겠구나" 하는 예상이 된다. 하지만 Map은 코드를 분석하지 않고서는 예상이 어렵다. 물론 메소드명이나 역할, 또는 위처럼 memberMap과 같은 변수의 이름을 보고 대략적으로 추측이 가능하지만, 담아야할 데이터가 많으면 많을수록 DTO 객체를 사용하는것보다 직관성이 떨어진다.
member.getEmall(); // 컴파일 에러
mamberMap.get("emall"); // 에러 X
오타가 있는 두줄의 코드이다. DTO 객체를 사용할 경우 컴파일 에러가 나겠지만, Map 객체를 사용할 경우 컴파일 단계에서 에러가 나지 않는다. 애초에 VO를 사용하는 코드의 경우 IDE에서 자동완성을 지원하므로 위와 같은 실수를 할 확률이 거의 없을뿐더러, 메소드명을 전부 타이핑하다가 실수가 나더라도 바로 알 수 있다. Map의 경우 로직과 관련된 부분도 아닌 이런 사소한 오타때문에 코드의 안정성이 떨어지고 개발 생산성을 떨어뜨릴 수 있다.
DTO 객체의 경우 필드의 타입이 이미 정의되있으나, Map의 경우엔 어떤 타입의 데이터를 담을지 알 수 없다. 그래서 상단의 코드를 살펴보면, key는 String, value는 Object 타입으로 정의한것을 알 수 있다. 즉, 데이터를 꺼내서 사용해야 하는 경우 Map은 계속해서 타입캐스팅이 필요하다.
String email = (String) mamberMap.get("email");
int age = (int) mamberMap.get("age");
위와 같이 반복적인 타입캐스팅은 그에 따른 비용이 발생하며, 코드 곳곳에서 보이는 캐스팅과 관련 된 코드가 가독성을 떨어뜨린다.
여기까지 DTO객체를 사용했을 때의 장점에 대해 알아보았다.
하지만 이럼에도 불구하고 Map 객체를 사용하는 이유 역시 있을것이다.
예를 들어, 현재 필요한 데이터를 하나의 DTO에 담을 수가 없고 여러 DTO에 나눠서 담아야 하는 경우에는 각각의 VO에 담아서 전부 전달하기 어렵기 때문에, Map에 필요한 데이터만 담아서 전달하는것이다.
그러나, 이런 경우에도 Map을 사용하는것보단 필요한 데이터만 담을 수 있는 별도의 DTO 객체를 만들어하여 그 객체를 데이터를 담는 그릇(?)으로 사용하는 것이 더 좋지 않을까 라고 생각한다.
이론적으로 데이터를 전달하기 위해서는 Map보단 DTO를 사용하는것이 여러모로 장점이 많다. 그러나 실무를 하다보면 상황에 따라 Map을 사용하는 것이 더 편한 상황이 있다. 물론 위에 언급한 것처럼 그런 경우도 용도에 맞는 DTO 객체를 따로 두는게 좋지 않나.. 라고 생각은 하지만, 그렇게 되는 경우 또 너무나 많은 DTO 객체를 관리해야될 수도 있기 때문에 결국 상황에 따라 유연하게 사용하는것이 좋을것같다.