0. 목차

  1. 개요
  2. 직면한 문제
  3. 첫 번째 구현: Chain of Responsibility 패턴 적용
  4. 첫 번째 구현의 문제점
  5. 두 번째 구현: 서비스 레벨의 방어 로직
  6. 두 번째 구현의 문제점
  7. 세 번째 구현: recorder 초기화 로직의 이동
  8. 세 번째 구현의 문제점
  9. 네 번째 구현: 체인 형식의 support 검증
  10. 결론

1. 개요

사내 업무 효율성 증진을 위해 펌웨어 검증을 자동화하는 프로그램을 만들 기회가 있었습니다. 이 글은 검증 자동화 툴을 만드는 과정에서 고민했던 Validation 로직을 다룹니다. 여러가지 검증 시나리오를 각각의 책임에 따라 검증하는 다수의 Validators 구현체들의 구현 책임을 위임하는 방식에서 맞닿뜨렸던 문제점과 해결 방안을 소개합니다.

2. 직면한 문제

ValidationService는 다음과 같이 다수의 validators를 갖고 있으면서 요청에 따라 해당 validators에게 validation 로직 역할을 위임하여 결과 값을 받는 책임을 갖고 있습니다.

문제는 validateTemplate 메서드와 같이 다수의 Template을 받을 경우 해당 템플릿에 맞는 Validator가 해당 템플릿을 받아 validation로직을 수행하도록 해야하므로 다음과 같이 2중 반복문이 발생하게 된다는 것입니다.

@Service
public class SimpleValidationService implements ValidationService {

    private final List<Validator> validators;

// ...

    @Override
    public void validateMultipleTemplates(List<Event> events, List<Template> templates) {
        templates.forEach(template -> validators.stream()
                .filter(validator -> validator.supports(template))
                .findFirst()
                .orElseThrow(() -> new ValidatorNotFoundException(template.getInitialAction().getName()))
                .given(template)
                .whenTestedWith(events)
                .thenValidate());
    }
}

메서드를 다음과 같이 분리해볼 수는 있으나 여전히 이중 반복문이 발생합니다. 코드 상으로도 복잡하고 n^2의 시간 복잡도로서 효율성에서 개선이 필요해보입니다.