메타지침 바인딩 기술 (Semantic Directive Binding) - Java 25 + Spring Boot 4.0 가이드

업데이트:

메타지침 바인딩 기술 (Semantic Directive Binding) 가이드

1. 개념 (Concept)

1.1 메타지침 바인딩이란?

메타지침 바인딩(Semantic Directive Binding)은 런타임에 메타데이터와 지시사항을 의미론적으로 바인딩하여, 동적 처리 로직을 구성하는 고급 아키텍처 패턴입니다.

핵심 특징

  • 동적 메타데이터 주입: 런타임에 메타정보를 동적으로 주입
  • 의미론적 해석: 컨텍스트 기반의 의미론적 해석 및 처리
  • 우선순위 기반 실행: 지시사항의 우선순위에 따른 순차 또는 병렬 처리
  • 컨텍스트 인식: 사용자, 소스, 환경 정보를 컨텍스트에 포함
  • 확장성: 새로운 지시사항을 쉽게 추가 가능한 플러그인 아키텍처

1.2 실제 활용 시나리오

메타지침 바인딩은 다음과 같은 상황에서 매우 유용합니다:

  1. CMS(콘텐츠 관리 시스템): 문서 발행 전 자동 검증, 형식 지정, 접근 제어 적용
  2. API 게이트웨이: 요청에 따른 인증, 로깅, 캐싱, 변환 지시사항 동적 적용
  3. 워크플로우 엔진: 프로세스 단계별 다양한 지시사항 조건부 실행
  4. 데이터 파이프라인: ETL 과정에서 검증, 변환, 필터링 지시사항 적용
  5. AI/ML 모델 서빙: 입력 전처리, 모델 선택, 후처리 지시사항 런타임 적용

2. 메커니즘 (Mechanism)

2.1 동작 원리

메타지침 바인딩의 동작 흐름은 다음과 같습니다:

┌──────────────────────────────────────────────────────────┐
│ 1. 요청 수신 (Request Received)                           │
│    - 사용자, 소스, 파라미터 정보                            │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────▼─────────────────────────────────────┐
│ 2. 컨텍스트 생성 (Context Creation)                        │
│    - DirectiveContext 객체 생성                           │
│    - 메타데이터 및 속성 설정                                │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────▼─────────────────────────────────────┐
│ 3. 지시사항 선택 (Directive Selection)                     │
│    - DirectiveRegistry에서 필요한 지시사항 조회              │
│    - 우선순위 순서로 정렬                                   │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────▼─────────────────────────────────────┐
│ 4. 순차 실행 (Sequential Execution)                       │
│    - 각 지시사항의 execute() 메서드 호출                    │
│    - 이전 결과를 다음 지시사항에 전달                        │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────▼─────────────────────────────────────┐
│ 5. 결과 집계 (Result Aggregation)                         │
│    - 모든 지시사항의 결과 수집                              │
│    - DirectiveResult 객체 반환                            │
└──────────────────────────────────────────────────────────┘

2.2 핵심 인터페이스

SemanticDirective 인터페이스

public interface SemanticDirective {
    /**
     * 지시사항의 이름 반환
     */
    String getName();

    /**
     * 지시사항 실행
     * @param context 실행 컨텍스트
     * @param parameters 매개변수
     * @return 실행 결과
     */
    Object execute(DirectiveContext context, Map<String, Object> parameters);

    /**
     * 지시사항이 유효한지 검증
     */
    boolean isValid();

    /**
     * 지시사항의 우선순위 반환 (높을수록 먼저 실행)
     */
    int getPriority();

    /**
     * 지시사항의 메타데이터 반환
     */
    Map<String, String> getMetadata();
}

DirectiveContext 클래스

@Data
@Builder
public class DirectiveContext {
    private String contextId;          // 고유 컨텍스트 ID
    private String userId;             // 사용자 ID
    private String sourceType;         // 요청 소스 타입
    private Map<String, Object> metadata;    // 메타데이터
    private Map<String, Object> attributes;  // 확장 데이터
}

3. 아키텍처 (Architecture)

3.1 전체 시스템 아키텍처

