-
Notifications
You must be signed in to change notification settings - Fork 0
[DB] VER2 설계에 대한 고찰 , 오류 인정, 개선 방향
명식이 버전2 업데이를 하며 "학교 인근 가게 스크랩" 기능을 추가 개발하였습니다. 이 과정에서 테이블 설계를 다음과 같이 하였습니다.
CREATE TABLE Scrap (
id INT PRIMARY KEY,
user_id INT,
store_id INT,
FOREIGN KEY (user_id) REFERENCES User(id),
FOREIGN KEY (store_id) REFERENCES Store(id)
);
사용자와 가게를 링크하는 다대다 관계 테이블이며, 당시에는 비식별 관계로 정의함으로써 스크랩 등록/해제를 고유 ID로 관리하는 것이 편리할 것이라 생각했습니다.
스크랩을 하는 행위는 한 명의 유저가 한 개의 가게를 리스트에 저장하고 나중에 쉽게 찾고 타인과 공유하기 위한 목적의 기능입니다.
본 서비스에서도 스크랩은 동일한 목적을 가진 기능입니다.
동일한 가게를 여러 번 스크랩하는 행위는 발생할 수 없으며 ( 논리적으로 ), 스크랩과 스크랩 해제만을 수행합니다.
따라서 유저와 가게 정보를 PK로 지정하여 다대다의 링크 테이블의 기능만을 하는 것이 스크랩의 본 목적과도 일치한다고 생각했습니다.
다대다 링크 테이블을 식별 관계로 정의하기 위해서는 다음과 같이 IdClass가 필요합니다.
public class MarkId implements Serializable { // Serializable를 반드시 구현해야 합니다.
private Long user;
private Long store;
public MarkId(){}
public MarkId(Long user, Long store) {
super();
this.user = user;
this.store = store;
}
}
이후 실제 StoreMark 테이블에서 다음과 같이 정의합니다.
@Entity
@Table(name = "mark")
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@IdClass(MarkId.class) // IdClass 지정
public class StoreMark implements Serializable { // Serializable 구현.
@Id
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@Id
@ManyToOne
@JoinColumn(name = "store_id")
private Store store;
public StoreMark StoreMark(
User user,
Store store
) {
this.user = user;
this.store = store;
return this;
}
이렇게 정의하면 테이블에는 다음과 같이 데이터가 적재됩니다.
자세한 변경 이력을 확인하고 싶으시면, 여기를 참고해주세요.
초기 개발 당시, 식별/비식별 관계를 충분히 고려하지 않고 개발 편리성을 생각하며 비식별관계
위주의 설계를 했습니다.
이번 리펙토링 과정을 겪으며, 기능이 잘 돌아간다고 하더라도 안주하지 않고 설계를 되돌아보는 시간이 필요함을 경험했습니다.
모든 설계가 처음부터 완벽할 수 없지만, 요구사항에 적합한 설계인지 끊임없이 의심하고 고민하는 자세가 필요하다고 생각합니다.!
설계 변경에 관해 함께 고민해주신 @규범님, @성식님 감사합니다 😊