0. 목차

  1. 개요
  2. 문제점
  3. 개선 1 - 필수 여부, 스트링 길이
  4. 개선 2 - Enum 타입
  5. 더 완벽한 캡슐화를 위하여
  6. What remains...
  7. 결론

1. 개요

본 글은 사내 업무 효율성 향상을 목적으로 펌웨어 검증 과정을 자동화하기 위한 프로그램 개발 경험을 공유합니다. 특히, Payload 객체의 구현과 검증 로직 개발 과정에서 발생한 다양한 문제들과 이에 대한 해결 방안을 중심으로 논의합니다. 이 과정에서 여러 Payload 클래스들을 효과적으로 검증하는 방법에 대한 고민과 그 해결책을 제시하고자 합니다.

2. 문제점

먼저 28개의 클래스 중 하나인 ChangeSomethingPayload 클래스를 예시를 살펴보겠습니다.

해당 클래스는 Payload 클래스입니다. 요청과 응답을 규정하고 있는 클래스로서 필드는 OCPP1.6 프로토콜에서 정의한 내용을 포함하고 있습니다. 요청 페이로드는 key와 value 두 개의 필드를 가지고 있고, 두 필드 모두 필수값이면서 문자열 길이 50 이내라는 제한 사항을 갖고 있습니다. 한편 응답 페이로드는 status라는 하나의 필드를 가지고 있습니다. status는 설정 변경 요청에 대한 응답 상태를 나타내며, SomethingStatus라는 Enum 클래스의 값 중 하나여야 힙니다.

위와 같은 제약 조건에 대해 애노테이션을 사용하지 않고 검증 로직을 개별 클래스 내에 구현하는 경우 다음과 같은 코드를 작성할 수 있을 것입니다.

public class ChangeSomethingPayload extends Payload{
    private String key;
    private String value;

    @Override
    public boolean isValid() {
        return keyIsValid() && valueIsValid();
    }

    private boolean keyIsValid() {
        return key != null && !key.trim().isEmpty() && key.length() <= 50;
    }

    private boolean valueIsValid() {
        return value != null && !value.trim().isEmpty() && value.length() <= 50;
    }

    public static class Response extends Payload {
        private String status;

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

        private boolean statusIsValid() {
            return status != null && SomethingStatus.contains(status);
        }
    }
}

SomethingStatus Enum 은 다음과 같이 정의합니다.

public enum SomethingStatus {

    ACCEPTED("Accepted"),
    REJECTED("Rejected"),
    ...
    ;

    private final String value;

    public static boolean contains(String request){
        return Arrays.stream(values()).anyMatch(status -> status.getValue().equals(request.trim()));
    }
}

이렇게 구현할 경우 무엇이 문제일지 생각해 봅시다. 만약 Payload 클래스가 이것 하나라면 크게 문제될 일이 없을 것 같습니다. 그런데 이와 같은 Payload가 28개나 존재하며, 내부에 가진 클래스까지 더하면 그보다 훨씬 많은 수의 클래스가 존재한 상황입니다. 각각의 Payload는 비슷한 제약 조건, 즉 필수여부, 문자열 제한, Enum 타입 필드 등을 갖고 있기 때문에 중복되는 로직을 매번 복사 붙여넣기 해야하는 문제가 생깁니다.

결과적으로 각 필드의 유효성을 검사하는 로직이 클래스 내에 흩어져 있어 코드의 가독성이 떨어지고, 중복된 코드가 발생합니다. 만에 하나 필드의 유효성을 검사하는 조건이 변경된다면 어떨까요? 해당 필드를 검증하는 모든 코드를 찾아서 수정해야 합니다.