회사 코드를 살펴보던 중, Enum의 각 값에 많은 정보가 함께 정의되어 있는 구조를 보게 되었습니다. 이러한 사용 방식이 과연 적절한지에 대한 고민을 하게 됐고, 이를 정리하기 위해 글을 작성하게 되었습니다.
이 글은 개인적 의견이기 때문에,
저렇게 생각할 수도 있구나정도로 이해해주시면 감사하겠습니다. 🙏🏻
1. 어떤 상황일까?
회사 코드를 보던 중, Enum 내부에 많은 값들을 가지고 있는 것을 보게 되었습니다. 아래와 같이 Enum에 비즈니스정책과 연관된 여러 값이 들어있는 것이죠.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
enum class OrderChannel(
val code: String,
val displayName: String,
val isMobile: Boolean,
val supportsCoupon: Boolean,
val supportsPoint: Boolean,
val supportsGift: Boolean,
val requiresAuthentication: Boolean,
val priority: Int
) {
WEB(
code = "WEB",
displayName = "웹",
isMobile = false,
supportsCoupon = true,
supportsPoint = true,
supportsGift = true,
requiresAuthentication = true,
priority = 1
),
APP(
code = "APP",
displayName = "모바일 앱",
isMobile = true,
supportsCoupon = true,
supportsPoint = true,
supportsGift = true,
requiresAuthentication = true,
priority = 0
);
......
}
좋은 코드일까? 라고 물으면 사람마다 생각이 다를 수 있을 것 같은데요. 개인적으로는 Enum이 데이터베이스의 테이블 과다를 게 없어서 아쉬움이 많이 남았습니다. 차라리 테이블이었다면 데이터를 동적으로 수정할 수라도 있을 텐데 Enum은 안되죠.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE IF NOT EXISTS order_channel
(
code VARCHAR(20) NOT NULL COMMENT '채널 코드',
display_name VARCHAR(50) NOT NULL COMMENT '채널명',
supports_coupon TINYINT(1) NOT NULL COMMENT '쿠폰 사용 가능 여부',
supports_point TINYINT(1) NOT NULL COMMENT '포인트 사용 가능 여부',
supports_gift TINYINT(1) NOT NULL COMMENT '선물하기 가능 여부',
requires_auth TINYINT(1) NOT NULL COMMENT '인증 필요 여부',
priority INT NOT NULL COMMENT '우선순위',
PRIMARY KEY (code)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci
COMMENT = '주문 채널별 정책 설정 테이블';
2. 왜 아쉽다는 생각이 들었을까?
Enum은 자주 변하지 않는 의미의 집합 을 표현하기 위해 존재하는 특별한 데이터 타입 입니다. 변수에 미리 정의된 상수만 담을 수 있도록 선택지를 제한하는 역할을 하죠. 하지만 각 상수에 여러 값을 넣기 시작하면, Enum은 더 이상 타입이 아닌 고정된 데이터를 담은 구조 에 가까워집니다. 즉, 의미 구분보다 변경 가능성 있는 값을 코드에 묶어두는 역할 을 하게 되는 것이죠.
An Enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.
또한 enum은 값뿐만 아니라 동작을 가질 수도 있는데요. 각 상수마다 서로 다른 로직을 구현하거나, 함수형 인터페이스를 통해 동작을 주입하는 방식도 가능하죠. 이러한 기능은 enum을 단순한 상수 집합이 아닌, 행위를 포함한 타입 으로 확장시킵니다. 하지만 값과 로직이 함께 늘어나기 시작하면, enum은 점점 하나의 완결된 객체처럼 변합니다. 이때부터 enum은 더 이상 의미의 선택지를 제한하는 타입이 아니라, 정적인 객체 그래프에 가까운 구조가 되니까요.
1
2
3
4
5
6
7
8
9
10
11
12
enum class DiscountPolicy(
val apply: (Int) -> Int
) {
FIXED(
apply = { price -> price - 1_000 }
),
RATE(
apply = { price -> (price * 0.9).toInt() }
);
}
3. 어느 정도가 적당할까?
개인적으로는 Enum에 두는 값은 많아도 두 개, 최대 세 개 를 넘지 않는 것이 적당하다고 생각하는데요. Enum이 표현해야 할 것은 정책이나 데이터가 아닌, 외부 시스템이나 데이터와 매핑하기 위한 최소한의 식별자 이기 때문입니다. 이 범위를 넘어 필드가 추가되기 시작하면, 해당 값들이 코드에 고정되어도 되는 성격인지 다시 판단해 볼 필요가 있습니다.
Enum이 비즈니스 정책을 코드에 고정하는 수단 이 되면
변경 가능성 있는 값을 컴파일 단위로 묶는 것이 되니까요. 🤔
4. 정리
개인적으로 Enum에는 최소한의 값만 존재해야 한다고 생각합니다. Enum에 값이 너무 많다면 값의 변경이 발생할 때마다 코드 수정과 배포가 필요해지고, 값 관리가 코드에 종속되니까요. 이 경우, Enum이 아닌 다른 구조로 관리하는 것이 바람직한 것 같습니다.