4.3 KiB
4.3 KiB
enum / constants 예시
이 문서는 enum / constants 기준을 코드 예시로 확인하기 위한 자료입니다.
핵심 기준은 고정된 의미 집합을 enum으로 표현하고, external code / display label / internal name을 섞지 않는 것입니다.
좋은 예시 1: 문자열 상수 대신 enum
public enum AuthProvider {
LOCAL,
GOOGLE,
KAKAO
}
if (user.getProvider() == AuthProvider.LOCAL) {
// local login flow
}
왜 좋은가:
- 고정된 값 집합을 타입으로 표현한다.
- 오타와 매직 스트링 분기를 줄인다.
좋은 예시 2: external code를 명시적 필드로 분리
public enum AuthProvider {
LOCAL("local"),
GOOGLE("google"),
KAKAO("kakao");
private final String code;
AuthProvider(String code) {
this.code = code;
}
public String code() {
return code;
}
}
왜 좋은가:
name()에 외부 계약을 맡기지 않는다.- 내부 enum 이름 변경과 외부 계약을 분리할 수 있다.
좋은 예시 3: EnumSet 사용
private static final EnumSet<AuthProvider> SOCIAL_PROVIDERS =
EnumSet.of(AuthProvider.GOOGLE, AuthProvider.KAKAO);
왜 좋은가:
- enum 집합이라는 의도가 직접 드러난다.
- 비트 플래그나 일반
Set보다 타입 안전하고 목적에 맞다.
좋은 예시 4: EnumMap 사용
private final EnumMap<AuthProvider, OAuthClient> clients =
new EnumMap<>(AuthProvider.class);
왜 좋은가:
- enum key 전용 자료구조라는 점이 명확하다.
- 일반
HashMap보다 목적에 더 잘 맞는다.
좋은 예시 5: 진짜 상수만 상수로 둠
private static final Duration ACCESS_TOKEN_TTL = Duration.ofMinutes(30);
private static final List<String> PUBLIC_PATHS = List.of("/", "/login");
왜 좋은가:
- 값이 immutable이다.
static final뿐 아니라 실제 의미도 안정적이다.
나쁜 예시 1: ordinal 저장/분기
int providerCode = provider.ordinal();
문제:
- enum 순서 변경이나 값 추가에 취약하다.
- stable contract가 아니다.
개선:
String providerCode = provider.code();
나쁜 예시 2: name/toString 문자열 비교
if (provider.name().equals("GOOGLE")) {
// google login flow
}
문제:
- enum 의미 비교를 문자열 비교로 내린다.
- 타입 안전성이 사라진다.
개선:
if (provider == AuthProvider.GOOGLE) {
// google login flow
}
나쁜 예시 3: 잡다한 constants class
public final class AppConstants {
public static final String PROVIDER_LOCAL = "LOCAL";
public static final String PROVIDER_GOOGLE = "GOOGLE";
public static final String PROVIDER_KAKAO = "KAKAO";
private AppConstants() {
}
}
문제:
- 고정된 의미 집합을 타입으로 표현하지 않는다.
- 문자열 오타와 분기 누락에 취약하다.
개선:
public enum AuthProvider {
LOCAL,
GOOGLE,
KAKAO
}
나쁜 예시 4: mutable collection을 상수처럼 사용
private static final Set<String> PUBLIC_PATHS = new HashSet<>();
문제:
static final이어도 내부 상태는 바뀔 수 있다.- 진짜 상수라고 보기 어렵다.
개선:
private static final Set<String> PUBLIC_PATHS = Set.of("/", "/login");
나쁜 예시 5: default로 enum 추가 누락 숨김
return switch (provider) {
case LOCAL -> localHandler();
default -> socialHandler();
};
문제:
- 새 enum 값이 생겨도 의도치 않게
default에 흡수될 수 있다. - 분기 누락이 컴파일 시점에 드러나기 어렵다.
개선:
return switch (provider) {
case LOCAL -> localHandler();
case GOOGLE, KAKAO -> socialHandler();
};
나쁜 예시 6: null 회피용 UNKNOWN 남용
public enum AuthProvider {
UNKNOWN,
LOCAL,
GOOGLE,
KAKAO
}
문제:
UNKNOWN이 실제 비즈니스 상태가 아니라면 의미 없는 상태가 생긴다.- 단순 null 회피가 enum 모델에 섞인다.
개선 방향:
- boundary 입력은 검증하거나 nullable로 명시한다.
- 조회 결과의 부재는 필요하면
Optional<AuthProvider>로 표현한다. - 실제 비즈니스 상태일 때만
UNKNOWN또는UNSPECIFIED를 둔다.