┌──────────────────────────────────────────────────────────────┐
│                    REST Controller                           │
│              (DocumentController)                            │
└──────────────────────┬───────────────────────────────────────┘
                       │
┌──────────────────────▼───────────────────────────────────────┐
│                  Service Layer                               │
│            (DocumentService)                                 │
│  - 문서 생성, 조회, 발행                                        │
│  - 지시사항 적용 조정                                           │
└──────────────────────┬───────────────────────────────────────┘
                       │
┌──────────────────────▼───────────────────────────────────────┐
│              Directive Processing Layer                      │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐  │
│  │      DirectiveProcessor (지시사항 실행 엔진)              │  │
│  │  - 단일 지시사항 실행                                     │  │
│  │  - 다중 지시사항 순차 실행                                │  │
│  │  - 조건부 지시사항 실행                                   │  │
│  └────────────────────────────────────────────────────────┘  │
│                       │                                      │
│  ┌────────────────────▼───────────────────────────────────┐  │
│  │      DirectiveRegistry (지시사항 중앙 관리소)             │  │
│  │  - 지시사항 등록/조회                                     │  │
│  │  - 우선순위 관리                                         │  │
│  └────────────────────────────────────────────────────────┘  │
└──────────────────────┬───────────────────────────────────────┘
                       │
┌──────────────────────▼───────────────────────────────────────┐
│            Concrete Directives Layer                         │
│                                                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│  │Validation│  │  Access  │  │Content   │  │ Caching  │      │
│  │Directive │  │ Control  │  │Formatting│  │Directive │      │
│  │          │  │Directive │  │Directive │  │          │      │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘      │
│                                                              │
│  + 커스텀 지시사항 추가 가능                                     │
└──────────────────────────────────────────────────────────────┘

3.2 클래스 다이어그램

┌─────────────────────────────┐
│   SemanticDirective         │
│     (Interface)             │
├─────────────────────────────┤
│ + getName(): String         │
│ + execute(...): Object      │
│ + isValid(): boolean        │
│ + getPriority(): int        │
│ + getMetadata(): Map        │
└─────────────────────────────┘
           △
           │ implements
           │
    ┌──────┴───────┬─────────────┬───────────────┐
    │              │             │               │
┌───┴──────┐  ┌────┴────┐  ┌─────┴────┐  ┌───────┴─┐
│Validation│  │ Access  │  │ Content  │  │ Caching │
│Directive │  │ Control │  │Formatting│  │Directive│
└──────────┘  │Directive│  │Directive │  └─────────┘
              └─────────┘  └──────────┘

3.3 컴포넌트 책임

컴포넌트 책임 주요 메서드
SemanticDirective 지시사항 정의 execute(), getPriority()
DirectiveContext 실행 환경 정보 제공 getAttribute(), setAttribute()
DirectiveRegistry 지시사항 관리 register(), getDirective()
DirectiveProcessor 지시사항 실행 execute(), executeSequence()
DocumentService 비즈니스 로직 조정 applyDirectives()

4. 활용 샘플 (Usage Example)

4.1 기본 사용 예제

4.1.1 문서 생성

curl -X POST http://localhost:8080/api/documents \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Spring Boot 3.3 가이드",
    "content": "Spring Boot는 엔터프라이즈 애플리케이션 개발을 간편하게 해줍니다.",
    "author": "Kim GracefulSoul"
  }'

# 응답:
{
  "id": 1,
  "title": "Spring Boot 3.3 가이드",
  "content": "Spring Boot는...",
  "author": "Kim GracefulSoul",
  "status": "DRAFT",
  "createdAt": 1717233000000,
  "updatedAt": 1717233000000
}

4.1.2 문서에 지시사항 적용

curl -X POST http://localhost:8080/api/documents/1/apply-directives \
  -H "Content-Type: application/json" \
  -d '{
    "directives": ["validation", "access-control", "content-formatting"],
    "userId": "admin"
  }'

