진행했던 프로젝트에서 웹뷰를 통해 여러 고객사에 자사 서비스를 제공하고 있었습니다. 고객사마다 제공되는 서비스는 url의 subdomain으로 구분되어 있었고, 고객사마다 다르게 적용되는 UI나 기능이 존재했습니다.
기존 코드에서는 고객사마다 다르게 동작하는 component 내부에서 url의 subdomain을 읽어오고, 각 고객사에 해당하는 string 값과 비교하는 로직이 중복되어 작성되어 있었습니다.
Problems
이러한 코드의 문제점에는 코드 중복과 하드코딩으로 인한 에러에 취약하다는 점이 있습니다.
- 코드 중복: url에서 subdomain을 읽어오고, 각 고객사(provider)에 해당하는 string 값과 비교하는 로직이 여러 component에 중복되어 존재하여 유지 보수가 어렵습니다.
- 하드 코딩:
provider === 'provider1'
와 같이 string literal 값과 비교하는 과정에서 human error가 발생할 수 있습니다. (error prone)
const provider = window.location.hostname.split(".")[0];
...
provider === "provider1" ? ... : ...;
Solutions
이러한 문제점들을 해결하기 위해 url의 subdomain과 고객사 provider를 비교하는 로직을 함수로 추출하기로 했습니다.
// providerUtils.ts
type SubdomainType = "provider1" | "provider2";
export const getSubdomain = (): SubdomainType | undefined => {
const subdomain = window.location.hostname.split(".")[0];
if ( /* check if subdomain is of type SubdomainType */ ) {
return subdomain;
}
return;
};
위의 코드와 같이 if 문의 조건식에서 subdomain의 타입을 확인하려고 했지만, runtime에서 TypeScript의 type 정보가 사라져서 다른 방법을 사용해야 했습니다.
TypeScript의 type 정보를 이용하기 위해서 아래 코드처럼 Provider들을 담은 providerList를 만들고 as const
assertion으로 type narrowing을 해 주었습니다.
as const
A const assertion tells the compiler to infer the narrowest or most specific type it can for an expression. If you leave it off, the compiler will use its default type inference behavior, which will possibly result in a wider or more general type.
// providerUtils.ts
const providerList = ['provider1', 'provider2'] as const;
type SubdomainType = (typeof providerList)[number];
const isSubdomain = (provider: string): provider is SubdomainType => {
return providerList.includes(provider as SubdomainType);
};
export const getSubdomain = (): SubdomainType | undefined => {
const subdomain = window.location.hostname.split('.')[0];
if (isSubdomain(subdomain)) {
return subdomain;
}
return;
};
이렇게 코드를 변경함으로써 얻은 장점은 다음과 같습니다.
-
provider가 추가되면 자동으로 providerList를 토대로 SubdomainType을 만들어 주어 코드 관리 및 유지 보수 측면에서 좋음
-
type predicate를 활용한 isSubdomain 함수를 만들어 조건문에서 type narrowing이 가능하도록 함
-
사용하는 곳에서 compiler hint로 개발 생산성 향상