로직은 같지만 개발과 운영에서 필요한 값이 다른 경우가 있는데, 대표적으로 url이 있습니다.
지금의 회사에서는 enum을 통해 관리하고 있지만, 그 방식이 enum 스럽지 않다고 생각하고 있었습니다.
그러던 중 기존 test - dev - stage - prod로 구성되었던 환경이 dev - qa - stage - prod로 변경되었고, 이 과정에서 코드를 개선한 내용을 기록해 봅니다.
Before
환경 변수 enum
public enum DeploymentEnvironment {
DEV, QA, STAGE, PROD;
private static final String AUTH_SERVER_NAME = Optional.ofNullable(System.getenv("AUTH_SERVER_NAME"))
.orElse("");
public static boolean isDev() {
return AUTH_SERVER_NAME.equals(DEV.name().toLowerCase(Locale.ROOT));
}
public static boolean isQA() {
return AUTH_SERVER_NAME.equals(QA.name().toLowerCase(Locale.ROOT));
}
public static boolean isStage() {
return AUTH_SERVER_NAME.equals(STAGE.name().toLowerCase(Locale.ROOT));
}
public static boolean isProd() {
return AUTH_SERVER_NAME.equals(PROD.name().toLowerCase(Locale.ROOT));
}
}
환경 구분이 enum으로 존재하긴 하지만 모든 환경을 확인하기 위해서는 4개나 되는 if-else가 필요합니다.
사용 예시 1
// swagger 설정
public class OpenApiConfig {
private OpenAPI getOpenAPI() {
if (DeploymentEnvironment.isDev()) {
return new OpenAPI()
.addServersItem(new Server().url("https://dev.aaa.co.kr/"))
.addServersItem(new Server().url("http://localhost:8820/"));
}
if (DeploymentEnvironment.isQA()) {
return new OpenAPI()
.addServersItem(new Server().url("https://qa.aaa.co.kr/"))
.addServersItem(new Server().url("http://localhost:8820/"));
}
if (DeploymentEnvironment.isStage()) {
return new OpenAPI()
.addServersItem(new Server().url("https://stage.aaa.co.kr/"))
.addServersItem(new Server().url("http://localhost:8820/"));
}
if (DeploymentEnvironment.isProd()) {
return new OpenAPI()
.addServersItem(new Server().url("https://api.aaa.com/"))
.addServersItem(new Server().url("http://localhost:8820/"));
}
return new OpenAPI()
.addServersItem(new Server().url("http://localhost:8820/"));
}
}
환경별로 다른 url을 설정하기 위해서는 4번의 if-else를 사용해야 했습니다.
사용 예시 2
public enum BBBCallbackRequest {
UPDATE_USER_ID(HttpMethod.PATCH, () -> getBaseUrl() + "/api/shop/user"),
;
private final HttpMethod httpMethod;
private final Supplier<String> urlSupplier;
private static String getBaseUrl() {
if (DeploymentEnvironment.isProd()) {
return "https://shop.bbb.com";
}
if (DeploymentEnvironment.isStage()) {
return "https://shopstage.bbb.co.kr";
}
if (DeploymentEnvironment.isQA()) {
return "https://shopqa.bbb.co.kr";
}
throw new IllegalStateException("local, dev 에서는 콜백하지 않습니다.");
}
}
심지어는 환경에 따라 예외를 발생시켜야 되는 경우도 있었습니다.
무엇보다도 url이 곳곳에 분산되어 관리하기 힘들었고 변경에 들어가는 공수도 컸습니다.
After
환경 변수 enum
public enum DeploymentEnvironment {
LOCAL("", ""),
DEV("", "https://dev.aaa.co.kr/"),
QA("https://shopqa.bbb.co.kr", "https://qa.aaa.co.kr/"),
STAGE("https://shopstage.bbb.co.kr", "https://stage.aaa.co.kr/"),
PROD("https://shop.bbb.com", "https://api.aaa.com/");
public static final DeploymentEnvironment CURRENT_DEPLOYMENT_ENVIRONMENT;
private final String bbbCallbackUrl;
private final String baseUrl;
static {
final String authServerName = Optional.ofNullable(System.getenv("AUTH_SERVER_NAME"))
.orElse("")
.toUpperCase(Locale.ROOT);
CURRENT_DEPLOYMENT_ENVIRONMENT = Arrays.stream(DeploymentEnvironment.values())
.filter(environment -> environment.name().equals(authServerName))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("알 수 없는 환경 변수"));
}
}
현재 환경을 CURRENT_DEPLOYMENT_ENVIRONMENT로 정의하고 정적 초기화합니다.
사용 예시
// 사용 예시 1
public class OpenApiConfig {
private static OpenAPI getOpenAPI() {
if (CURRENT_DEPLOYMENT_ENVIRONMENT.getBaseUrl().isBlank()) {
return new OpenAPI().addServersItem(new Server().url("http://localhost:8820/"));
}
return new OpenAPI().addServersItem(new Server().url(CURRENT_DEPLOYMENT_ENVIRONMENT.getBaseUrl()));
}
}
// 사용 예시 2
public enum BBBCallbackRequest {
UPDATE_USER_ID(
HttpMethod.PATCH, () -> CURRENT_DEPLOYMENT_ENVIRONMENT.getBbbCallbackUrl() + "/api/v2/shop/user"),
;
private final HttpMethod httpMethod;
private final Supplier<String> urlSupplier;
}
사용 예시가 극단적으로 간결해졌습니다.
무엇보다도 enum을 통해 코드 응집도를 높였기에 환경이 변경되어도 enum만 수정하면 되는 것이 가장 큰 장점입니다.
마치며
예시는 2개뿐이지만 실제로는 더 많은 사용이 있었고, 이 수정을 통해 미래의 변경 영향도도 축소할 수 있습니다.
만약 환경 변수 관리가 더 민감했다면 Spring Cloud Config 등을 활용할 수 있겠지만, 그것 또한 구성과 운영의 어려움이 있고 지금의 회사에서도 Dockerfile을 통한 관리 정도는 하기에 괜찮다고 이 정도의 개선만 진행했습니다.
'Series > 내가 해본' 카테고리의 다른 글
git branch 전략 + commit 기록 방법 선택하기 (3) | 2023.10.09 |
---|---|
ErrorMessage를 관리하는 방법 (1) | 2022.06.15 |
DB 값을 enum 으로 표현해보자 (0) | 2021.11.20 |
Elastic Beanstalk 구성 삽질기 - 글쑤시개 (0) | 2021.08.14 |
Slack Bot 으로 채널에 글쓰기 (0) | 2021.08.04 |