티스토리 뷰

728x90
SMALL

배경

과거 객체지향 강의에서 추상화, 카테고라이즈에 대해 배웠다. 그런데 나는 이런 것들을 실제로 사용하고 있는걸까? 하는 의문점들이 조금씩 들던와중에 실무에 적용할일이 생겼다.

 

배경 설명

- Foo라는 enum이 존재한다.

- enum이 자주 추가되지는 않지만 계속해서 추가되는건 확실하다.

- 프론트엔드, 백엔드 모두에서 전역적으로 사용된다.

- 경우에 따라 특정 enum 값만 허용되어야 한다.

- input이 전체 enum인데 outpt은 특정 enum으로 필터링해야한다.

- enum에 매핑되는 value가 존재하는 경우가 있다.

- enum이 추가될 때마다 전체 시스템을 점검해야하므로, 많은 시간이 소요된다.

 

고민

나는 Foo enum을 추가해야하는 요구사항을 받았다. 또한 기존과는 약간 다른 타입의 enum이였다.

작업하는건 그냥 노가다성으로 할 수 있지만 그 다음에 같은 요구사항을 받았을 때 개선되는게 없었다. 그래서 작업을 잠시 멈추고 객체지향, 추상화에 대해 생각했다.

 

요구사항을 분석해보니 enum을 몇가지 타입으로 나눌 수 있다는 것을 깨달았다.

미래의 요구사항까지 고려해 적당한 카테고리를 찾았고 이를 팀에 공유했다.

 

ex)

type ExtractValue<T> = T[keyof T];

// 특정 카테고리에 속하는 Foo Enum만을 모아둠
export declare const FOO_1: {
    readonly bar1: FOO.bar1;
    readonly bar2: FOO.bar2;
};
export type FOO_1 = ExtractValue<typeof FOO_1>;

// 위와 유사하게 타입 생성

 

예상 질문. 요구사항이 복잡해서 위 타입에 하나씩 넣어주는게 어렵게되면 어떻게 해야할까요??

- 여러 속성을 정의하고 스크립트를 돌려서 codegen으로 type을 생성하면 될 것 같네요.

- 근데 이정도로 복잡한 요구사항은 최대한 쉬운 정책으로 풀어야하지 않나.. 생각이 드네요..

import fs from 'fs';
import path from 'path';

enum FOO {
  bar1 = 'bar1',
  bar2 = 'bar2',
}

interface FooAttribute {
  value: FOO;
  isA: boolean;
  isB: boolean;
  isC: boolean;
  bar: 'chicken' | 'pizza';
}

// FOO Enum 값을 기준으로 FooAttribute를 매핑
const fooRecord: Record<keyof typeof FOO, FooAttribute> = {
  bar1: {
    value: FOO.bar1,
    isA: true,
    isB: false,
    isC: false,
    bar: 'chicken',
  },
  bar2: {
    value: FOO.bar2,
    isA: true,
    isB: false,
    isC: true,
    bar: 'chicken',
  },
};

// 조건을 만족하는 FOO_1 객체 생성
const filteredFoo1 = Object.entries(fooRecord).filter(([key, value]) => value.isA && value.bar === 'chicken');

// TypeScript 코드로 변환
const output = `
import { FOO } from '@/foo'

type ExtractValue<T> = T[keyof T];

// 자동 생성된 코드
export declare const FOO_1: {
  ${filteredFoo1.map(([key, value]) => `readonly ${key}: FOO.${key},`).join('\n  ')}
};
export type FOO_1 = ExtractValue<typeof FOO_1>;
`;

// 파일 저장
const filePath = path.join(__dirname, 'foo.ts');
fs.writeFileSync(filePath, output.trim());

console.log(`foo.ts 생성 완료: ${filePath}`);

 

팀에 공유하기

시스템을 만들어났지만 팀이 사용하지 않으면 무용지물이다. 기존의 문제점, 개선한 방법, 실제로 개선된 시스템을 사용하는 방법, 장점 등을 문서로 정리해서 공유해야한다.

또한 위 시스템이 모든 팀원에게 익숙해지기 전까지는 적극적으로 리뷰를 해야한다. 한 번 공유했다고 모두가 100% 이해하고 기억하기는 어렵다.

 

후기

enum이 추가될 때 위 타입에 추가를 한 뒤 ci를 돌리면 웹, 앱, 백엔드 모든 파트에서 변경되어야하는 부분을 찾을 수 있게 되었다.

이 enum은 굉장히 많이 사용되는 enum이기 때문에 시간 비용으로만 따져봐도 꽤 큰 성과라고 생각한다.

다음에는 기회가 된다면 모델링에 대한 글을 써볼까한다.

728x90
LIST
댓글
공지사항