위의 JSON을 클래스로 바인딩시킬 DTO 클래스를 생성해서 API에 대한 Request, Response를 관리하는 것이 바람직합니다. 간혹 Map, JSON(gsoon, jackson) 등을 이용해서 유연하게 두는 예도 있지만 저는 개인적으로 권장하지 않습니다. 가장 큰 이유는 해당 값에 무슨 데이터가 있는지 확인하기 어렵습니다. 코드 가독성이 심각하게 떨어지며 정확히 어떤 자료형인지 확인하기도 어렵습니다. 또 @JsonProperty를 통해서 해당 실제 JSON 키값과 객체의 멤버 필드 값을 다르게 설정 할 수 있습니다.
Setter를 사용하지 않기
이전 포스팅에서도 Setter 사용하지 않기를 언급한 적이 있습니다. Response DTO 클래스 같은 경우는 더욱 Setter를 제공할 필요가 없지만, 관습적으로 Setter 메서드를 추가하는 경우가 많습니다. 해당 객체를 어디서든지 변경이 가능한 객체가 되기 때문에 명확한 이유 없이 관습적인 Setter는 반드시 지양 해야 합니다.
반면 Request 객체는 필요한 값을 바인딩시켜 보내줘야 합니다. 이러한 경우는 Builder 패턴을 이용해서 객체를 생성하면 많은 장점이 있습니다. 제가 느끼는 대표적인 장점들 아래와 같습니다.
객체의 멤버필드를 수정 할 수 있는 수정 메소드를 제공 해주면 됩니다. 단순하게 setter라는 네이밍으로 공개하는 것보다 해당 메소드의 기능을 잘 표현하는 네이밍을 갖는 것이 적합합니다. 더 구체적인 내용은 이전 포스팅 Settet 사용하지 않기에 정리 되어 있습니다.
String으로 관리할 경우 해당 값 이외의 입력에 대한 예외코드를 작성하면 런타임시에 발생하게 됩니다. enum 클래스로 관리했을 경우 개발자는 해당 enum 값이 외에는 값을 넣을 수도 없게끔 강제하는 것이 실수를 줄이는 방법입니다. String은 변경 및 유지 보수에 취약합니다. 이처럼 API에서 강제된 항목들은 enum 클래스로 관리하는 것이 바람직합니다.
publicvoidsendErrorMessage(){ // 적절한 Error Message를 가공하는 책임 // 해당 메소드의 변경시 이유는 Error Message의 변경시에만 변경 이유를 갖는다 final PagerDutyDto.Request request = buildErrorMessage(); send(request); }
publicvoidsendInfoMessage(){ // 적절한 Info Message를 가공하는 책임 // 해당 메소드의 변경시 이유는 Info Message의 변경시에만 변경 이유를 갖는다 final PagerDutyDto.Request request = buildInfoMessage(); send(request); }
private PagerDutyDto.Response send(final PagerDutyDto.Request request){ // 넘겨 받은 request를 PagerDuty 에게 보내는 책임 // 해당 메소드의 변경시 이유는 PagerDuty API 변경시만 변경 이유를 갖는다. -> Request, Response 변경이 대표적인 예 try { final String url = "https://events.pagerduty.com/v2/enqueue"; return restTemplate.postForObject(url, request, PagerDutyDto.Response.class); } catch (HttpClientErrorException e) { log.error(e.getResponseBodyAsString(), e); thrownew RuntimeException(e); } }
클린 코드 출처
작게 만들어라!
함수를 만드는 첫 번째 규칙은 '작게!'다. 함수를 만드는 둘째 규칙은 '더 작게!'다. …중략 한 가지만 해라!
함수는 한 가지를 해야 한다. 그 한 가지를 잘해야 한다. 그 한 가지만을 해야 한다. … 중략
클린 코드에서 언급했듯이 함수의 기본단위는 정말 작아야 한다고 생각합니다. 그래야 재사용성이 높아지며 가독성, 유지보수에 좋은 코드가 된다고 생각합니다.
sendErrorMessage() 메소드는 적절하게 Error Message를 만들어서 send 메소드에게 전달해주는 것이 그 함수가 하는 일입니다. 함수의 크기가 작으며 적은 일을 수행하고 있습니다.
send() 메소드도 넘겨받은 request값을 PagerDutry API 에게 요청하고 그에 따른 응답값을 받는 일만 합니다. 그렇게 된 결과 sendInfoMessage() 메서드에서도 재사용성이 높아지고, 해당 함수가 하는 일이 단순해져서 가독성이 높아집니다. 또 위에서도 언급했듯이 PagerDuty API 변경시에만 해당 메소드가 변경됩니다. 그런 결과 유지 보수하기 편한 이점이 있다고 생각합니다.