2023.11.10 - [Knowledge/개발지식] - [스진초 5기/개발지식] DDD 설계와 SQL 중심 설계
[스진초 5기/개발지식] DDD 설계와 SQL 중심 설계
오늘의 주제는 DDD 설계이다. DDD 설계는 워낙 요즘 많이 사용하고 팀프로젝트나 실무에선 기본으로 사용되기 때문에 DDD 프로젝트의 구조(패키지 구조 등...)엔 생각보단 익숙하다. 하지만 '왜 사
jh7722.tistory.com
위 글에서 관계형 데이터베이스를 활용한 SQL 중심 개발의 문제점을 다뤘었다.
이번에 JPA 공부를 다시 시작하면서 SQL 중심개발과 ORM를 활용한 객체 중심 개발의 차이를 알아야 필요가 있어 정리한다.
객체와 관계형 데이터베이스의 차이를 나타내는 4가지 핵심
1. 상속
관계형 데이터베이스는 기본적으로 자바와 같은 객체지향 언어에서 말하는 상속의 개념은 존재하지 않는다. 하지만 상속관계를 비슷하게 표현할 수 있는데 테이블을 부모 자식 관계 형태로 나타내는 것이다.
위와 같이 부모역할을 하는 ITEM 테이블을 만들어 그것을 활용하면 된다. 이것을 [Table 슈퍼타입 서브타입 관계]라고 한다.
하지만 문제가 존재한다.
만약 ALBUM 테이블에 데이터를 삽입(저장)한다고 가정하자.
INSERT INTO ITEM...
INSERT INTO ALBUM...
먼저 ITEM 테이블을 Insert 하고 ALBUM을 Insert 해야 되는 과정을 해줘야 한다. 그렇다. 관계형 데이터베이스에서 객체화시키려면 분해하는 작업이 필요하다. (여기선 SQL 문을 분해해서 처리한다는 개념)
만약 조회를 하려고 한다면 더 복잡한 과정을 거쳐야한다. ITEM과 ALUBM 테이블을 조인해서 조회한 결과로 Album 객체를 생성해야 한다. 그렇기 때문에 SQL 중심 개발에서는 관계형 데이터베이스를 활용하여 객체의 상속 관계를 쓰지 않게 된다.
객체지향언어를 활용한다면?
간단하게 자바컬렉션을 통해 album 객체를 저장할 수 있다.
list.add(album);
조회한다고 생각하면 객체를 자바컬렉션에서 가져가 조회하면 되고 부모 타입으로 변형환 할 수 도 있다.(다형성)
Album album = list.get(albumId);
// 부모 타입으로 조회 후 다형성 활용 가능
Item item = list.get(albumId);
2. 연관 관계
객체는 참조를 이용하여 연관관계 값을 가져올 수 있다. (member.getTeam)
관계형 데이터베이스는 외래키를 사용하여야 한다. (JOIN ON M.TEAM_ID = T.TEAM_ID)
그럼 외래키를 이용한 객체 모델링은 어떻게 할까?
class Member {
String id; //MEMBER_ID 컬럼 사용
Long teamId; //TEAM_ID FK 컬럼 사용 //**
String username;//USERNAME 컬럼 사용
}
class Team {
Long id; //TEAM_ID PK 사용
String name; //NAME 컬럼 사용
}
Member에서 teamId를 가지고 있어야지만 Member 테이블에 저장 및 연관 조회가 가능해진다. 사실 아무 문제없어 보일 수 도 있다. 하지만 이것은 객체지향적인 모델링은 아니다.
객체는 위에서 언급했듯이 참조를 통해 연관관계를 맺어야 한다.
올바른 객체 모델링
객체지향 모델링을 하려면 객체에는 teamId가 아닌 Team을 보관해야 한다
class Member {
String id; //MEMBER_ID 컬럼 사용
Team team; //참조로 연관관계를 맺는다. //**
String username;//USERNAME 컬럼 사용
Team getTeam() {
return team;
}
}
class Team {
Long id; //TEAM_ID PK 사용
String name; //NAME 컬럼 사용
}
하지만 이렇게 객체지향 모델링을 하면 DB 저장이나 조회가 쉽지 않다. 테이블은 참조가 필요 없고, 객체는 외래 키가 필요 없기 때문에 개발자가 중간에서 변환을 해줘야 한다.
하지만 DB와의 관계가 아닌 객체세상에서 바라본다면 어떻게 될까?
list.add(member);
Member member = list.get(memberId);
Team team = member.getTeam();
변환과정이 따로 필요 없이 저장하려면 Member List 컬렉션에 add만 하면 되고 그 리스트에서 값을 가져오면 된다. 연관관계 데이터도 간단히 가져올 수 있다.
3. 객체 그래프 탐색
객체는 자유롭게 객체 그래프를 탐색 할 수 있어야 한다.
데이터베이스의 객체를 보관 시 발생하는 문제점
처음 실행하는 SQL에 따라 탐색 범위가 결정된다.
만약 Team을 조인하는 Member 값을 가져오는 SQL을 작성하여 사용한다면 Member.getTeam() 값은 가져올 수 있겠지만 Memger.getOrder() 값을 가져올 수 없게 된다.
객체는 자유롭게 객체를 탐색해야 하지만 처음 실행하는 SQL에 의존하게 된다. 이러면 해당 엔티티에 대한 신뢰 문제가 발생하게 된다.
class MemberService {
...
public void process() {
Member member = memberDAO.find(memberId);
member.getTeam();
member.getOrder().getDelivery();
}
...
}
우리는 주로 스프링 MVC 같은 계층형 구조를 한다. 만약 Service 계층에서 DAO를 활용한다고 가정하자. SQL에 의존한다면 객체의 연관 값을 신뢰 있게 호출할 수 있을까? 내가 모든 개발을 다 하지 않은 이상 확신할 수 없어 find() 메서드 내부를 확인할 것이다.
결국 계층형 구조에서 service 개발을 하기 위해 어디까지 탐색이 가능한지 확인할 수 없기 때문에 탐색 범위를 알아보려면 데이터 접근 계층인 DAO를 열어 SQL을 직접 확인해야 한다. 엔티티가 SQL에 종속되기 때문에 발생하는 문제인데 결론적으로 이런 부분 때문에 진정한 의미의 계층 분할이 어렵게 된다.
4. 비교
데이터베이스는기본 키의 값으로 각 로우를 비교한다. 반면에 객체는 동일성(==), 동등성(equeal) 비교라는 두 가지 비교를 활용한다.
그렇기 때문에 데이터베이스와 객체 사이의 비교는 차이가 있을 수밖에 없다.
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2 // 다르다
class MemeberDAO {
String sql = "SELECT * FROM MEMEBER WHERE MEMBER_ID = ?"
...
return new Member(...);
}
위 코드를 보면 동일 기본 키 값으로 객체를 조회했지만 두 객체의 동일성 비교는 false가 나오게 된다. 왜냐하면 DB 관점에서는 둘을 동일한 로우지만 객체관점에서는 서로 다른 인스턴스이기 때문이다.
다음과 같이 객체 컬렉션을 활용한다면 두 객체는 동일하다.
Member member1 = list.get(0);
Member member2 = list.get(0);
member1 == member2 // 같다
결론
객체와 관계형 데이터베이스는 비슷한 것 같지만 막상 객체지향적인 코드로 작성하기 위해 모델링하면 많은 자원이 활용될 수밖에 없다.
결국 객체 모델과 관계형 데이터베이스 모델은 지향하는 패러다임이 서로 다르다. 위 예시들과 같이 간단한 문제에서도 시간적 소요와 코드를 소비하는데 더 정교한 객체 모델링을 한다고 가정하면 패더라임의 불일치는 더 심해지게 된다.
이런 패러다임의 불일치는 결국 데이터 중심의 개발로 이루어지게 된다. 자바 진영에서는 해당 이슈에 대한 숙제를 안고 있었고, 패러다임의 불일치를 해결하기 위해 많이 노력해 왔다.
그 결과물이 바로 JPA 이며, JPA는 이와 같은 패러다임 불일치를 해결해 주며 정교한 객체 모델링이 가능하게 해 준다.
참조
'Knowledge > 개발지식' 카테고리의 다른 글
[네트워크] PDU(protocol data unit) (0) | 2024.05.16 |
---|---|
[개발지식] 라이브러리와 프레임워크 (0) | 2024.05.01 |
[스진초 5기/개발지식] DDD 설계와 SQL 중심 설계 (1) | 2023.11.10 |
[개발지식] 빌드관리도구와 Maven과 Gradle (0) | 2023.10.13 |
[개발지식] 빌드와 컴파일 (0) | 2023.10.10 |