39. 명명 패턴보다 애너테이션을 사용하라

명명 패턴 이란?

메서드에 이름을 특정 이름으로 시작하게 만들어서, 해당 이름이 들어가면 실행하도록 만들기 위한 패턴

명명 패턴의 단점?

  1. 오타가 나면 안된다

    public void tsetSum() { /* 오타! 테스트가 실행되지 않음 */ }
  2. 올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다

    // 클래스 이름에 test를 붙여도 테스트로 인식되지 않아요
    public class TestCalculator { /* ... */ }
  3. 프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다

    // 어떤 예외가 발생해야 테스트가 성공하는지 이름으로 표현하기 어려워요
    public void testDivideByZeroThrowsException() { /* ... */ }

✅ 애너테이션을 사용하면 명명 패턴의 단점들을 개선할 수 있다!

애너테이션이란?

코드에 정보를 추가하는 특별한 표시. @로 시작한다

@Test
public void sum() { /* 테스트 코드 */ }

애너테이션의 장점

  1. 오타가 나면 컴파일 오류가 발생해요

    @Tset // 컴파일 오류! 이런 애너테이션은 없어요
    public void sum() { /* ... */ }
  2. 적용 위치를 제한할 수 있어요

    @Target(ElementType.METHOD) // 메서드에만 사용 가능해요
    public @interface Test { }
  3. 추가 정보를 전달할 수 있어요

    @ExceptionTest(ArithmeticException.class)
    public void divideByZero() { /* ... */ }

❓ 그러면 애너테이션을 만들어서 실행시키기만 하면 되지않나?

자동으로 동작하는 건 아니다!

➔ 실제로 어떤 동작을 하게 하려면, 그 애너테이션을 해석하고 처리할 코드를 따로 만들어야 한다

간단한 애너테이션 만들기

  1. 마커 애너테이션 (정보 없이 표시만 하는 애너테이션)

    // 테스트 메서드임을 표시하는 애너테이션
    @Retention(RetentionPolicy.RUNTIME) // 실행 중에도 유지됨
    @Target(ElementType.METHOD)         // 메서드에만 사용 가능
    public @interface Test {
    }
  2. 매개변수가 있는 애너테이션

    // 특정 예외가 발생해야 성공하는 테스트를 표시
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ExceptionTest {
        Class<? extends Throwable> value(); // 매개변수 (예외 클래스)
    }
  3. 사용 예시

    // 마커 애너테이션 사용
    @Test
    public static void sum() {
        // 테스트 코드
    }
    
    // 매개변수가 있는 애너테이션 사용
    @ExceptionTest(ArithmeticException.class)
    public static void divideByZero() {
        int result = 5 / 0; // ArithmeticException 발생
    }

여러 값을 전달하는 방법

  1. 배열 사용하기

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ExceptionTest {
        Class<? extends Throwable>[] value(); // 배열 매개변수
    }
    
    // 사용 예시
    @ExceptionTest({ArithmeticException.class, NullPointerException.class})
    public static void testMultipleExceptions() {
        // 이 중 하나의 예외가 발생하면 테스트 성공
    }

    ✔️ 문법적으로 더 간단함

    ✔️ 모든 값을 한 번에 지정해야 함

    ✔️ 코드가 더 깔끔해 보일 수 있음

  1. 반복 가능한 애너테이션 사용하기 (자바 8 이상)

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Repeatable(ExceptionTestContainer.class) // 반복 가능하게 만들기
    public @interface ExceptionTest {
        Class<? extends Throwable> value();
    }
    
    // 컨테이너 애너테이션
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ExceptionTestContainer {
        ExceptionTest[] value();
    }
    
    // 사용 예시
    @ExceptionTest(ArithmeticException.class)
    @ExceptionTest(NullPointerException.class)
    public static void testMultipleExceptions() {
        // 두 애너테이션을 따로 반복해서 사용
    }

    ✔️ 각 값을 별도로 지정할 수 있음

    ✔️ 코드를 나중에 수정할 때 개별 항목을 추가/제거하기 쉬움

    ✔️ 읽기에 더 명확할 수 있음 (각 예외가 별도 줄에 표시됨)

애너테이션과 명명 패턴 비교

명명 패턴
애너테이션

오타에 취약함

컴파일 시점에 오류 검사

적용 대상 제한 불가

@Target으로 적용 대상 제한 가능

추가 정보 전달 어려움

매개변수로 다양한 정보 전달 가능

패턴 확인 위해 문자열 처리 필요

리플렉션 API로 쉽게 처리 가능

실생활에서 볼 수 있는 애너테이션 예시

@Override: 메서드가 부모 클래스의 메서드를 재정의했음을 표시

@Deprecated: 더 이상 사용하지 않는 기능임을 표시

@SuppressWarnings: 특정 경고를 무시하도록 지시

스프링 프레임워크: @Controller, @Service, @Autowired

요약

✔️ 명명 패턴은 오타, 적용 대상 제한, 정보 전달 문제가 있다

✔️ 애너테이션은 이러한 문제를 해결하며 더 안전하고 유연하다

✔️ 자바의 다양한 메타 애너테이션을 활용해 용도에 맞는 애너테이션을 만들 수 있다

✔️ 프로그램 요소에 정보를 추가하거나 특별한 처리가 필요할 때는 명명 패턴 대신 애너테이션을 사용하자!


🧩 어려웠던 점

  • 리플렉션 API를 이해하고 사용하는 것이 처음에는 어려웠다

  • 애너테이션의 다양한 메타 애너테이션(@Retention, @Target 등)의 의미 이해하기

  • 컨테이너 애너테이션과 @Repeatable 개념 이해하기

💭 느낀 점

  • 애너테이션은 코드를 더 명확하고 안전하게 만들어 준다

  • 프레임워크 개발자와 사용자 간의 소통을 더 쉽게 만들어 준다

  • 현대 자바 개발에서 애너테이션은 필수적인 기능이다

  • 적절히 사용하면 코드의 가독성과 유지보수성이 크게 향상 될것이다

Last updated