[TYPESCRIPT] Decorator를 쓰기 전에 먼저 고민하게 되는 것들

 

Decorator를 도입하기 전에, 대부분 비슷한 고민을 한 번쯤은 하게 됩니다.

 

  • 이 로직을 함수로 분리하면 안 되는 이유가 있는가
  • 호출부에서 명시적으로 보이는 게 오히려 낫지 않은가
  • 나중에 이 코드를 처음 보는 사람이 이해할 수 있을까

 

Decorator는 코드의 겉모습을 깔끔하게 만들어주지만, 그만큼 실행 흐름을 코드 밖으로 밀어내는 특성이 있습니다. 그래서 “중복 제거”라는 이유만으로 선택하면, 나중에 유지보수 단계에서 비용이 커지는 경우가 많습니다.

 

권한 체크를 Decorator로 빼고 싶을 때

예를 들어, 여러 API에서 비슷한 권한 체크 로직이 반복된다고 가정해보겠습니다.

 


async function updateUser(userId: string, role: string) {
  if (role !== 'ADMIN') {
    throw new Error('FORBIDDEN');
  }
  // ...
}

 

이 코드가 여러 곳에 반복되면, 자연스럽게 Decorator를 떠올리게 됩니다.

 


function RequireRole(role: string): MethodDecorator {
  return (target, propertyKey, descriptor) => {
    const original = descriptor.value as Function;

    descriptor.value = async function (...args: unknown[]) {
      const context = args[0];
      if (context.role !== role) {
        throw new Error('FORBIDDEN');
      }
      return original.apply(this, args);
    };
  };
}

 

이렇게 만들면 호출부는 분명 깔끔해집니다.

 


@RequireRole('ADMIN')
async updateUser(context: Context) {
  // ...
}

 

다만 이 시점부터는,

  • 권한 체크가 언제 실행되는지
  • 실패 시 어떤 예외가 던져지는지
  • 테스트에서 이 로직을 어떻게 우회할지

 

같은 질문에 바로 답하기가 어려워집니다. 로직이 사라진 게 아니라, 보이는 위치가 바뀐 것에 가깝습니다.

 

Decorator가 잘 맞는 쪽과 어긋나는 쪽

경험상 Decorator가 비교적 무리 없이 쓰이는 경우는 다음과 같습니다.

 

  • 프레임워크가 실행 흐름을 이미 관리하고 있는 영역
  • 실행 결과에 영향을 주지 않는 부가 정보
  • 없어도 동작은 하지만, 있으면 편한 기능

 

반대로 다음과 같은 경우에는 한 번 더 고민해보는 편이 좋습니다.

 

  • 비즈니스 분기 로직이 Decorator 안에 들어가는 경우
  • Decorator 없이는 메서드가 의미를 잃는 구조
  • 에러 처리와 예외 흐름이 Decorator에 숨겨진 경우

 

이런 구조에서는 코드를 따라가며 이해하는 데 드는 시간이 눈에 띄게 늘어나는 경우가 많습니다.

 

메타데이터 중심 Decorator는 상대적으로 부담이 적다

Decorator를 꼭 써야 한다면, 동작을 바꾸기보다는 정보를 남기는 용도로 사용하는 편이 안정적입니다.

 


function Feature(name: string): MethodDecorator {
  return (target, propertyKey) => {
    Reflect.defineMetadata('feature', name, target, propertyKey);
  };
}

 

이 경우 Decorator는 실행 흐름에 직접 개입하지 않습니다. 대신 다른 계층에서 이 메타데이터를 읽어 필요한 처리를 하게 됩니다.

 

이 방식은 로직의 위치가 비교적 명확하고, 테스트나 디버깅에서도 부담이 덜합니다.

 

실무에서 자주 겪는 문제

  • Decorator가 많아질수록 실행 순서를 추적하기 어려워진다
  • 에러가 발생했을 때 실제 원인을 찾기 힘들다
  • IDE에서 코드 흐름을 따라가기 어렵다

 

특히 팀 단위 개발에서는 Decorator 사용 여부가 코드 스타일 차이를 넘어 이해 비용 차이로 이어지는 경우도 많습니다.

 


 

Decorator는 메타프로그래밍 도구로서 분명한 장점이 있습니다. 다만 그 장점이 항상 코드 가독성과 유지보수성으로 이어지지는 않습니다.

 

실무에서는 프레임워크가 이미 제공하는 영역에서는 적극적으로 활용하되, 도메인 로직을 감싸기 시작하는 시점부터는 한 번 더 구조를 점검하는 편이 안전합니다.

 

Decorator는 문제를 해결하는 수단 중 하나일 뿐이고, 모든 반복 로직을 해결해주는 만능 도구는 아닙니다. 어디까지 사용할지에 대한 기준을 팀 안에서 공유하는 것이 오히려 더 중요한 부분입니다.