Open AI사가 개발한
ChatGPT
로 세간이 떠들썩하다. 무료로 사용할 수 있다는 소식을 듣고 얼마나 똑똑한지 시험해보기로 했다. 무엇을 시도해보면 좋을까 고민하다가 code review를 요청해보기로 했다.
ChatGPT를 직접 사용해보시려면 여기를 클릭하세요.
httpclient 라이브러리를 사용하여 API 요청을 보내고 응답을 받아오는 http 통신 메서드이다.
핵심 리뷰 내용을 하나씩 뜯어보자.
CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
try {
...
finally {
if (null != closeableHttpClient) {
try {
closeableHttpClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
try (CloseableHttpClient closeableHttpClient = httpClientBuilder.build(){
....
try statement
는 close 메소드를 자동 실행해주는 명령어이다. close를 필요로 하는 Statement class의 인스턴스나 Stream 타입의 클래스 들이 작업 완료 후에 수행해야 하는 close() 메소드를 자동을 수행해주기 때문에 굳이 나눠 작성할 필요가 없다.
내 코드는 try문 시작 전 CloseableHttpClient
인스턴스를 생성하고 finally문에서 조건 확인 후 다시 close를 해주었기 때문에 try, if, finally이 중첩되어 가독성이 나빴다. 개선된 코드에선 동일 로직을 1줄로 처리할 수 있었다.
HttpPost httpPost = new HttpPost(requestUrl);
try {
...
try (CloseableHttpClient closeableHttpClient = httpClientBuilder.build(){
HttpPost httpPost = new HttpPost(requestUrl);
HttpPost
는 post 방식으로 전송하기 위해 url, config, entity 등의 정보를 담는 역할을 수행하며, 실제 post 통신 작업은 CloseableHttpClient
의 인스턴스를 통해 이루어진다. 따라서 CloseableHttpClient
인스턴스 생성이 보장되기 전에 HttpPost
인스턴스를 생성할 필요가 없다.
개선된 코드에선 CloseableHttpClient
인스턴스가 정상적으로 생성된 상황에서 HttpPost
인스턴스를 생성하므로, 행여 CloseableHttpClient
인스턴스가 정상적으로 build되지 않은 상황에서 메모리가 낭비될 가능성을 줄였다.
HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
String resData = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
return objectMapper.readValue(resData, responseType);
HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
String resData = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
return objectMapper.readValue(resData, responseType);
} else {
logger.error("Failed to call post, status code: " + statusCode);
throw new ServiceException("API_RESPONSE_ERROR", "API call failed. Please contact the administrator.", null);
}
HttpResponse
는 execute()
로 수행한 요청에 대한 응답 결과를 담는 역할을 수행한다. 이 때 getEntity()
로 실제 data를 읽기 전 getStatusCode()
로 송신한 요청에 대한 statusCode를 먼저 확인하는 것이 올바른 순서다. chatGPT가 개선한 코드는 성공인 경우(200~299)에만 getEntity()를 수행하도록 하였다.
사실 개발 당시 statusCode를 분리할 생각을 못했던 것은 아니었다. 하지만 API를 제공하는 업체가 어떠한 경우에도 200 code를 전달하는 식으로 개발을 해놓은 상태라 굳이 안해도 되겠다고 판단하였다. 하지만 정석은 이러하니 statusCode에 따라 Exception 처리를 하는 습관을 들이는 것이 좋다는 생각이 든다.
(참고) HTTP response status codes
의미 | code 범위 |
---|---|
Informational responses | 100 - 199 |
Successful reponses | 200 - 299 |
Redirection messages | 300 - 399 |
Client error responses | 400 - 499 |
Server error responses | 500 - 599 |
public <E, T> T callPost(String protocol, String serverHost, String blockChainServerDetailUrl, E requestParam, Class<T> responseType) {
String blockChainServerBaseUrl = String.format("%s://%s", protocol, serverHost);
String requestUrl = blockChainServerBaseUrl + blockChainServerDetailUrl;
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(1 * 10000).setConnectTimeout(1 * 10000).setConnectionRequestTimeout(1 * 10000).build();
try (CloseableHttpClient closeableHttpClient = httpClientBuilder.build()) {
HttpPost httpPost = new HttpPost(requestUrl);
httpPost.setConfig(requestConfig);
String msg = objectMapper.writeValueAsString(requestParam);
logger.info(msg);
StringEntity entity = new StringEntity(msg, "UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
String resData = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
return objectMapper.readValue(resData, responseType);
} else {
logger.error("Failed to call post, status code: " + statusCode);
throw new ServiceException("API_RESPONSE_ERROR", "API call failed. Please contact the administrator.", null);
}
} catch (Exception e) {
logger.error("Failed to call post, error: " + e.getMessage());
throw new ServiceException("API_RESPONSE_ERROR", "API call failed. Please contact the administrator.", e);
}
}
CloseableHttpClient
is automatically closed, even in case of an exception.ServiceException
.ServiceException
now includes the original exception in its constructor, so that additional debugging information can be obtained if needed.우리 회사는 코드 리뷰 문화가 정착되지 않아서 주니어가 리뷰를 받기가 어려운데, chatGPT를 이용하면 손쉽게 유의미한 수준의 리뷰를 얻을 수 있을 것 같아 기쁘다! 리뷰 내용을 참고해서 차주 리팩토링을 해볼 생각이다.
이 정도 수준이라면 다음엔 좀 더 복잡한 코드로 리뷰를 요청해도 괜찮을 것 같다. 이 글을 보신 분들도 한 번 사용해보시길~!
ChatGPT를 직접 사용해보시려면 여기를 클릭하세요.
References