Files
project-auth-server/docs/examples/language/enum-constants.md
T

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를 둔다.