본문 바로가기

Design Patterns

게이트웨이 패턴, 서비스 스텁 패턴

이 포스팅은 엔터프라이즈 어플리케이션 아키텍처 패턴 18장을 요약했습니다.

 

게이트 웨이

외부 시스템이나 자원에 대한 접근을 캡슐화하는 객체 aka, 갖다 쓸 때 만들어서 사용하는 API

 

외부 자원에 접근할 때는 해당 자원의 API를 사용해야 한다. (전용 API) 예를들어, 외부 이메일 시스템을 연동한다고 할때 EmailSender.send(id, emailformat, title, content ...) 와 같이 제공하는 형식을 맞춰서 사용해야 한다. 모든 특수한 API 코드를 일반 객체처럼 보이는 인터페이스를 포함하는 클래스로 래핑하면 이 문제를 간단하게 해결할 수 있다.

 

작동 원리

외부 자원에 대해 어떤 작업을 수행해야 하는지 고려해서 용도에 맞는 API를 만든 다음 사용하면 끝

 

주요 용도

서비스 스텁을 적용하는 지점

외부 서비스와 연결

 

사용 시점

외부 자원에 대한 인터페이스가 불편하다고 느껴질 때

 

장점

게이트웨이를 구현한 후에는 자원을 다른 종류로 교체하기가 쉬움(게이트 웨이만 수정하면 됨)

 

특성

  • 유연성
  • 단순성
  • 테스트 용이성

비슷한 기술

매퍼(Mapper), 파사드(Facade), 어댑터(Adapter), 중재자(Mediator)

 

예제: 특정 메시징 서비스에 대한 게이트웨이

예제에서는 메시지 서비스를 사용해 메시지 하나를 전송하는 인터페이스에 대한 게이트웨이를 작성한다.

 

인터페이스에는 다음과 같은 메서드가 하나 있다.

int send(String messageType, Object[] args); 

첫 번째 인수는 메시지의 유형을 ,두번째 인수는 메시지를 지정하는 인수다. 예를 들어 메시지 유형으로는 "CNFRM", 메시지를 지정하는 인수에는 ID 번호, 크기, 코드를 넣는다고 하자. 메시징 시스템은 인수의 형식을 확인하고 잘못된 메시지를 보내거나 잘못된 인수와 올바른 메시지를 보내는 경우 오류를 생성할 수 있다.

 

이런 범용 인터페이스는 다음과 같이 게이트웨이로 구체적인 API를 만들어줄 필요가 있다.

class MessageGateway...

  protected static final String CONFIRM = "CNFRM";
  private MessageSender sender;
    
  public void sendConfirmation(String orderID, int amount, String symbol){
    Object[] args  new Object[]{orderID, new Integer(amount, symbol);
    send(CONFIRM, args);
  }

  private void send(String msg, Object[] args) {
    int returnCode = doSend(msg, args);
    if (returnCode == MessageSender.NULL_PARAMETER)
      throw new NullPointerException();
    if (returnCode != MessageSender.SUCCESS)
      throw new IllegalStateException();
  }

  protected int doSend(String msg, Object[] args){
    Assert.notNull(sender);
    return sender.send(msg, args);
  }

 

서비스 스텁(Service Stub) 패턴 (Mock object)

테스트 중 문제가 될 수 있는 서비스에 대한 의존성을 제거한다.

 

  • 엔터프라이즈 시스템은 타사 서비스를 이용하는 경우가 많은데 테스트 중에는 이러한 외부 시스템에 대한 의존성을 낮추기 위해 서비스 스텁으로 대체한다.
  • 외부 서비스를 로컬에서 인메모리로 빠르게 실행되는 서비스 스텁으로 대체한다.

 

작동 원리

  1. 게이트웨이를 통해 서비스에 대한 접근을 정의 (게이트웨이는 분리 인터페이스 여야 한다.)
  2. 서비스의 요구사항 파악하여 해당 서비스 스텁을 작성한다.

 

사용 시점

서비스 간의 의존성 때문에 개발과 테스트 속도가 더뎌지는 경우

 

예제: 소비세 서비스(자바)

 

1. 게이트웨이를 통해 서비스 스텁을 로드하기 위해 인터페이스 정의

interface TaxService...
    public static final TaxService INSTANCE = (TaxService) PluginFactory.getPlugin(TaxService.class);
    public TaxInfo getSalesTaxInfo(String productCode, Address addr, Money saleAmount);

 

2. 테스트에 필요한 요구사항을 파악하여 서비스 스텁 작성

  • 간단한 고정 세율 서비스 스텁
class FlatRateTaxService implements TaxService...

  private static final BigDecimal FLAT_RATE = new BigDecimal("0.500");

  public TaxInfo getSalesTaxInfo(String productCode, Address addr, Money saleAmount){
    return new TaxInfo(FLAT_RATE, saleAmount.multiply(FLAT_RATE);
  }
  • 특정 주소와 상품의 조합에 대해 면세를 제공하는 서비스 스텁
class ExemptProductTaxService implements TaxService...

public TaxInfo getSalesTaxInfo(String productCode, Address addr, Money saleAmount){
  if(productCode.equals(EXEMPT_PRODUCT) && addr.getStateCode().equals(EXEMPT_STATE)){
    return new TaxInfo(EXEMPT_RATE, saleAmount.multiply(EXEMPT_RATE);
  } else{
    return new TaxInfo(FLAT_RATE, saleAmount.multiply(FLAT_RATE);
  }
}

 

'Design Patterns' 카테고리의 다른 글

분리 인터페이스 패턴, 플러그인 패턴  (0) 2020.10.09
매퍼 패턴, 계층 상위 형식패턴  (0) 2020.10.09
지연로드(Lazy Load) 패턴  (0) 2020.10.04
식별자 맵 패턴  (0) 2020.10.03
작업단위 패턴  (0) 2020.10.03