LinkedIn

구체적인 Exception Catch를 해야하는 이유

2021. 4. 22. 00:25 | 자바 개발자되기

이전 회사 A에서는 서비스에서 발생할 수 있는 Custom Exception을 최대한 구체적으로 작성하였다.

 

이후 회사 B에서는 Exception을 최소한으로 분류하여 사용하고 있다.

 

무조건 '어떤 것이 옳다'는 없다.

 

다만 각각의 선택지마다 사이드 이펙트는 분명히 존재한다.

 

Custom Exception을 구체적으로 작성하여 사용하지 않았을 때 발생할 수 있는 문제 중 하나는 "공통" 처리로 인한 사이드 이펙트이다.


예제 코드

기존

public class BlackListChecker {
    public boolean isBlackList(final String ip) {
        try {
            IpLogger.log(new Ip(ip));
            // check blacklist
            if(blackList)
            {
            	return true;
            }
        } catch (final Exception e) {
            return false;
        }
        return false;
    }
}
  • 해당 ip가 블랙리스트인지 체크한다. 만약 블랙리스트라면 true, 아니면 false를 반환한다.
  • 처리 중 에러가 발생한다면 블랙리스트가 아닌 것으로 취급(false 반환)

 

시간이 지나 Exception이 발생하게 된다면 블랙리스트로 취급하도록 기준이 강화되었다고 생각해보자.

이후 기준 강화

public class BlackListChecker {
    public boolean isBlackList(final String ip) {
        try {
            IpLogger.log(new Ip(ip));
            // check blacklist
            if(blackList)
            {
            	return true;
            }
        } catch (final Exception e) {
            // 기준이 강화되어 에러가 발생한다면 안전하게 블랙리스트로 취급
            return true;
        }
        return false;
    }
}

 

예를 들기 위한 극단적인 코드이지만 기준이 강화된 이후 변경된 코드로 인해 블랙리스트가 아닌 ip에 대하여 블랙리스트로 취급되는 문제가 발생하였다.

 

열심히 디버깅하여 문제의 원인을 찾아보았다.

 

왜 문제가 발생하였을까?

 

문제는 아래와 같이 호출 된 코드이다.

blackListChecker.isBlackList("");

어떠한 이유가 됬든 IP로 전달되어야 할 인자 값에 blank string이 전달되었다.

이렇게 전달된 데이터로 인해 Ip 객체 생성 new Ip(ip) 에서 InvalidStringException이 발생하였다.

 

이 경우 블랙리스트로 판단하는 것이 맞을까?

물론 요구 사항에 따라 달라지겠지만 극단적으로 이 서비스에서는 ip가 blank string이면 블랙리스트가 아니어야 한다.

 

문제점

  • 블랙리스트인지 확인하는 코드에서 발생하는 Exception catch를 구체적으로 분류하지 않았다.
  • 그로 인해 예상치 못한 Exception raise(정상 처리로 반환했어야 할)가 발생하였을 때 의도하지 않은 결과가 반환되었다.

 

해결 방안

이 글은 Exception Catch를 구체적으로 나열하지 않고 공통된 하나의 Exception으로 다뤘을 때의 문제점을 전달하기 위해 작성하였다.

결론은 Exception Case를 구체적으로 분류하여 각각의 에러 상황에 개발자가 의도한 로직이 처리되도록 하는 것 이다.

public class BlackListChecker {
    public boolean isBlackList(final String ip) {
        try {
            IpLogger.log(new Ip(ip));
            // check blacklist
            if (blackList) {
                return true;
            }
        } catch (final InvalidStringException e) {
            // 인자로 전달 된 ip가 문제가된 경우 블랙리스트가 아님으로 취급
            return false;
        } catch (final Exception e) {
            // 기준이 강화되어 에러가 발생한다면 안전하게 블랙리스트로 취급
            return true;
        }
        return false;
    }
}

 

하지만 사실 아래와 같은 편법으로 작성할 때가 많기도 하다.

public class BlackListChecker {
    public boolean isBlackList(final String ip) {
        if(isInvalidString(ip)) {
            return false;
        }
        try {
            IpLogger.log(new Ip(ip));
            // check blacklist
            if(blackList)
            {
            	return true;
            }
        } catch (final Exception e) {
            // 기준이 강화되어 에러가 발생한다면 안전하게 블랙리스트로 취급
            return true;
        }
        return false;
    }
}
  • 인자로 전달된 ip(String)가 적절한 문자인지 확인