[Spring] Java Enum 활용하기 (Enum Code API)

Cho-D-YoungRae·2022년 8월 30일
0

해당 글은 세부 개발에 대한 내용보다는 제가 고민하고 결론에 도달했던 과정에 대해서 쓰여져 있습니다. 세부 개발 관련된 내용은 참고에 첨부해둔 링크와 제가 이후에 사용하기 위해 만들어둔 깃허브 코드를 확인해주시면 좋을 것 같습니다.

상황1 (코드테이블)

프로젝트 초반 논의에서 위 이미지와 같이 상수값들을 code 테이블을 통해서 관리하려고 했습니다. 그러나 이러한 형태로 상수값을 사용하게 되면 여러가지 단점들이 존재했습니다.

  • 컴파일 에러 불가능
  • 코드를 조회하기 위해 DB 접근 증가 (+조인도 발생)
  • 관리해야할 테이블 증가

조금만 생각하고 찾아봐도 많은 단점들이 있었습니다. 그래서 코드 테이블을 사용하지 않고 상수 값들을 모두 enum으로 관리하기로 하였습니다. 이렇게함으로써 인텔리제이같은 IDE의 지원도 받을 수 있게 되었으며, 코드 테이블을 사용할 때의 단점을 모두 극복하고 enum의 장점을 적극 활용할 수 있습니다.

상황1 해결 & 상황2 (Enum)

이렇게 상수를 모두 enum으로 사용하였지만 아직 불편한 점이 남아있었는데요. 위 두 이미지 중 아래 이미지는 특정 요청에 대한 응답 JSON을 나타낸 것인데, 보이시는 것과 같이 상수값만 반환해주다 보니 위 이미지 enum의 주석에서와 같이 뷰에서 보여지는 값을 위해서 프론트에서도 이 상수들을 관리해주어야 했습니다.

상황2 해결 (Enum Code API)

프론트에서도 상수를 관리해주어야 했던 상황2를 해결하기 위해서 위 이미지와 같이 사용되는 enum이 코드(code)와 뷰에서 보여지는 값(title)을 반환하도록 인터페이스(EnumMapperType)를 구현하도록 하고 enum을 조회할 수 있는 API를 개발해서 프론트에서도 상수를 관리하지 않고도 뷰에서 보이는 값을 사용할 수 있도록 하였습니다.

고민 후 적용하지 않은 방법

상황2에 대한 고민을 시작했을 때는 이미 프로젝트가 어느정도 진행된 상태였습니다. 그렇기 때문에 더욱이 새로운 방법의 도입은 신중해야했습니다. 그래서 아래 두가지를 가장 염두에 두었습니다.

  1. 코드 전반에 영향이 적도록
  2. 새로운 규칙이 발생하지 않도록

아래의 고민 후 적용하지 않은 방법들은 위에 부합하지 않다고 생각하여 적용하지 않게 되었습니다. 실제 저의 구현과 비교해보시려면 가장 상단에 제가 걸어둔 깃허브 링크를 통해 확인해주시면 감사드리겠습니다.

제가 사용한 방식은 API 자체를 분리한 방법이라 Response에서는 뷰에서 보여지는 값이 포함되지 않고 이를 조회하기 위해 API 호출이 한번 더 발생하게 됩니다. 이렇게 하면 API 호출은 더 잦아지지만 코드 전반에 수정은 최대한 적게 도입이 가능했습니다. 만약 Response 에 뷰에서 보여지는 값을 포함시키는 방법을 사용했다면 테스트와 RestDocs(API 문서)에 많은 수정이 발생했을 것 입니다.

먼저 말씀을 드리면 아래의 고민 후 적용하지 않은 방법들은 모두 Response 에 뷰에서 보여지는 값을 포함시키는 방법이고 이것이 적용하지 않은 이유 중 하나입니다.

또한 API 가 리소스에 관련된 데이터만을 반환시켜주도록 하고 싶었는데 뷰에서 보여지는 값이 포함되어도 괜찮은 것인지에 대한 고민도 있었습니다.

// Response에 뷰에서 보여지는 값 포함 X -> Code 조회 API 분리하는 방법
{
	"field" : "AD_MARKETING",
  	"fieldCategory" : "CONTEST"
}
// Response에 뷰에서 보여지는 값 포함 O -> Code 조회 API 안 하는 방법
{
	"field" : {
      "code" : "AD_MARKETING",
      "title" : "광고/마케팅"
    },
  	"fieldCategory" : {
      "code" :   "CONTEST",
      "title" : "공모전"
    }
}

@JsonFormat(shape = JsonFormat.Shape.OBJECT)

제가 위에서 code, title 을 반환하는 메서드를 구현하도록 인터페이스(EnumMapperType)를 사용했습니다. 여기서 이 인터페이스에 @JsonFormat(shape = JsonFormat.Shape.OBJECT) 를 붙여주면 EnumMapperType 을 구현한 enum 이 Response에 포함되면 뷰에서 보여지는 값을 포함하는 형태로 표현됩니다.

그러나 이 방법을 사용하게 되면 테스트에서 Request 에 대한 값을 변환할 때도 뷰에서 보여지는 값을 포함하는 형태인 { code, title } 형태로 변환하게 되고 저는 RestDocs를 API 문서로 사용하고 있어서 Request 의 형태가 이렇게 변환된 형태로 문서에 까지 반영될 수 있는데 이것은 제가 의도한 형태가 아니기 때문에 이 방법을 사용하지 않기로 했습니다.

ObjectMapper 커스터마이징

ObjectMapper 를 커스터마이징해서 @JsonFormat 를 사용하지 않고 EnumMapperType 을 구현한 enum 을 뷰에서 보여지는 값을 포함하는 형태인 { code, title } 과 같은 형태로 변환시킬 수 있습니다. 그러나 이 방법도 위 @JsonFormat 를 사용한 방법과 동일하게 테스트의 Request 에 대한 변환에도 영향을 미치게 됩니다.

그래서 테스트에서 Request 를 변환할 때는 새로운 ObjectMapper 를 생성하는 등의 방법으로 커스터마이징이 적용되지 않은 ObjectMapper를 사용하는 형태를 생각해볼 수 있습니다. 그러나 이 방법을 사용하면 Request를 ObjectMapper 로 변환하는 테스트들에 모두 적용해야해서 많은 수정이 발생할 수 있으며 새로운 테스트에서도 Request를 변환할 때는 커스터마이징되지 않은 ObjectMapper를 사용해야된다는 규칙이 발생하게 됩니다. 이것들은 제가 피하고 싶었던 상황이었고 그래서 이 방법을 선택하지 않게 되었습니다.

남은 고민

참고한 링크들 덕분에 최대한 서버에 부담이 가지 않도록 구현하였다고 생각합니다. 그럼에도 'API가 분리되어서 서버에 호출이 많아지는 것이 괜찮은가', 'Response에 뷰에서 보여지는 값을 포함시켜 주는 것이 좋은 방법인가' 라는 고민이 완전히 해결되지는 않은 것 같습니다.

좀 더 많은 경험을 해보며 이에 대한 고민을 해결해야겠습니다.

참고

0개의 댓글