# 응답:
{
  "status": "SUCCESS",
  "results": {
    "validation": {
      "valid": true,
      "errors": {},
      "warnings": {}
    },
    "access-control": {
      "hasAccess": true,
      "userRoles": ["admin", "read", "write", "delete"],
      "requiredRoles": []
    },
    "content-formatting": {
      "formatted": "# Spring Boot 3.3 가이드\n\nSpring Boot는..."
    }
  },
  "executionTime": 45
}

4.1.3 특정 지시사항 직접 실행

curl -X POST http://localhost:8080/api/documents/directives/content-formatting/execute \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "admin",
    "parameters": {
      "content": "안녕하세요, Semantic Directive Binding입니다.",
      "formatType": "html"
    }
  }'

# 응답:
{
  "formatted": "<p>안녕하세요, Semantic Directive Binding입니다.</p>"
}

4.2 구현 예제

4.2.1 커스텀 지시사항 구현

@Slf4j
@Directive(
    name = "email-notification",
    description = "이메일 알림 발송",
    priority = 70
)
public class EmailNotificationDirective implements SemanticDirective {
    private static final String EMAIL = "email";
    private static final String SUBJECT = "subject";
    private static final String BODY = "body";

    @Override
    public String getName() {
        return "email-notification";
    }

    @Override
    public Object execute(DirectiveContext context, Map<String, Object> parameters) {
        String email = (String) parameters.get(EMAIL);
        String subject = (String) parameters.get(SUBJECT);
        String body = (String) parameters.get(BODY);

        log.info("Sending email to: {} with subject: {}", email, subject);

        Map<String, Object> result = new HashMap<>();
        result.put("status", "SENT");
        result.put("email", email);
        result.put("timestamp", System.currentTimeMillis());

        // 실제 이메일 발송 로직
        // emailService.send(email, subject, body);

        return result;
    }

    @Override
    public boolean isValid() {
        return true;
    }

    @Override
    public int getPriority() {
        return 70;
    }

    @Override
    public Map<String, String> getMetadata() {
        return Map.of(
            "category", "notification",
            "version", "1.0",
            "async", "true"
        );
    }
}

4.2.2 컨트롤러에서 사용

@Slf4j
@RestController
@RequestMapping("/api/documents")
@RequiredArgsConstructor
public class DocumentController {
    private final DocumentService documentService;
    private final DirectiveProcessor directiveProcessor;

    /**
     * 문서에 지시사항 적용
     */
    @PostMapping("/{id}/apply-directives")
    public ResponseEntity<DirectiveResult> applyDirectives(
            @PathVariable Long id,
            @RequestBody ApplyDirectivesRequest request) {
        
        // 비즈니스 로직
        DirectiveResult result = documentService.applyDirectives(
            id,
            request.getDirectives(),
            request.getUserId()
        );

        return ResponseEntity.ok(result);
    }

    /**
     * 특정 지시사항 직접 실행
     */
    @PostMapping("/directives/{directiveName}/execute")
    public ResponseEntity<Object> executeDirective(
            @PathVariable String directiveName,
            @RequestBody ExecuteDirectiveRequest request) {
        
        DirectiveContext context = DirectiveContext.builder()
                .contextId(UUID.randomUUID().toString())
                .userId(request.getUserId())
                .sourceType("rest-api")
                .build();

        try {
            Object result = directiveProcessor.execute(
                directiveName,
                context,
                request.getParameters()
            );
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.badRequest()
                .body(Map.of("error", e.getMessage()));
        }
    }
}

4.2.3 서비스에서의 활용

@Slf4j
@Service
public class DocumentService {
    private final DirectiveProcessor directiveProcessor;

