엔티티에 롬복 활용하기


#엔티티 멤버들 선언 위치 (자바 코드 규약)

Java static code analysis: The members of an interface or class declaration should appear in a pre-defined order

  • 오라클에서 정의한 클래스의 멤버들 선언 순서는 아래와 같다.

    • 클래스 변수 → 인스턴스 변수 → 생성자 → 메서드
  • 예시

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comment extends BaseEntity {

    @Id
    @GeneratedValue
    @Column(name = "comment_id")
    private Long id;

    private String content;

    private int depth;

    private Long bundleId;

    private Long bundleOrder;

    private boolean existsCheck;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "post_id")
    private Post post;

    @Builder
    public Comment(String content, int depth, Long bundleId, Long bundleOrder, boolean existsCheck, User user, Post post) {
        this.content = content;
        this.depth = depth;
        this.bundleId = bundleId;
        this.bundleOrder = bundleOrder;
        this.existsCheck = existsCheck;
        this.user = user;
        this.post = post;
    }

    public void updateComment(String content){
        this.content = content;
    }

    public void removeComment(){
        this.existsCheck = false;
    }
}

#엔티티에서 롬복 활용

@Data 지양

  • 많은 기능을 지원해주지만 지양하고자 하는 Setter를 포함하고 있다.

  • 또한 ToString으로 인한 순환참조 문제가 발생할 수 있다.

@Setter 지양

  • 도메인주도 개발관점에서 보면 애그리거트의 일관성을 깨트리는 주요 원인이다.
    즉 애그리거트의 내부 상태의 변경은 애그리거트 루트 객체 내에 응집되게 존재해야 한다.

  • setXXX 메서드는 중요 도메인의 의미나 의도를 표현하지 못한다.

  • 도메인 로직이 도메인 객체가 아닌 표현, 응용 계층으로 분산되게 되고, 코드를 유지보수 하는데 많은 리소스가 낭비된다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)

  • 디폴트 생성자를 자동으로 생성해주는 어노테이션이다.

  • 디폴트 생성자가 필요한 이유는 JPA에서 지연로딩 사용시 프록시 객체가 필요하기 때문이다.
    이 프록시 객체는 실제 엔티티를 상속받아서 만들어야 한다. 즉 상속을 받기 위해서는 상위 클래스의 디폴트생성자를 하위클래스에서 호출할 수 있어야 하기 때문에 생성자가 필요하다.

  • 접근권한은 최소화 할수록 좋다. Protected면 프록시 객체 생성에 문제없다. (무분별한 객체 생성 방지)

  • 추가로 아무 생각없이 @AllArgsConstructor를 썼는데 이는 모든 필드를 가지는 생성자를 생성해주는데 아마 필요한 경우는 거의 없을 것이라 생각된다. (자동생성되는 PK값이 존재하기 때문에)
    즉 필요한경우가 아니면 쓰지말자.

@Builder

  • 해당 어노테이션을 클래스 레벨에서 사용할지, 메서드(생성자) 레벨에서 사용할지 고민했었다.

  • 생성자에 @Builder를 선언하는게 낫다는 결론을 내렸다.

    1. 클래스 레벨에서 사용할 경우 @AllArgsConstructor와 마찬가지로 모든 필드에 대해 파라미터를 받는 생성자를 만든다. 자동생성되는 PK값이나 Auditing으로 자동 생성되는 createDate, lastModifiedDate 값이나 넘겨받을 필요가 없는 데이터에 대해서도 값을 받을 수 있다. 이는 휴먼에러를 유발할 수 있다.

    2. 클래스 레벨에서 사용할 경우 @AllArgsConstructor가 강제된다. 빌더를 이용해 마지막에 build() 시 모든 필드가 존재하는 생성자를 호출하기 때문에 @AllArgsConstructor가 없다면 오류가 발생한다.

  • 생성자에 @Builder 어노테이션을 선언해서 사용하는걸 지향하자.
💡 개발에는 정답이 없다. 즉 위 내용은 정답이 아니고 나의 주관적인 생각이다.

좋은 웹페이지 즐겨찾기