이미지 로딩 중...
CodeDeck AI
2025. 11. 8. · 1 Views
Facade Pattern 트러블슈팅 완벽 가이드
복잡한 서브시스템을 단순화하는 Facade 패턴의 실전 트러블슈팅 가이드입니다. 실무에서 자주 발생하는 문제와 해결책을 코드와 함께 제시합니다.
들어가며
이 글에서는 Facade Pattern 트러블슈팅 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- Facade_Pattern_기본_구조
- 순환_참조_문제_해결
- 과도한_책임_분리하기
- 에러_처리_전략
- 트랜잭션_관리_패턴
- 캐싱_레이어_추가
- 비동기_작업_조율
- 버전_관리_전략
- 테스트_용이성_개선
- 설정_주입_패턴
- 로깅_및_모니터링
- 재시도_로직_구현
1. Facade_Pattern_기본_구조
개요
Facade 패턴은 복잡한 서브시스템의 인터페이스를 단순화하여 클라이언트가 쉽게 사용할 수 있도록 합니다. 여러 개의 복잡한 클래스들을 하나의 간단한 인터페이스로 제공합니다.
코드 예제
class VideoConverter {
convert(filename: string, format: string): string {
const file = new VideoFile(filename);
const codec = CodecFactory.extract(file);
const result = BitrateReader.convert(file, codec, format);
return new AudioMixer().fix(result);
}
}
설명
VideoConverter는 VideoFile, CodecFactory, BitrateReader, AudioMixer 등 복잡한 서브시스템을 감추고 convert 하나의 메서드로 간단하게 제공합니다.
2. 순환_참조_문제_해결
개요
Facade 내부에서 서브시스템들이 서로를 참조할 때 순환 참조가 발생할 수 있습니다. 의존성 주입과 인터페이스를 활용하여 해결합니다.
코드 예제
interface IPayment { process(): void; }
class PaymentFacade {
constructor(
private validator: IPayment,
private processor: IPayment
) {}
pay() {
this.validator.process();
this.processor.process();
}
}
설명
구체적인 클래스 대신 인터페이스를 사용하고 생성자 주입을 통해 순환 참조를 방지하며 테스트 가능성을 높입니다.
3. 과도한_책임_분리하기
개요
Facade가 너무 많은 책임을 가지면 God Object가 됩니다. 단일 책임 원칙을 적용하여 여러 개의 작은 Facade로 분리합니다.
코드 예제
class UserAuthFacade {
login(credentials: Credentials) { /* auth only */ }
logout() { /* auth only */ }
}
class UserProfileFacade {
getProfile(id: string) { /* profile only */ }
updateProfile(data: Profile) { /* profile only */ }
}
설명
하나의 거대한 UserFacade 대신 인증과 프로필 관리를 별도의 Facade로 분리하여 각각의 책임을 명확히 합니다.
4. 에러_처리_전략
개요
서브시스템의 다양한 예외를 Facade에서 일관된 방식으로 처리하고 클라이언트에게 명확한 에러를 전달합니다.
코드 예제
class OrderFacade {
async placeOrder(order: Order) {
try {
await this.inventory.check(order);
await this.payment.process(order);
return await this.shipping.schedule(order);
} catch (e) {
throw new OrderError('주문 처리 실패', e);
}
}
}
설명
서브시스템의 다양한 에러를 catch하여 클라이언트가 이해하기 쉬운 OrderError로 변환하여 에러 처리를 단순화합니다.
5. 트랜잭션_관리_패턴
개요
여러 서브시스템 작업을 하나의 트랜잭션으로 묶어 원자성을 보장합니다. 실패 시 롤백 로직을 Facade에서 관리합니다.
코드 예제
class BookingFacade {
async book(data: Booking) {
const session = await this.db.startSession();
try {
await this.reserve(data, session);
await this.charge(data, session);
await session.commit();
} catch (e) {
await session.rollback();
throw e;
}
}
}
설명
데이터베이스 세션을 활용하여 예약과 결제를 하나의 트랜잭션으로 처리하고, 실패 시 자동으로 롤백하여 데이터 일관성을 유지합니다.
6. 캐싱_레이어_추가
개요
Facade에 캐싱 로직을 추가하여 서브시스템 호출을 최소화하고 성능을 향상시킵니다. 캐시 무효화 전략도 함께 구현합니다.
코드 예제
class ProductFacade {
private cache = new Map<string, Product>();
async getProduct(id: string) {
if (this.cache.has(id)) return this.cache.get(id);
const product = await this.db.find(id);
this.cache.set(id, product);
return product;
}
}
설명
Map을 활용한 간단한 캐시를 Facade 내부에 구현하여 동일한 요청에 대해 데이터베이스 조회를 줄이고 응답 속도를 개선합니다.
7. 비동기_작업_조율
개요
여러 비동기 서브시스템 호출을 효율적으로 조율합니다. 병렬 처리가 가능한 작업은 Promise.all을 사용하여 성능을 최적화합니다.
코드 예제
class DashboardFacade {
async getData(userId: string) {
const [user, stats, notifications] = await Promise.all([
this.userService.get(userId),
this.analyticsService.getStats(userId),
this.notificationService.getRecent(userId)
]);
return { user, stats, notifications };
}
}
설명
서로 독립적인 세 가지 서비스 호출을 Promise.all로 병렬 처리하여 순차 실행 대비 3배 빠른 응답 시간을 달성합니다.
8. 버전_관리_전략
개요
API 버전이 변경될 때 기존 클라이언트를 깨뜨리지 않고 새 기능을 추가합니다. Facade에서 버전 분기 처리를 담당합니다.
코드 예제
class ApiGateway {
handle(req: Request) {
const version = req.headers['api-version'];
if (version === 'v2') {
return new FacadeV2(this.services).process(req);
}
return new FacadeV1(this.services).process(req);
}
}
설명
요청 헤더의 버전 정보에 따라 적절한 Facade 구현체를 선택하여 하위 호환성을 유지하면서 새로운 기능을 제공합니다.
9. 테스트_용이성_개선
개요
Facade의 서브시스템 의존성을 인터페이스로 추상화하여 Mock 객체로 쉽게 대체할 수 있게 합니다. 단위 테스트가 용이해집니다.
코드 예제
interface IEmailService { send(to: string): Promise<void>; }
class NotificationFacade {
constructor(private email: IEmailService) {}
async notify(user: User) {
await this.email.send(user.email);
}
}
// Test: new NotificationFacade(mockEmailService)
설명
구체 클래스 대신 IEmailService 인터페이스에 의존하여 테스트 시 실제 이메일 발송 없이 Mock 객체로 대체하여 빠르고 안정적인 테스트가 가능합니다.
10. 설정_주입_패턴
개요
서브시스템 설정을 Facade 생성 시점에 주입하여 환경별로 다른 동작을 구현합니다. 개발/스테이징/프로덕션 환경 분리에 유용합니다.
코드 예제
class StorageFacade {
constructor(private config: StorageConfig) {}
async save(file: File) {
if (this.config.env === 'prod') {
return this.s3.upload(file);
}
return this.localStorage.save(file);
}
}
설명
설정 객체를 생성자로 주입받아 프로덕션 환경에서는 S3를, 개발 환경에서는 로컬 스토리지를 사용하도록 동작을 분기합니다.
11. 로깅_및_모니터링
개요
Facade에서 서브시스템 호출을 래핑하여 로깅, 메트릭 수집, 성능 측정을 중앙화합니다. 운영 중 문제 추적이 쉬워집니다.
코드 예제
class PaymentFacade {
async processPayment(order: Order) {
const start = Date.now();
try {
const result = await this.gateway.charge(order);
this.logger.info('결제 성공', Date.now() - start);
return result;
} catch (e) {
this.logger.error('결제 실패', e);
throw e;
}
}
}
설명
결제 처리 전후로 시간을 측정하고 성공/실패 로그를 기록하여 운영 환경에서 결제 성능과 에러율을 모니터링할 수 있습니다.
12. 재시도_로직_구현
개요
일시적인 네트워크 오류나 서비스 장애에 대응하기 위해 Facade에서 재시도 로직을 구현합니다. Exponential backoff 전략을 사용합니다.
코드 예제
class ApiFacade {
async fetchWithRetry(url: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await this.http.get(url);
} catch (e) {
if (i === retries - 1) throw e;
await this.sleep(2 ** i * 1000);
}
}
}
}
설명
최대 3번까지 재시도하며 실패할 때마다 대기 시간을 2배씩 늘려(1초, 2초, 4초) 서버 부하를 줄이면서 일시적 장애를 극복합니다.
마치며
이번 글에서는 Facade Pattern 트러블슈팅 완벽 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#TypeScript #DesignPatterns #Facade #Architecture #CleanCode