    /**
     * 문서 발행 워크플로우
     */
    public Document publishWithValidation(Long documentId, String userId) {
        Optional<Document> docOpt = getDocument(documentId);
        if (docOpt.isEmpty()) {
            throw new IllegalArgumentException("Document not found");
        }

        Document doc = docOpt.get();

        // 1단계: 컨텍스트 생성
        DirectiveContext context = DirectiveContext.builder()
                .contextId(UUID.randomUUID().toString())
                .userId(userId)
                .sourceType("publishing-workflow")
                .build();

        // 2단계: 지시사항 설정
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("content", doc.getContent());
        parameters.put("rules", "strict");

        // 3단계: 검증 지시사항 실행
        Map<String, Object> validationResult = (Map<String, Object>) 
            directiveProcessor.execute("validation", context, parameters);

        if (!(Boolean) validationResult.get("valid")) {
            throw new IllegalStateException("Validation failed");
        }

        // 4단계: 접근 제어 확인
        parameters.put("requiredRoles", Set.of("editor", "admin"));
        Map<String, Object> accessResult = (Map<String, Object>) 
            directiveProcessor.execute("access-control", context, parameters);

        if (!(Boolean) accessResult.get("hasAccess")) {
            throw new SecurityException("Access denied");
        }

        // 5단계: 문서 발행
        doc.setStatus("PUBLISHED");
        doc.setUpdatedAt(System.currentTimeMillis());
        
        return doc;
    }
}

5. 주요 코드 해석 (Key Code Explanation)

5.1 DirectiveRegistry 상세 분석

@Slf4j
@Component
public class DirectiveRegistry {
    // 지시사항을 스레드 안전하게 관리
    private final Map<String, SemanticDirective> directives = new ConcurrentHashMap<>();

    /**
     * 지시사항 등록 (커스텀 지시사항도 추가 가능)
     */
    public void register(SemanticDirective directive) {
        if (!directive.isValid()) {
            log.warn("Invalid directive: {}", directive.getName());
            return;
        }
        directives.put(directive.getName(), directive);
        log.info("Directive registered: {} (priority: {})",
                directive.getName(), directive.getPriority());
    }

    /**
     * 우선순위 순서로 모든 지시사항 반환
     * 높은 우선순위부터 먼저 실행됨
     */
    public List<SemanticDirective> getDirectivesByPriority() {
        return directives.values().stream()
                .sorted(Comparator.comparingInt(SemanticDirective::getPriority).reversed())
                .collect(Collectors.toList());
    }
}

주요 특징:

  • ConcurrentHashMap: 멀티스레드 환경에서 안전한 동시 접근
  • 우선순위 기반 정렬: 실행 순서를 명확히 정의
  • 검증 로직: 무효한 지시사항 등록 방지

5.2 DirectiveProcessor 상세 분석

@Slf4j
@Component
public class DirectiveProcessor {
    private final DirectiveRegistry registry;

    /**
     * 다중 지시사항 순차 실행
     * 에러 발생 시에도 계속 실행 (Fail-Over)
     */
    public Map<String, Object> executeSequence(List<String> directiveNames,
                                                DirectiveContext context,
                                                Map<String, Object> parameters) {
        Map<String, Object> results = new HashMap<>();

        for (String directiveName : directiveNames) {
            try {
                Object result = execute(directiveName, context, parameters);
                results.put(directiveName, result);
                log.debug("Directive executed successfully: {}", directiveName);
            } catch (Exception e) {
                log.error("Failed to execute directive: {}", directiveName, e);
                // 에러를 기록하지만 계속 진행
                results.put(directiveName, Map.of("error", e.getMessage()));
            }
        }

        return results;
    }

    /**
     * 조건부 실행
     * 특정 조건을 만족하는 지시사항만 실행
     */
    public Map<String, Object> executeWithPredicate(DirectiveContext context,
                                                     Map<String, Object> parameters,
                                                     Predicate<SemanticDirective> predicate) {
        return registry.getAllDirectives().stream()
                .filter(predicate)
                .sorted(Comparator.comparingInt(SemanticDirective::getPriority).reversed())
                .collect(HashMap::new,
                    (map, directive) -> {
                        try {
                            Object result = directive.execute(context, parameters);
                            map.put(directive.getName(), result);
                        } catch (Exception e) {
                            map.put(directive.getName(), Map.of("error", e.getMessage()));
                        }
                    },
                    Map::putAll
                );
    }
}

주요 특징:

  • Fail-Over: 한 지시사항 실패 시에도 계속 실행
  • 람다 기반 조건 처리: 함수형 프로그래밍 활용
  • 에러 핸들링: 예외를 결과에 포함시켜 추적 가능

5.3 ValidationDirective 상세 분석

