테스트를 진행하면서 계속 이런식으로 Empty List일 때와 null일 때 두가지를 동시에 처리하고 있다.
이건 혹여나 문제가 생길까봐 테스트를 진행해본 것인데
빈 리스트일 때는 null처리를 하지 못하는 탓에
이런식으로 복잡하게 Null이거나 Empty List일 때 경우를 모두 포괄해서 예외처리를 했다.
이렇게 복잡하게 할 필요가 있을까?하는 의문이 들었다.
프로필 변경 API는 쓰임새가 생각보다 복잡하다.
여러가지 케이스를 다루는 탓에 매개변수도 많아졌다.
가령,
이런 식으로 굉장히 복잡하게 사용 케이스가 나뉜다.
각각의 케이스마다 클라이언트에게 어떻게 사용하면 좋을지를 전달하더라도
완벽하게 이해하길 바라기가 쉽지 않다...
그래서 클라이언트한테 "newImages로 추가할 게 없어도 EmptyList로 전달해주세요!" 라고 요청해도
제대로 지켜지지 않을 수 있겠다는 생각을 했다.
클라이언트 코드가 변경되면서 이를 잊어버릴 수도 있고...
위키백과에 따르면, 방어적 프로그래밍 개념은 다음과 같다.
예상치 못한 입력에도 한 소프트웨어가 계속적 기능 수행을 보장할 수 있도록 고안된 방어적 설계의 한 형태이다.
참고자료 : 방어적 프로그래밍(Defensive programming), 방어 코딩(defensive coding)
방어적 프로그래밍을 하지 않으면 다음과 같은 문제들이 생길 수 있다.
이에 대비하기 위해서
을 해야 한다.
지금 코드마다 이런식으로 null 체크를 하니 너무 복잡해졌다.
대신 Optional.ofNullable을 이용해보자.
ofNullable은 null이면 그냥 EmptyList를 반환하는 방식이다. 매개변수로 null을 받는다.
of는 null체크를 해서 null이면 NPE 예외를 던진다.
코드가 실제로 어떻게 동작하는지 확인해보자
null이어도 NPE가 발생하지 않고 count 0을 반환한다.
EmptyList일 때도 정상적으로 작동한다.
flatmap을 사용한 건 ofNullable이 List자체를 stream으로 만들기 때문에 그 Stream을 한겹 없애주려고 쓴 것이다.
long count = Optional.ofNullable(newProfileImages)
.stream() //Stream<List<ProfileImageRequest>>
.flatMap(List::stream) //Stream<ProfileImageRequest>> -->이런식으로 변경된다.
.filter(ProfileImageRequest::isMainPhoto).count();
StackOverflow를 검색을 해보니 Stream.ofNullable을 쓰면 stream()을 별도로 호출하지 않아도 바로 null이면 Empty 스트림을, null아 아니면 Stream을 만들어서 이 방식을 더 권장한다고 한다.