불변(immutable) 이란 인스턴스가 생성, 초기화 된 이후에 변하지 않음을 의미합니다.
JDK 21 에서 추가된 record 는 불변 객체를 만드는 가장 쉬운 방법입니다.
Lombok 라이브러리는 getter, setter, constructor 등 반복적으로 작성해야 하는 코드들을 애너테이션을 붙이기만 하면 자동 생성 해주는 편리한 라이브러리입니다.
하지만 편하다고 해서 Lombok 애너테이션을 남발하는 것은 좋지 않습니다.
사용하지 않는 코드를 생성하면서 컴파일 시간이 늘어나는 등의 부작용이 있을 수 있습니다.
⚠️ 그중 가장 치명적인 것은 @Setter 를 통해 불변성이 깨지는 부작용입니다.
어떤 경우에 불변성이 지켜져야 할까요?
웹 개발을 하면서 가장 많이 접하게 될 경우는 바로 DTO, Entity 입니다.
DTO(Data Transfer Object) 는 API 요청/응답 혹은 계층간에 데이터를 전달할 목적으로 사용됩니다.
클라이언트의 요청을 서버에서 임의로 변경해야 한다면 그것은 잘못 설계된 API 입니다.
서버는 캡슐화를 통해 스스로 처리할 수 있는 부분을 제외하고, 클라이언트가 제공해야 하는 부분만 노출해야 합니다.
(응답 DTO 는 응답하는 순간 서버가 불변성을 관리하지 않으니 제외)
계층간 데이터를 전달할 때에도 마찬가지입니다.
데이터를 전달하는 계층에서 완성된 데이터는 전달 받은 계층에서 변경되는 것을 원하지 않습니다.
정의한 인터페이스대로 불변 데이터를 넘겨주면, 변경되지 않는다는 보장과 함께 계층간의 결합도를 낮출 수 있습니다.
주로 JPA 를 사용할 때 사용하게 되는 Entity 객체는 반드시 불변이여야 하는 것은 아닙니다.
그러나 변경을 스스로 관리해야 하는 책임은 있습니다.
단순히 setter 를 열어둔다면 무결성이 파괴될 수 있습니다.
예를 들어 User entity 에 string 타입의 name 컬럼이 NOT NULL 제약조건이 있다고 해봅시다.
User 에 @Setter 를 붙인다면 user.setName(null) 이 Java 문법적으로는 아무런 문제가 되지 않습니다.
그러나 영속성 관리가 되는 시점에서 SQL Error 를 맞이하게 될 것입니다.
아마도 개발자는 이런 의도였을 겁니다.
user.clearName() 또는 user.isNameAvailable(false)
이렇게 의도가 명확한 메서드 이름과 함께 setter 접근을 막아두면,
필드 변경과 함께 지켜져야 하는 것들에 대해 Entity 자기 자신이 책임질 수 있습니다.
Lombok 은 분명히 개발 효율과 가독성을 높여주는 아주 유용한 라이브러리 입니다.
그러나 Lombok 애너테이션을 사용할 때에는 정말로 필요한 코드인지 한번더 생각하고,
특히 불변성이 지켜져야 하는 경우에는 @Setter 사용을 조심해야 합니다.
(@Data 애너테이션은 @Setter 를 포함합니다.)
계층간에 DTO 를 전달하다 보면 가공이 필요할 때가 있습니다.
예를 들면 성과 이름을 합쳐서 하나의 필드에 전달한다거나, 비즈니스 로직에서 다루어지지만 API 응답에서는 제외되어야 하는 민감한 정보들이 있습니다.
이것들을 제외하면 이전 계층에서 전달 받은 데이터와 다음 계층으로 넘겨줘야할 데이터의 구조가 거의 유사합니다.
계층간의 인터페이스가 다르기 때문에 여러개의 Record 가 만들어지는 것은 피할 수 없지만,
변경 과정에서 생성자 호출이 길어지는 것은 static 메서드를 만들어서 피할 수 있습니다.
User user = userRepository.getUserById(id);
UserResponse userResponse = new UserResponse(
user.id(),
user.lastName() + user.firstName(),
user.address(),
user.email(),
user.phone()
); // 너무 길다
return userResponse;
User user = userRepository.getUserById(id);
UserResponse userResponse = UserResponse.from(user); // 캡슐화
return userResponse;
가독성도 높이고 자기 자신을 생성하는 책임을 스스로 가지도록 합니다.