@Slf4j
@Directive(
        name = "validation",
        description = "콘텐츠 유효성 검증",
        priority = 100  // 가장 높은 우선순위 (가장 먼저 실행)
)
public class ValidationDirective implements SemanticDirective {

    @Override
    public Object execute(DirectiveContext context, Map<String, Object> parameters) {
        String content = (String) parameters.get("content");
        String rules = (String) parameters.getOrDefault("rules", "basic");

        log.info("Validating content with rules: {} in context: {}", 
                 rules, context.getContextId());

        Map<String, Object> validationResult = new HashMap<>();
        validationResult.put("valid", true);

        // 규칙 수준에 따라 다른 검증 수행
        switch (rules) {
            case "strict" -> performStrictValidation(content, validationResult);
            case "medium" -> performMediumValidation(content, validationResult);
            default -> performBasicValidation(content, validationResult);
        }

        return validationResult;
    }

    private void performStrictValidation(String content, Map<String, Object> result) {
        // 1. 기본 검증
        performMediumValidation(content, result);
        
        // 2. 문자 유효성 검증
        if (content != null && !content.matches(".*[가-힣a-zA-Z0-9].*")) {
            result.put("valid", false);
            result.put("errors", Map.of("content", "유효하지 않은 문자 포함"));
        }
    }
}

주요 특징:

  • 우선순위 100: 다른 지시사항보다 먼저 실행
  • 확장 가능한 검증 로직: 규칙별 다른 검증
  • 정상적인 인터페이스 응답: 모든 검증 결과를 맵으로 반환

6. 유사 기술 비교 (Comparison with Similar Technologies)

6.1 Spring AOP (Aspect-Oriented Programming)

개념

Spring AOP는 횡단 관심사(Cross-Cutting Concerns)를 분리하여 모듈성을 향상시키는 기법입니다.

예시 코드

@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.directives.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        log.info("Method called: {}", joinPoint.getSignature());
    }

    @After("execution(* com.example.directives.service.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        log.info("Method finished: {}", joinPoint.getSignature());
    }
}

비교 분석

항목 Semantic Directive Binding Spring AOP
목적 동적 지시사항 실행 횡단 관심사 분리
실행 시점 명시적 호출 자동 인터셉션
확장성 런타임 지시사항 추가/제거 컴파일 타임 정의
학습곡선 낮음 중간
성능 약간의 오버헤드 최소 오버헤드
사용 사례 CMS, API 게이트웨이 로깅, 트랜잭션 관리
유연성 매우 높음 높음

장단점

Semantic Directive Binding의 장점:

  • ✅ 런타임 동적 구성
  • ✅ 사용자 정의 지시사항 쉬운 추가
  • ✅ 명시적이고 이해하기 쉬운 코드
  • ✅ 컨텍스트 기반 유연한 처리

Semantic Directive Binding의 단점:

  • ❌ 명시적 호출 필요
  • ❌ 비즈니스 로직과 혼재
  • ❌ 약간의 성능 오버헤드

Spring AOP의 장점:

  • ✅ 자동 적용
  • ✅ 비즈니스 로직 분리
  • ✅ 최소 성능 오버헤드
  • ✅ 선언적 설정

Spring AOP의 단점:

  • ❌ 컴파일 타임 정의
  • ❌ 동적 추가/제거 어려움
  • ❌ 학습곡선이 가파름

6.2 Chain of Responsibility 패턴 vs Semantic Directive Binding

Chain of Responsibility 예시

public abstract class Handler {
    protected Handler nextHandler;

    public abstract void handle(Request request);

    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }
}

public class ValidationHandler extends Handler {
    @Override
    public void handle(Request request) {
        if (isValid(request)) {
            if (nextHandler != null) {
                nextHandler.handle(request);
            }
        }
    }
}

public class AuthenticationHandler extends Handler {
    @Override
    public void handle(Request request) {
        if (isAuthenticated(request)) {
            if (nextHandler != null) {
                nextHandler.handle(request);
            }
        }
    }
}

비교 분석

