일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 일상
- Java
- JPA
- Coputer Science
- proxyFactory
- Junit 5
- db
- backend
- Test code
- 인프콘2023
- FCM
- MySQL
- softeer
- modelmapper
- 테크쇼
- ObjectMapper
- mapstruct
- Spring
- JPQL
- 자바
- ExceptionResolver
- enumSet
- OS
- 소프티어
- Test
- Test Doulbe
- Server
- Service 계층 테스트
- RequestBody
- 공룡책
- Today
- Total
공부내용공유
Value object Null 값 처리하기 (feat: null object pattern) 본문
서론
value object 여러가지 장점이 있고 이를 잘 활용하면 응집도 높고 DRY한 코드를 작성할 수 있다. 그래서 나도 여러군데서 열심히 사용하려고 노력하였고 이 과정에서 여러 애매한 상황들을 많이 만났다, 오늘 글에서는 value object의 null 처리에 관해서 다룰 예정이다.
(지극히 개인적인 경험과 자료를 찾아보면서 제 생각등을 정리한 글이니 참고만 하고 반박 의견이 있다면 공유해주세요.)
본론
목차는
- value object의 null
- ObjectValue<Nullable> vs Nullable<ObjectValue>
- 상황에 맞게?
으로 구성될 예정이다.
Value Object의 null
객체지향적인 코드를 지향하면서 클래스를 만들고 사용하다보면 value object를 자주 사용하게 된다. 관련된 값들, 로직들을 모음으로 응집성을 높이고 책임을 명확히 하여 테스트 코드 작성을 더 용이하게 만들고 DRY한 코드를 작성할 수 있다는 점이 내게 굉장히 매력적으로 다가왔었다.
다만 사용하다가 이런 고민에 빠졌다.
class User {
private final String userName;
private final int age;
private final Address;
private final Email;
}
class Email {
private final String email;
}
이러한 유저 클래스가 있다고 해보자. 이름, 나이, 주소는 필수이지만 Email의 경우에는 필수가 아니다, 즉 nullable하다.
이러한 상황에서 난 고민에 빠졌다. User.Email == null
이 맞을까? 아니면 User.Email.email == null
이 맞을까?
여러 자료도 찾아봤고 사수님들한테도 의견을 구하고 많은 고민을 했다, 아직도 명확하지는 않지만 내용들을 간단히 정리하겠다.
ObjectValue<Nullable> vs Nullable<ObjectValue>
첫번째는 Email 의 String email
이 nullable한 경우이다.
이러한 식으로 설계하면 어떤 장점, 단점이 있을까?
public class Email {
private final String email;
public Email (String email) {
if(email == null) {
throw Exception();
}
validate(email);
this.email = email;
}
public String getEmail() {
if(email == null) {
//예외호출?
//빈값 전달?
}
return email;
}
private void validate(String email) {
//email 검증
}
}
이러한 Email 클래스가 있다고 하고 다양한 클래스들에서 사용되고 있다고 가정해보자. Email 클래스를 사용하는 클라이언트들은 값을 넣거나 사용할 때 별도의 null에 관한 걱정없이 사용해도 Email 내부에서 처리한다는 장점이 있다.
만약 null 처리가 없었다면
User user = repository.getUser();
if(user.email == null) {
throw new UserDoNotHaveEmailException();
}
//user.email 로 메일 보내기
Owner owner = repository.getOwner();
if(email != null) {
owner.updateEmail(email);
}
이렇게 값을 불러오든 값을 수정하든 null 처리를 각 클라이언트에서 해줘야 한다.
또 다른 케이스인 User가 Email 자체를 null로 갖는 케이스다. 이러한 방식으로 설계를 했을 때는 어떤 장점이 있을까??
class Email {
private final String email;
Email (String email) {
validate(email);
this.email = email;
}
public String getEmail() {
return email;
}
private void validate(String email) {
//email 검증
}
}
아까 다른 예시에서는 장점이었던 것이 단점이 될 수 있다. Email이라는 value object라면 순수히 email에 관한 로직만 가지고 있어야 하는데 각 메서드마다 null값이 들어가게 된다.
즉, Email 클래스 자체가 nullable하고 String email은 NotNull이라 하면 오로지 자신의 로직에만 집중을 할 수 있다는 장점이있다.
결국 상황에 따라 어떤 방식이 유리할지 달라지게 된다? 참 애매한 결론이다.. 그런데 이 주제에 관련해서 자신의 의견을 굉장히 잘 정리해 놓은 글을 발견했었다. (해당 내용에 대해 굉장히 정리를 잘해놓은 글이다.)
상황에 맞게?
해당 글의 결론만 빠르게 요약하면
Choose ValueObject<Nullable> over Nullable<ValueObject> when possible
(when the null/empty value makes sense in the context of the value object)
- This choice will help reduce the number of nulls you work with in your system
- The null object design pattern essentially advocates for this choice as well
"ValueObject<Nullable>이 너의 시스템에서 null 존재 자체를 많이 줄여주므로 문맥상 말이되면 사용하여라, 아니라면Nullable<ObjectValue>를 사용하여라" 이다.
문맥상 말이 된다는 것은 이를 테면 Money, Quantity와 같이 값이 없을 수 있는 것을 의미한다. 만약 Email, PhoneNumber라고 하면 그 안에 값이 없는 것은 논리적으로 말이 안된다.
어느정도 설득이 되는 의견이다, 다만 ValueObject<Nullable>
을 문맥상 값이 없어도 말이 되는 상황에 사용하라고 나와있는데 그러한 상황들을 떠올려 보면
class Money {
private final long money;
}
class LikeList {
private final List<Long> likeItemIds;
}
이러한 것들이 있는데 얘네들이 꼭 null 값으로 값이 없음을 표현해야 할까?
class Money {
private static final long VERY_VERY_POOR = 0;
priate final long money;
}
class LikeList {
private final List<Long> likeItemIds;
List<Long> getList() {
//null이 아니라 빈 리스트 반환.
}
}
위와 같이 많은 상황을 생각한건 아니지만 웬만한 상황에서 위와 같이 null이 아닌 그러한 값을 대신하는 무언가를 사용할 수 있다고 생각한다.
블로그의 글쓴이도 null object pattern를 소개하면서 이러한 방식을 추천하고 있다.
결론
상황에 따라 달라져야 하지만 이러한 자료들을 읽고 사용해보면서 null object pattern과 유사한 방식으로 null을 다른 값으로 표현하여 좀 더 도메인적인 부분을 드러낼 수 있는게 아니면 Nullable<ObjecValue>
를 사용하는게 나을 것 같다는 생각이다.
하지만 다른 케이스도 장점이 충분히 많다고 생각하기에 상황에 맞춰, 팀원과 잘 얘기하여 각자가 가진 장점을 잘 살리면 될 것 같다.
'Server > Java' 카테고리의 다른 글
Java Random, SecureRandom, RandomStringUtil 살펴보기 (0) | 2024.06.28 |
---|---|
java package private (feat : default 접근 제어자) (0) | 2024.06.09 |
java testFixture 는 어디에 둘까 (feat: package - private fixture) (0) | 2024.05.25 |
java, kotlin에서 null 처리 (0) | 2024.03.31 |
java hashMap 살펴보기 (feat: red black tree) (2) | 2024.03.15 |