[Spring] 제대로 된 CRUD - Update

건도리 ·2023년 7월 20일
0

Spring

목록 보기
10/12
post-thumbnail

개요

호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS) 를 보며 학습한 내용을 정리하기 위해서 포스팅을 진행합니다. 이번 포스팅에서는 CRUD에서 수정을 의미하는 UPDATE 기능에 대해 서술해보도록 하겠습니다.

예시 코드

첫번째 안좋은 예시

// Post.java
@Setter
...
public class Post {
	private String title;
	private String content;
}

// PostService.java
public void Edit(Long id, PostEdit postEdit){
	Post post = postRepository.findById(id)
		.orElseThrow(() -> new IllegalArgumentStatement("존재하지 않는 아이디"));

	post.setTitle(postEdit.getTitle());
	post.setContent(postEdit.getContent());

	...
}
	

Post 도메인 클래스에 @Setter 어노테이션을 추가하여 Setter 메소드를 통해 내용을 수정하는 코드입니다.

개발에서 @Setter를 사용하는 것을 지양하는데 이유는 다음과 같습니다.

  • 캡슐화 위반 : 객체의 내부 상태를 외부에서 직접 변경하는 것은 캡슐화 원칙에 위배됩니다.
  • 불변성 : 필드가 불변성을 가져야 하는데 Setter 메소드를 통해 해당 불변성이 깨질 수 있습니다.

쉽게 설명하자면 악의적인 사용자가 Setter 메소드를 이용해 자신이 원하는 값으로 데이터를 수정할 수 있으며 이는 굉장히 큰 문제를 야기할 수 있습니다. 따라서 위와 같은 코드를 사용해서는 안됩니다.

두번째 안좋은 예시

// Post.java
public class Post {
	...

	public void change(String title, String content) {
		this.title = title;
		this.content = content;
	}
}

// PostService.java
public void Edit(Long id, PostEdit postEdit){
	Post post = postRepository.findById(id)
		.orElseThrow(() -> new IllegalArgumentStatement("존재하지 않는 아이디"));

	post.change(postEdit.getTitle(), postEdit.getContent());
	
	...
}

위 예제에서는 change() 로 넘겨주는 매개변수의 순서가 정해져있습니다. 두 개의 필드라 단순해 보이지만, 만약 10개가 넘는 필드가 있다면 어떨까요? 필드의 순서에 맞춰 값을 넘기다보면 실수가 발생할 수 있습니다. 그리고 해당 실수는 컴파일에 아무런 문제가 없기 때문에 문제를 발견하기 더 힘들어집니다.

좋은 예시

// Post.java
public PostEditor.PostEditorBuilder toEditor() {
	return PostEditor.builder()
						.title(title)
						.content(content);
}

public void edit(PostEditor postEditor){
	this.title = postEditor.getTitle();
	this.content = postEditor.getContent();
}

// PostEditor.java
public class PostEditor {
	private final String title;
	private final String content;
	
	@Builder
	public PostEditor(String title, String content){
		this.title = title;
		this.content = content;
	}

// PostService.java
...
public void edit(Long id, PostEdit postEdit) {
	Post post = postRepository.findById(id)
								.orElseThrow(() -> new IllegalArgumentStatement());
	
	PostEditor.PostEditorBuilder editorBuilder = post.toEditor();

	PostEditor postEditor = editorBuilder.title(postEdit.getTitle())
											.content(postEdit.getContent())
											.build();

	post.edit(postEditor)

하지만 여전히 문제점이 존재합니다. 예를 들어, 사용자는 title만 수정하였으므로 프론트 단에서 수정된 title 값만 넘겨주었다고 가정해봅시다. content에는 null 이 들어갑니다. 따라서 이는 수정할 데이터만 보낼 것인지, 수정할 데이터를 포함한 모든 데이터를 보낼 것인지에 따라 로직이 변경될 수 있습니다.

대처 방안

if(postEdit.getTitle()!= null){
	editorBuilder.title(postEdit.getTitle());
}

if(postEdit.getContent()!= null) {
	editorBuilder.content(postEdit.getContent());
}

post.edit(editorBuilder.build());

만약 수정된 값만 넘어온다고 가정하면 위와 같이 null 여부를 확인하고 변경된 값에 대해서만 값을 넘겨주면 됩니다.

profile
배움이 즐거워요 ! 함께 그 즐거움을 나눴으면 좋겠습니다 :)

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

글 잘 봤습니다, 감사합니다.

답글 달기