항목 Semantic Directive Binding Chain of Responsibility
구조 중앙 집중식 분산식 (체인)
우선순위 명시적 우선순위 체인 순서
분기 처리 쉬움 복잡함
조건부 실행 직관적 복잡함
메모리 사용 적음 중간
확장성 높음 중간

활용 시나리오

Semantic Directive Binding 추천:

  • 다양한 지시사항을 조합해야 할 때
  • 지시사항 순서가 자주 변할 때
  • 조건부 실행이 필요할 때
  • 우선순위 기반 처리가 필요할 때

Chain of Responsibility 추천:

  • 선형 처리 흐름이 있을 때
  • 각 핸들러가 독립적일 때
  • 메모리가 제한적일 때

6.3 Strategy 패턴 vs Semantic Directive Binding

Strategy 패턴 예시

public interface SortingStrategy {
    void sort(int[] array);
}

public class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Quick sort implementation
    }
}

public class Sorter {
    private SortingStrategy strategy;

    public Sorter(SortingStrategy strategy) {
        this.strategy = strategy;
    }

    public void sort(int[] array) {
        strategy.sort(array);
    }
}

비교 분석

항목 Semantic Directive Binding Strategy Pattern
목적 다중 지시사항 처리 알고리즘 선택
개수 여러 개 동시 실행 하나만 선택
조합 자유로운 조합 선택만 가능
컨텍스트 풍부한 컨텍스트 최소 컨텍스트
복잡도 중간 낮음

6.4 Interceptor 패턴 (필터) vs Semantic Directive Binding

Interceptor 예시

@Component
public class LoggingInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                            HttpServletResponse response, 
                            Object handler) throws Exception {
        log.info("Request: {}", request.getRequestURI());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, 
                               HttpServletResponse response, 
                               Object handler, 
                               Exception ex) throws Exception {
        log.info("Response status: {}", response.getStatus());
    }
}

비교 분석

항목 Semantic Directive Binding Interceptor
실행 시점 비즈니스 로직 HTTP 요청/응답
적용 범위 도메인 로직 웹 계층
제어 명시적 선언적
유연성 높음 제한적

7. 실전 비교 표

기술 선택 가이드

┌─────────────────────────────────────────────────────────────────┐
│                 기술 선택 의사결정 매트릭스                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│ 요구사항: 동적 지시사항 실행, 복잡한 로직 조합                        │
│ → Semantic Directive Binding ⭐⭐⭐⭐⭐                      │
│                                                                 │
│ 요구사항: 횡단 관심사 분리 (로깅, 트랜잭션)                           │
│ → Spring AOP ⭐⭐⭐⭐⭐                                       │
│                                                                 │
│ 요구사항: 선형 처리 체인                                           │
│ → Chain of Responsibility ⭐⭐⭐⭐                            │
│                                                                 │
│ 요구사항: 단일 알고리즘 선택                                        │
│ → Strategy Pattern ⭐⭐⭐⭐⭐                                 │
│                                                                 │
│ 요구사항: HTTP 요청/응답 처리                                      │
│ → Interceptor Pattern ⭐⭐⭐⭐⭐                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

8. 성능 최적화 (Performance Optimization)

8.1 캐싱 지시사항 활용

@PostMapping("/{id}/apply-directives")
public ResponseEntity<DirectiveResult> applyDirectivesWithCache(
        @PathVariable Long id,
        @RequestBody ApplyDirectivesRequest request) {
    
    String cacheKey = id + ":" + String.join(",", request.getDirectives());
    
    Map<String, Object> cacheParams = new HashMap<>();
    cacheParams.put("cacheKey", cacheKey);
    cacheParams.put("cacheTTL", 5 * 60 * 1000); // 5분

    DirectiveContext context = DirectiveContext.builder()
            .contextId(UUID.randomUUID().toString())
            .userId(request.getUserId())
            .sourceType("rest-api")
            .build();

    Map<String, Object> cacheResult = (Map<String, Object>) 
        directiveProcessor.execute("caching", context, cacheParams);

    if ((Boolean) cacheResult.get("hit")) {
        // 캐시 히트
        return ResponseEntity.ok((DirectiveResult) cacheResult.get("value"));
    }

    // 캐시 미스 - 지시사항 실행
    DirectiveResult result = documentService.applyDirectives(
        id, 
        request.getDirectives(), 
        request.getUserId()
    );

    return ResponseEntity.ok(result);
}

