여태껏 진행했던 프로젝트들과 회사에서 진행하는 프로젝트의 가장 큰 차이점이 있다면 안정성, 가독성이라고 생각한다.
단순 기능 구현에 급급하지 않았는 지, 내부 코드를 확인해보기는 했는 지.. 부족한 부분이 많이 있었음을 깨닫고 있는 것 같다.
그 중에서 코드 리뷰를 많이 받았던 부분에 대해서 정리해보고자 한다.
개인적인 의견(코드 스타일)이다. 누군가는 가독성이 좋다고 느낄 수 있지만, 또 다른 누군가는 가독성이 오히려 좋지 않다고 느낄 수 있다. 그래서 정답이라기보다 하나의 생각을 정리한 글으로 인지했으면 좋겠다.
바로 Null , Empty에 관한 내용이다.
Null, Empty 체크를 하지 않았거나, 스스로 봤을 때도 가독성이 많이 떨어지는 코드를 많이 작성했다.
이 외에도 Default Configuration, Auto Configuration에 기대어 설정을 많이 했었다. 지금은 조금 나아졌다..
Multi Datasource / Elastic search의 인덱스, 샤드, 레플리카 / Kafka의 Producer , Consumer , Partition 설정 / 배포 환경 분리 등 다양한 부분에서 세부적인 설정을 위해 필수라는 것을 최근에 많이 느끼고 있다..
어떤 코드가 정답이라고 할 수는 없지만, 상황이나 의도에 효과적인 코드는 있을 수도 있는 것 같다.
특히 Empty와 Null 중에서 주의깊게 봤던 부분은 CollectionUtils(StringUtils 등 각종 유틸리티) , Optional.ofNullable, Optional<T>이다.
CollectionUtils.isEmpty()
우선 CollectionUtils에 대해 국한되는 내용은 아니다. StringUtils와 같은 각종 유틸리티에 대한 사용에 의미를 둔다.
CollectionUtils를 쓰지 않고, xxxList.isEmpty() 이런 식으로 사용하는 방법도 있다.
그러나 CollectionUtils내부 코드를 보면 다음과 같이 null과 empty를 동시에 체크한다.
이는 empty 뿐만 아니라 Null로 인해 발생할 수 있는 예외상황에 대해서도 처리할 수 있다는 장점을 갖는다.
하지만 나의 경우는 null 인 경우 빈 배열을 반환하고, null 이 아닌 경우는 해당 배열을 반환하고자 했기 때문에 개발 의도와 다소 맞지 않았다. (null 체크 목적을 갖고 있었음)
Optional<T>
Optional은 null 처리에 일반적으로 사용되는 방법들 중 하나이다.
orElseGet으로 null 값인 경우 다른 값을 반환하도록 사용할 수 있었으며, 아예 orElseThrow를 통해 다른 예외를 발생시킬 수도 있는 등, 다양한 기능을 제공한다.
그러나 Optional 값으로 다른 객체를 한번 더 감싼다는 점에서 오버헤드일 수 있다고 생각했다.(자세한 건 Profiling 해봐야 알 것 같다. 그리고 GC에서 단순 객체 참조는 크게 성능에 영향을 미치지 않는 것 같긴 하다..)
또한, List에 대한 null 체크를 하고자 했기때문에 Optional 내부에 List를 사용하는 경우에는 Optional.empty 타입을 반환하는 경우 동작 의도와 다르게 동작할 수 있다는 위험성이 존재했다.(null 값인 경우 Optional.empty 타입으로 넘어감)
Optional.ofNullable()
Optional.ofNullable()은 기본적으로 Optional<T>와 동일하게 동작한다.
Optional.ofNullable()은 Optional<T>에 비해 값이 null일 수 있는 상황에서 (개인적으로) 간결하고 명시적으로 null 처리를 할 수 있다는 장점을 갖는다.
그리고 Optional의 경우 각 변수마다 if( == null)을 통해서 체크할 필요가 없다는 점과, (개인적으로) 가독성이 좋고 Exception에 강건한 코드를 짤 수 있다는 점으로 인해 Optional.ofNullable()을 사용하여 구현하였다.
Optional.of는 null값이 들어가는 경우 NullPointerException이 발생한다
삼항 연산자
이 외에도 삼항 연산자를 사용하는 방법도 존재한다.
List<Data> dataList= (foundDataList == null) ?
Collections.emptyList() : foundDataList.stream().map(Data::toData).toList();
와 같이 쓸 수 있다. 그리고 적다보니 기억난 내용인데 Collections.emptyList()와 같은 정적 팩토리 메서드로 가독성과 메모리 효율성을 모두 챙기는 것에 대해서도 유용하게 사용하고 있다.
간단한 null 처리가 가능하며 오히려 더 간결해질 수 있다고 생각한다. 그러나 복잡한 null 처리 로직이나 예외 처리가 필요한 경우에는 Optional을 활용한 방법이 더 좋다고 생각한다.
물론 Optional 도 과도하게 사용하면 오히려 가독성이 떨어질 수 있다.
코드 스타일에는 정답이 없다고 생각한다. 팀원분들 성향이나 프로젝트의 의도에 따라 천차만별이다.
정답이 없지만, 프로젝트를 진행함에 있어 항상 안정성과 가독성이 좋은 코드를 짜기 위한 노력을 하는 것은 중요하다고 생각한다.
부족함을 인지하고 다양한 고민과 생각을 통해 더 발전할 수 있도록 노력해야겠다.
'백엔드 > 에러-예외 처리' 카테고리의 다른 글
Try with Resources / Try Finally (0) | 2024.05.06 |
---|---|
예외 VS 에러 (Java) (0) | 2023.06.22 |