안녕하세요, 도토리입니다.
잘못된 정보가 있거나 오류가 있으면 언제든지 댓글로 이야기 해주세요!! 😅
회사에서 이미 운영중인 시스템에 Open API를 만드는 일을 맡게되어서 기존 소스를 조금씩 리펙토링하면서 API 서버를 만들고있다..
개발하면서 공통코드를 어떻게하면 효율적으로 불러서 쓸 수 있을까 라는 문제에 직면하고 나름? 칭찬받으면서 해결한 부분이 있어서 공유하고자 한다!
공통코드가 어떻게 생겼을까?
이 시스템에는 모든 코드가 다 G로 시작하는 Gcode로 되어 있었다.
예를들어 USD / 달러 라는 우리가 통상적으로 미국달러를 USD라는 코드로 부른다. 그리고 찾아봤는데 ISO에 등재된 국제 표준으로써 USD 또한 공통 코드값이다.
하지만.. 이 시스템에서는 USD / 달러 이것들 조차 공통 Gcode로 변환해서 DB에서 기준정보로 관리중이였다.
예를들어 코드에 대해서만 컬럼으로 표시하자면 아래와 같은 상황인 것이다.
code_id | code | code_nm |
G123123 | USD | 달러 |
G456456 | KRW | 원 |
이 외에도 모두가 다 아는 KG, CM 등의 대중적인 코드또한 Gcode로 변환되어 저장되어있었다.
물론 비즈니스적으로 사용하는 코드들도 Gcode로 저장되어서 관리되었다.
개인적으로는 DB에서 조회했을경우 한눈에 코드값을 알기 어려워 매우 마음에 들지 않는 코드이다.
어떻게 효율적으로 불러다 사용할까?
여기서부터 고민이였다.
이렇게 생긴 코드를 어떻게 불러다가 사용하지..?
1차로 생각했던것은 key값으로 매번 db를 조회해오는것이였다.
단순히 생각해도 DB I/O가 많아질테고, 당연히 하기 싫었다.
한번에 쫙 조회해와서 쓰고 싶었다.
그래서 Map 형태로 불러다가 저장해두고 쓰고 싶었다.
Map은 구조 특성상 생성할때 시간이 조금 들지만 key로 찾아오기때문에 읽어서 사용하는데는 빠르다는 장점이 있는데,
이를 활용해서 서버가 뜨면서 Map을 구성하고, 구성한 뒤에는 계속 불러다가 사용할 수 있도록 하고 싶었다.
두가지를 생각했어야했다..
1. Value가 2개 이상인 것을 Map의 형태로 어떻게 만들 것인가?
2. Cache를 안쓰고 어떻게 서버가 뜨면서 Map을 만들어두고 불러다 쓸 수 있을까?
Value가 2개 이상인 것을 어떻게 Map으로 만들까?
처음에는 Key를 Gcode로 하고 value를 그냥 List<String>해서 순서대로 code, codeNm 넣으면 되지 않을까? 라고 생각했었다.
하지만, 이렇게 하면 다음과 같은 문제들이 바로 보였다.
1. code가 0번째고, codeNm이 1번째야 라고 모두가 알고있어야함
2. 만약 어떠한 경우에서 없는 값의 index를 찾으려면 notFoundException이 떨어짐
그래서 고민하던중.. 그냥 code랑 codeNm을 가지고있는 객체를 만들어서 Map으로 만들면 안되나? 라는 생각을 하게 되었다.
정말 단순하게 Pair라는 객체를 만들고 안에 code와 CodeNm이라는 값을 가지고 있도록 만들었다.
@Getter
@Builder
@AllArgsConstructor
public class Pair {
private String code;
private String codeNm;
}
그리고 아래와 같이 commonCodeRepository에서 findAll해온 뒤에
이를 stream API를 사용해서 toMap을 해주었다
List<CommonCode> commonCodeList = commonCodeRepository.findAll();
this.codeMap = commonCodeList.stream().collect(Collectors.toMap(
k -> k.getCdId(),
v -> new Pair(v.getCd(), v.getCdNm()))
);
본인 기준으로는 처음보는 Map 형태였으나, Map을 좋아하는 사람으로써 매우 뿌듯했다.
Map<String, Pair> 라는 형태..
이렇게 Map을 관리하게 되면서 List로 value를 구성하면 걱정되던 문제들이 해결이 되었다.
1. code가 0번째고, codeNm이 1번째야 라고 모두가 알고있어야함
-> 알 필요 없이 아래와 같이 code와 codeNm을 상황에 따라 불러 쓸 수 있다.
// 일부분 발췌
public ResponseDto cancel(String countryCd, String currencyCd, Map<String, Pair> codeMap) {
// 예를들어 국가코드는 국가명을 알아야하고, 통화코드는 코드값을 알아야한다면 아래와 같이 구분해서 불러 올 수 있다.
String nationNm = codeMap.getOrDefault(cneeCountryCd, null).getCodeNm();
String currencyNm = codeMap.getOrDefault(currencyCd, null).getCode();
}
2. 만약 어떠한 경우에서 없는 값의 index를 찾으려면 IndexOutOfBoundsException이 떨어짐
-> index로 값을 조회해오지않고 위의 코드처럼 직접 get으로 가져오기때문에 IndexOutOfBoundsException은 떨어질일이 없다.
서버가 뜨면서 Map을 만들어두고 불러다 쓸 수 있을까?
요건은 2가지였다.
1. 공통코드 양이 많으니, 매번 만들지 않고 서버가 기동될때 한번만 Map을 만든다.
2. 서비스에서 호출해서 사용할때 매번 만들지 않아야한다.
이 부분에 대해서는 조금 글이 길어지기도하고, 주제를 두개로 나눠서 글을 쓰고싶어서 다음 글에서 다루겠다..!
마무리
구글링을 해봐도 이것만큼 간편하게 Key 하나에 Value 여러개로 Map을 만들어서 사용하는것이 안보여서 뭔가 뿌듯했다.
(물론 더 좋고 간단하고.. 완벽한 구조가 있을것이다..)
데이터의 양이 방대하다면 Map을 만드는데 공간복잡도가 커지는 단점이 있어서 조금 더 좋은 방법을 시간날때 찾아봐야겠다.
이 글을 보고 실제로 도움을 얻었다면... 댓글 한번씩만 부탁드립니다 ㅎㅎ
'JAVA' 카테고리의 다른 글
[Junit5] Test Code 돌릴때 Jasypt 암호화로 인해 실패할때.. (0) | 2023.09.28 |
---|---|
[JAVA] Exception을 떨어트리고 response를 custom 해보자! (0) | 2023.08.30 |
[JAVA / 해결] MapStruct(Mapper) DTO <-> Entity 자동 생성 안될때 (0) | 2023.07.12 |
[JAVA] 대량 데이터 Insert 속도 개선 관한 이야기 - 2편 (0) | 2022.11.22 |
[JAVA] 대량 데이터 Insert 속도 개선 관한 이야기 - 1편 (0) | 2022.11.20 |