8.2 병렬 처리

@Service
public class ParallelDirectiveService {
    private final DirectiveProcessor directiveProcessor;
    private final ExecutorService executorService;

    public ParallelDirectiveService(DirectiveProcessor directiveProcessor) {
        this.directiveProcessor = directiveProcessor;
        this.executorService = Executors.newFixedThreadPool(4);
    }

    /**
     * 독립적인 지시사항을 병렬로 실행
     */
    public Map<String, Object> executeParallel(
            List<String> directives,
            DirectiveContext context,
            Map<String, Object> parameters) {
        
        List<CompletableFuture<Map.Entry<String, Object>>> futures = 
            directives.stream()
                .map(directiveName -> CompletableFuture.supplyAsync(() -> {
                    try {
                        Object result = directiveProcessor.execute(
                            directiveName,
                            context,
                            parameters
                        );
                        return Map.entry(directiveName, result);
                    } catch (Exception e) {
                        return Map.entry(
                            directiveName, 
                            Map.of("error", e.getMessage())
                        );
                    }
                }, executorService))
                .toList();

        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
            .join();
    }
}

9. 테스트 (Testing)

9.1 단위 테스트

@SpringBootTest
class DirectiveRegistryTest {
    @Autowired
    private DirectiveRegistry directiveRegistry;

    @Test
    void testDirectiveRegistration() {
        ValidationDirective directive = new ValidationDirective();
        directiveRegistry.register(directive);

        assertThat(directiveRegistry.contains("validation")).isTrue();
        assertThat(directiveRegistry.size()).isGreaterThan(0);
    }

    @Test
    void testGetDirectivesByPriority() {
        List<SemanticDirective> directives = 
            directiveRegistry.getDirectivesByPriority();

        // 우선순위 순서 확인
        for (int i = 0; i < directives.size() - 1; i++) {
            assertThat(directives.get(i).getPriority())
                .isGreaterThanOrEqualTo(directives.get(i + 1).getPriority());
        }
    }
}

9.2 통합 테스트

@SpringBootTest
class DocumentServiceIntegrationTest {
    @Autowired
    private DocumentService documentService;

    @Autowired
    private DirectiveRegistry directiveRegistry;

    @Test
    void testApplyDirectivesToDocument() {
        // 문서 생성
        Document doc = documentService.createDocument(
            "테스트 문서",
            "테스트 콘텐츠",
            "테스터"
        );

        // 지시사항 적용
        DirectiveResult result = documentService.applyDirectives(
            doc.getId(),
            List.of("validation", "access-control"),
            "admin"
        );

        assertThat(result.getStatus()).isEqualTo("SUCCESS");
        assertThat(result.getResults()).containsKeys("validation", "access-control");
    }
}

10. 결론 및 권장사항 (Conclusion & Recommendations)

10.1 메타지침 바인딩 기술의 강점

동적 구성: 런타임에 지시사항을 추가/제거/변경 가능
확장성: 새로운 지시사항을 쉽게 추가 가능
명확성: 비즈니스 로직이 명확하게 표현됨
재사용성: 지시사항을 여러 곳에서 재사용 가능
테스트 용이: 각 지시사항을 독립적으로 테스트 가능

10.2 주의사항

⚠️ 성능: 리플렉션 기반이므로 성능 모니터링 필요
⚠️ 복잡도: 과도한 사용 시 디버깅이 어려워질 수 있음
⚠️ 학습곡선: 팀원들의 학습 필요

10.3 활용 시 체크리스트

  • 동적 지시사항이 정말 필요한가?
  • 팀의 기술 스택과 맞는가?
  • 성능 요구사항을 만족하는가?
  • 적절한 에러 핸들링을 구현했는가?
  • 로깅과 모니터링을 충분히 했는가?
  • 문서화가 충분한가?
  • 테스트 커버리지가 충분한가?

참조 (References)

※ Sample Code는 여기에서 확인 가능합니다.

댓글남기기