안전한 Record 사용을 위한 Wither 패턴 활용
- 레코드 클래스는 불변성을 위해 설계되었지만, 컬렉션 필드를 포함할 경우 내부 상태 변경 및 외부 노출로 인해 불변성이 쉽게 깨질 수 있습니다. 💥
- 레코드 내 컬렉션 필드에
addAll() 같은 메서드를 제공하면 내부 상태가 직접 변경되어 레코드의 불변성이 파괴되는 문제가 발생합니다. 🚫
- 레코드가 자동으로 생성하는 필드 접근 메서드(예:
comments())가 컬렉션 필드를 직접 반환하면, 외부 코드에 의해 내부 컬렉션이 수정될 수 있는 '노출된 가변성' 문제가 발생합니다. 🔓
- '위더 패턴'은 레코드의 불변성을 유지하면서 필드 값을 변경하는 것처럼 보이게 하는 방법으로, 기존 객체를 수정하는 대신 변경된 값을 가진 '새로운 레코드 객체'를 생성하여 반환합니다. 🔄
- 위더 패턴 메서드는 일반적으로
with[필드명] 형태로 명명되며, 새로운 객체를 반환함으로써 원본 객체의 불변성을 보장합니다. 🆕
- 수동으로 위더 패턴을 구현하면 반복적인 '보일러 플레이트' 코드가 많이 발생하여 개발 효율성을 저해할 수 있습니다. 📝
- Lombok의
@With 어노테이션은 위더 패턴 메서드 생성을 자동화하여 보일러 플레이트 코드를 줄여주는 유용한 도구입니다. ✨
- 하지만
@With 어노테이션은 컬렉션 필드에 대한 방어 로직(예: 방어적 복사)을 자동으로 제공하지 않아, 컬렉션의 불변성 유지에는 한계가 있습니다. ⚠️
- 안전한 레코드 사용을 위한 Lombok 전략은 다음과 같습니다: 레코드에
@With를 적용하고, 컬렉션 필드에 대해 Lombok이 생성한 with[컬렉션필드명] 메서드를 private으로 만듭니다. 🔒
- 이후,
withAdd[컬렉션아이템명]과 같은 사용자 정의 public 메서드를 구현하여, 새로운 요소를 받을 때 기존 컬렉션을 방어적으로 복사하고 새 요소를 추가한 후, private with[컬렉션필드명] 메서드를 활용해 새로운 레코드 객체를 반환합니다. 🛡️