JPA 프로젝트를 수행하는 도중 특정 Entity 에 대한 DTO 를 update, save 등의 케이스마다 클래스를 분류하면 너무 많은 클래스가 생길거란 생각이 들었다. 따라서 1개의 클래스 내부에 관련된 DTO 를 Record 로 생성하는 방식을 채택하였다.
다음은 Post DTO 를 save, update 하는 request 와 response 를 record 로 저장한 PostDto 클래스이다.
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
public class PostDto {
public record SaveRequest(
@NotNull
String title,
@NotNull
String content,
Long userId
) {
}
public record UpdateRequest(
@NotNull
Long id,
@NotNull
String title,
@NotNull
String content,
Long userId
) {
}
public record CheckingIdResponse(
Long id
) {
}
public record Response(
Long id,
String title,
String content,
UserDto.Response user,
LocalDateTime createdAt,
LocalDateTime updatedAt,
String createdBy
) {
}
}
여기서 3가지(+1) 피드백을 받게 되었다.
1. nested class 는 static 선언을 통해 외부 클래스와 불필요한 참조를 제거하라
2. static 사용 시 생성된 객체는 gc 에 의해 회수 되지 않아 문제가 발생한다.
3. 생명주기가 다르다.
4. 그외에도 static 은 객체지향적이지 않고 캡슐화에 맞지 않지만, DTO 특성상 사용가능하다 판단하였습니다
하지만 여러 소스를 찾아보니 굉장히 흥미로운 부분들을 찾을 수 있었다.
You can declare instance methods in a record class, independent of whether you implement your own accessor methods. You can also declare nested classes and interfaces in a record class, including nested record classes (which are implicitly static).
다음 글에서 우리는 record 내부에 nested record 클래스를 선언하면 내재적으로 static 하게 선언되는 것을 확인할 수 있다.
Java Language Updates_15_Record
Java8 부터는 permenent 영역이 없어지고 metaspace 가 생겼다. 기존에 perment 영역에 저장되는 sattic object 는 heap 영역에 저장되도록 병경되었다. 그렇기 때문에 참조를 잃은 static object 는 GC 의 대상이 될수 있다.
Java8부터는 static이 heap영역에 저장된다?
static은 프로그램 실행 시점에 메모리에 할당을 하며, 웬만하면 프로그램 종료 시점까지 메모리에서 해제되지 않는다. 따라서 외부 클래스와 생명주기가 다르다는 특징이 가지며 이런경우 굳이 내부 클래스를 이용해야 하는가에 대한 지적이 있었다.
2가지 소스를 통해 nested record 사용시 받은 피드백들이 해결이 될 수 있다고 생각한다. 하지만 실제로 Java8 부터 참조를 잃은 static 객체가 GC 의 대상이 되는지 예외적인 조건은 없는지에 대해서는 좀 더 깊이 있게 공부를 할 필요성을 느낀다. 또한 궁극적으로 nested record 를 사용하는 코드가 좋은 코드일지 좀더 개선 가능한 코드가 존재하는지에 대해서도 고민해 보고 싶다.
https://unabated.tistory.com/entry/%EC%99%9C-%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-static%EC%9D%98-%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%A7%80%EC%96%91%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80
https://docs.oracle.com/en/java/javase/15/language/records.html
https://jgrammer.tistory.com/144