나는 지금까지는 어떤 데이터를 삭제할 때 바로 delete를 실행하는 방식으로 처리해 왔다.
예를 들어 블로그 포스트를 삭제하거나 회원 정보를 삭제할 때, API를 통해 곧바로 데이터를 제거하는 식이었다.
이 방식은 흔히 Hard Delete라고 부르며, 말 그대로 데이터를 실제로 지워버리는 것이다.
DELETE FROM users WHERE id = 5;
Hard Delete는 DELETE SQL 문을 실행하거나 파일·데이터를 직접 제거하기 때문에, 삭제된 데이터는 데이터베이스에서 더 이상 조회할 수 없다. 별도의 백업이 없다면 복원도 불가능하다.
Hard Delete의 장점을 생각해 보면, 우선 삭제된 데이터가 DB에 남지 않기 때문에 용량 관리에 유리하다. 또한 회원을 조회할 때마다 is_deleted = false 같은 조건을 붙일 필요가 없어 쿼리가 단순해지고, 성능 관리 측면에서도 효율적이라는 장점이 있다.
하지만 단점도 분명하다. 데이터를 데이터베이스에서 완전히 제거하기 때문에, 잘못 삭제했을 경우 복구할 수 없다. 또 회원은 삭제를 원하더라도 서비스 입장에서는 모든 회원의 활동 이력이나 흔적을 남겨두는 것이 유용할 수 있다. 그러나 Hard Delete를 사용하면 해당 정보가 사라지기 때문에 이력 추적이나 감사 로그 관리가 어렵다는 문제가 생긴다.
예를 들어 회원 정보를 삭제한다고 해보자.
회원이 탈퇴를 원해서 삭제했는데, 며칠 뒤 다시 가입하고 싶어진다면 어떻게 될까?
기존 데이터를 복구할 수 없다면, 아예 새로운 유저로 등록할 수밖에 없다.
이런 상황에서 사용할 수 있는 방식이 바로 Soft Delete이다.
Soft Delete란?
Soft Delete란 데이터베이스나 시스템에서 실제로 데이터를 삭제하지 않고, 삭제된 것처럼 표시하는 방식을 말한다.
즉, 물리적으로 데이터를 제거하는 대신 is_deleted = true 같은 플래그나 deleted_at 같은 컬럼을 사용해 논리적으로 삭제 상태만 관리하는 것이다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private boolean isDeleted = false; // Soft Delete 플래그
public void delete() {
this.isDeleted = true;
}
}
위 예시를 보면 isDeleted라는 멤버 변수가 있다. 회원 삭제 API가 호출되면 서버는 실제 데이터를 제거하는 대신 isDeleted 값을 true로 바꾼다. 이렇게 하면 기존 회원의 정보는 DB에 그대로 남아 있으면서, 시스템에서는 삭제된 것처럼 동작하게 만들 수 있다.
UPDATE users SET is_deleted = TRUE WHERE id = 5;
여기서는 데이터를 실제로 삭제하는 것이 아니라 is_deleted 값을 true로 바꾸는 것이기 때문에, 실제 쿼리문은 DELETE 문이 아니라 회원 정보를 변경하는 UPDATE 문이 된다.
Soft Delete는 회원 정보를 바로 삭제하지 않음으로써 얻는 이점도 있지만, 단점도 분명하다.
우선 DB에 회원 정보가 계속 쌓이게 되므로 장기적으로는 성능 저하를 유발할 수 있다.
또한 회원을 조회하는 상황에서는 is_deleted = false,
즉 삭제되지 않은 회원만 걸러내야 하므로 쿼리가 복잡해질 수 있다는 한계가 있다.
HTTP Method는 뭘로 해야되지?
여기서 REST API 관점에서 하나 궁금한 점이 생긴다.
REST API에 따르면 회원을 삭제하는 행위는 보통 DELETE 메서드에 해당한다. 하지만 실제 서버 구현을 보면 데이터를 완전히 지우는 것이 아니라, 회원 정보의 is_deleted 값을 변경하는 Update 방식으로 처리된다.
그렇다면 이때 HTTP 메서드를 설정할 때는 DELETE로 해야 할까, 아니면 PATCH로 해야 할까?
REST API에서 중요한 것은 리소스를 어떻게 표현할 것인가이지, 내부 구현 방식은 크게 중요하지 않다.
따라서 “회원 삭제”라는 행위의 의미를 전달하는 것이 핵심이므로, 일반적으로는 DELETE 메서드가 더 RESTful하다고 할 수 있다.
클라이언트 입장에서는 “이 회원은 더 이상 존재하지 않는다”는 사실이 중요하지, DB에서 실제로 Hard Delete가 되었는지 Soft Delete가 되었는지는 알 필요가 없다.
그렇다고 해서 PATCH를 사용하면 잘못된 것은 아니다.
다만 이 경우에는 API 문서에서 “회원 삭제”라고 표현하기보다는 “회원 상태 수정(삭제 처리)”와 같이 리소스의 상태 변경임을 명확히 드러내야 REST 원칙과의 일관성을 유지할 수 있다.
정리하면, 권장되는 방식은 DELETE를 사용하는 것이다. 비즈니스적으로 “회원 리소스를 삭제한다”는 의미가 명확하고, 내부적으로 Hard Delete인지 Soft Delete인지는 구현 세부 사항이므로 클라이언트에 굳이 드러낼 필요가 없기 때문이다.
