-
Notifications
You must be signed in to change notification settings - Fork 2
Entity에서의 무분별한 Setter 사용 금지.
여러 블로그를 돌아다니며 JPA를 학습하던 와중, Entity에서 Setter를 사용하지 않을것을 권고하는 글을 보았다. 왜 사용하지 말라는 것인지 궁금하여 타 블로그와 강좌들을 보며 정리해보고자 한다.
영한님의 충고..
PM과 이 주제에 대하여 깊은 토론을 하며 세터를 사용하지 말라면, 어떻게 update 로직을 처리하는지 상당한 고민에 빠졌었다.
Controller단에서 GetDto를 반환받아 Dtd의 Setter를 사용하여 부분 수정 후, Service단에서 Dto를 가인수로 받아 Entity로 변환 후, Repository단의 메서드를 통해 수정을 해야할 것으로 생각하던 와 중, 그렇다면, HTTP 메서드인 PUT과 PATCH의 구분이 없어지는 것이 아닌가?
전체를 수정하는 것과 일부분을 수정하는 것은 엄청난 차이인데 필자가 생각했던 방식은 하나가 변경되든 모든게 변경되는 결국 전체 DTO를 받아 수정하는것이므로 PUT에 다를 바 없었다.
따라서 주변 기술블로그와 강좌를 통해 명쾌한 답변과 해결 방안을 모색해보았다.
복잡한 로직에서 setter를 사용하면 유지보수적인 측면에서 엄청난 손해를 본다고 한다. 수많은 패키지와 클래스 중에서 무분별하게, 그리고 최악의 경우 수만가지의 칼럼이 모두 바뀔 경우 하나하나 세터를 사용한다면 가독성 측면에서 엄청난 손해이자 참사이다. 복잡해지면 복잡해질수록 나도 모르는 사이 값들이 변경될 수 있다는 소리이다. 즉, 추적하기 어려운상황까지 다가갈 수 있으므로 이러한 대참사와 개발자의 실수를 방지하기위해 다들 Setter를 권고하지 않는 것이였다.
또한, @setter를 통한 set메서드는 단순히 set이기에, 의도를 파악하지 못할 수 있다.
따라서 Entity 클래스에서 수정이라는 기능을 원한다면, update 메소드를 따로 만들어 내부 로직으로 사용하고 Service단에서 update 메소드를 호출하는 방식이 훨씬 가독성이 올라가고 의도를 파악하기 쉽다는 것이다.
즉, 의미를 명쾌하게 알 수 있는 메서드 명을 통해 가독성을 높이며, 무분별한 사용을 방지할 수 있으며, 유지보수측면에서 엄청난 이득을 챙길 수 있는 것이다.
다음은 이러한 결론을 토대로 응용해본 코드이다.
- Entity
@NoArgsConstructor
@Getter
@Entity
public class HelloPost extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //기본키, 자동증가
private Long id;
@Column(nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
@ManyToOne //등업게시판은 오직 한명의 유저만이 작성할 수 있다.
private User user;
@Builder
public HelloPost(String title, String content, User user){
this.title = title;
this.content = content;
this.user = user;
}
public void update(String content){
this.content = content;
}
}
//Martin0o0 - Go! younhacom
b. Service
@RequiredArgsConstructor
@Service
public class HelloPostsService {
private final HelloPostRepository helloPostRepository;
@Transactional
public Long update(Long id, HelloPostsUpdateDto helloPostsUpdateDto){
HelloPost posts = helloPostRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당하는 게시글이 없다. No : " + id));
posts.update(helloPostsUpdateDto.getContent());
return id;
}
@Transactional
public Long modify(Long id, String content){
HelloPost post = helloPostRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당하는 게시글이 없다. No : " + id));
post.update(content);
return id;
}
}