본문 바로가기

Client/React

wrapper로 constant 관리하기

반응형

 

레거시 프로젝트 루트에 config.json 파일을 두고 api로 호출해서 사용

> 추후 값이 추가되거나, 변경 될 경우 json 파일만 수정해서 배포할 수 있도록 하려는 의도

> 플랫폼 별로 프로젝트 서버가 따로 돌아가고 있는데, 동일한 값을 사용하고 있었기 때문에 데이터 변경 시 모든 파일을 수정해야 하는 상황, 한 벌로 관리하고 싶었음

 

문제점

> 관리가 제대로 안됨, 결국 프로젝트마다 별개의 config 파일을 사용하고 있었음

> key 하드코딩을 제거하기 위해 별도의 constant를 새로 정의해서 추가적인 관리 비용이 발생됨

 

레거시 데이터 예시

// config.json
{
  "SOME_CODE": {
    "01": "Title 01",
    "02": "Title 02",
    ...
  },

  "SOME_TYPE": {
    "A": {
      "FULL_NAME": "Apple",
      "FULL_NAME_KO": "사과",
      "ABBR_KO": "사"
    },
    "B": {
      "FULL_NAME": "Banana",
      "FULL_NAME_KO": "바나나",
      "ABBR_KO": "바"
    }
  },

  "SOME_OTHER": {
    "Some data": "something",
    ...
  }
}
// prj_constants.js
const C_SOME_CODE = Object.freeze({
    ABC: "01",
    DEF: "02",
    ...
});

 

micro frontend 기법을 활용해 서비스 마이그레이션을 진행하며 기존 js+vue 프로젝트를 react18+ts 로 변경했으니 constant 데이터 관리도 개선해보고자 한다.

우선, 초반에는 기존 vue 프로젝트에서 사용하던 config 파일을 그대로 사용하려 했으나, 위에서 작성한 것과 같이 기존 구조에서 얻을 수 있는 장점이 없기에, json 파일을 api 형태로 호출하는 방식은 버리고 constant 파일 구조부터 변경했다.

프로젝트 내부에 기존 constant 데이터를 관리하되, 이후 모노레포 방식으로 관리할 수 있도록 코드 내에서 직접 사용하는게 아닌, wrapper 를 거쳐서 사용하도록 한다.

프로젝트에서 해당 데이터를 list 방식으로 출력에 사용하기도 하고(많은 화면에서), code(key)를 활용해 title 을 노출하는 등의 사용성이 많아 모노레포 방식이 아니더라도 wrapper 를 생성해 관리하는 것이 유지보수 등에 유리할 것으로 판단했다.

 

우선 config.json 파일 형식부터 바꿔서 관리했다. (일단 네이밍도 config 데이터가 아니었기에 파일명부터 변경했다)

// constants.ts
const SOME_CODE = {
    TITLEA: { code: "01", title: "title 01" },
    OTHERTITLE: { code: "02", title: "title 02" },
    ...
} as const;

이후 wrapper 파일을 생성한다

// wrapper.ts
type KeyOf<T> = keyof T;
type ValueOf<T> = T[keyof T];

const createWrapper = <T extends Record<string, unknown>>(constant: T) => {
    type TKey = KeyOf<T>;
    type TValue = ValueOf<T>;

    return {
        raw: constant,

        keys: Object.keys(constant) as TKey[],

        values: Object.values(constant) as TValue[],

        entries: Object.entries(constant).sort() as [TKey, TValue][],

        get: (key: TKey) => constant[key] as TValue
    }
}

const SomeCode = createWrapper(SOME_CODE);

이 방식으로 wrapper를 만들면, wrapper 호출 시점의 constant 구조가 자동으로 타입화 되기 때문에 타입 에러가 날 일도, key를 일일이 하드코딩 해야 할 일도 없다. (get 함수를 통해 데이터를 추출할 때에는 key를 직접 작성해야 하긴 하지만, key 또한 타입화 되어있기 때문에 자동완성 지원 & 잘못된 데이터가 들어갈 일 없음)

 

이후 실제 사용하는 곳에서는 

wrapper 의 SomeCode 를 import 해서 사용하면 되고, constant 파일을 모노레포로 관리하게 될 경우, wrapper의 import 경로만 변경하면 되니 이후의 유지보수도 용이해진다.

초반에는 config 데이터를 vue에서 props로 받는 형태를 사용하다가, api 등 react app 외부에서 사용할 수 없다는 이슈로 configStore로 관리를 하고 있었는데, 이렇게 개선하니 프로젝트 내부의 사용성도 개선되고 ts파일로 작성되니 app 외부에서도 사용할 수 있게 된 것이 아주 만족스럽다.

 

글 쓰기 귀찮아서 그냥 아무렇게나 후려갈겼는데 언제 정리를 하게 될런지 모르겠다

반응형