SQL 중심 설계
서비스가 DB 테이블의 구조, DB 동작방식에 의존하는 설계
객체지향과 어울리지 않는 설계로 SQL 중심 설계를 했을 때의 단점들을 살펴본다.
데이터베이스의 구조에 의존
객체지향 세상은 PK, FK를 사용하지 않고 객체 참조를 통해 서로를 바라보지만, DB구조에 의존한 설계는 다음과 같다.
class Member{
private Long id;
private String name;
private Long team_id; // team의 PK를 FK로 들고 있음
}
class Team{ // 해당 팀에 속하는 Member를 찾을 때는 FK와 join을 통해 가져옴
private Long id;
private String name;
}
데이터베이스의 동작방식에 의존
객체 자신이 포함하고 있는 데이터를 조작하는데 필요한 행동을 정의해야한다.
데이터를 저장하고 이용하기에 DB만큼 좋은게 마땅하지 않기 때문에 사용하지만, 절차지향처럼 객체 내의 데이터를 밖으로 드러내보여 캡슐화를 위반하면서 외부에서 객체를 사용할 때도 구체화에 의존하기에 결합도가 높아진다.
public Class User{
private Long id;
private String name;
}
public Class Repository{
@Override
public User insert(User user) {// CRUD 쿼리를 통해 객체 < - > DB 컨트롤 필요
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(conn -> {// 클래스 필드, 메소드가 변경되면 SQL도 영향을 받는다.
PreparedStatement ps = conn.prepareStatement("INSERT INTO users(seq,name) VALUES (null,?)", new String[]{"seq"});
ps.setString(1, user.getName()); // 클래스 필드가 private이지만 밖으로 노출되어야 SQL문을 짤수있다.
return ps;
}, keyHolder);
Number key = keyHolder.getKey();
long generatedSeq = key != null ? key.longValue() : -1;
return new User.Builder(user)
.seq(generatedSeq)
.build();
}
}
데이터베이스는 데이터 정규화를 통해 저장 및 검색에 특화되있고, 객체지향은 추상화, 캡슐화, 상속, 다형성 등의 시스템의 복잡성을 제어할 수 있는 것을 목표로 하기에 관계형 DB와 객체지향 패러다임 사이의 차이를 좁히기 위해 DB <-> 객체 변환의 추상화를 제공하는 ORM을 사용한다.
ORM 적용한 설계
다수의 JPA 어노테이션을 이해를 돕고자 생략
class Member{
private Long id;
private String name;
private Team team // 자신의 team을 참조하는 변수를 가짐
}
class Team{
private Long id;
private String name;
private List<Member> members; // team은 자신의 member들을 참조할 수 있음
}
public Class User{
private Long id;
private String name;
}
public class Repository{
EntityManager em;
@Transactional
public void insert(User user){
em.persist(user);
}
}
다음과 같이 객체지향적인 구조 설계와 CRUD 쿼리 시에도 SQL을 추상화해 SQL에 의존도를 낮추고, 데이터를 외부로 노출하지 않는 동작의 설계가 가능하다.
DDD 설계 맛보기
도메인이란
현실세계에서 발생하는 사건 중 소프트웨어로 해결할 문제의 영역을 도메인이라고 하며
객체는 보는 관점은 중요하지 않고 특성과 기능에 따라 추상화 또는 구체화를 하지만,
도메인은 사용자가 사용하는 모든 것을 설명할 수 있고, 보는 관점에 따라 달라진다.(작은 프로젝트에선 거의 동일)
예를 들어 어떤 상품을 온라인으로 판매에 대한 영역은 쇼핑몰 도메인으로 해결한다.
쇼핑몰이 가져야할 주문, 배송, 상품 관리, 결제 등의 서비스들은 쇼핑몰의 서브 도메인으로 설계한다.
여러 도메인들의 조합으로 쇼핑몰 도메인이 완전한 기능을 제공하게 되는 것처럼 도메인의 연동을 통해 완전한 기능을 제공한다.
DDD란
비즈니스 도메인별로 나누어 설계하는 방식으로 핵심목표는 도메인 간의 의존성은 최소화하고 응집성은 최대화하는 것이다.
DDD는 개념설계인 Strategic Design과 프로그래밍을 위한 구체적 설계인 Tatical Design으로 나뉜다.
DDD는 중대한 비즈니스 규칙이 있는 복잡한 서비스를 구현할 때만 적용하는게 설계에 대한 낭비를 막을 수 있다.
Strategic Desgin
도메인 전문가 및 기술팀이 함께 모여 유비쿼터스 언어를 토해 도메인 지식을 공유 및 이해하고, 이를 기준으로 개념과 경계를 식별해 바운디드 컨텍스트로 정의하고 경계의 관계를 컨텍스트 맵으로 정의하는 활동
유비쿼터스 언어
도메인에 대한 어휘를 이해 관계자(도메인 전문가, 개발자, 분석가) 들이 공통적으로 의미를 이해할 수 있도록 정의하는 것이 중요하기에 도메인에 대한 문서, 도메인 모델, 코드, 테스트 등 모든 곳에서 같은 용어를 사용한다.
소통과정에서 발생하는 용어의 모호함을 줄일 수 있고 개발자는 도메인과 코드 사이에서 불필요한 해석과정을 줄일 수 있다.
바운디드 컨텍스트
서브 도메인 내의 도메인 모델을 더 명확하게 표현하기 위한 경계로 비즈니스 도메인의 사용자, 프로세스, 정책, 규정을 고유한 비즈니스 목적별로 그룹핑한 것이다.
컨텍스트 맵(도메인 모델)
서브 도메인과 Bounded Context는 일대일로 대응되는 것이 권장되지만 항상 유지할수는 없기 때문에 위 그림과 같이 도메인과 Bounded Context간의 연관관계를 도식화한 Diagram인 Context Map이 필요하다.
Strategic Design의 결과물
Core 서브 도메인 : 비즈니스 목적 달성을 위한 핵심 도메인으로 우선순위의 투자가 필요
Supporting 서브 도메인 : 핵심 도메인을 지원하는 도메인
Generic 서브 도메인 : 공통기능(메일,SSO, 결제) 도메인으로서 이미 만들어진 SW나 시스템을 통해 대체가능
Tatical Desgin
식별된 바운디드 컨텍스트 내의 도메인 개념인 도메인 모델을 구성하는 유용한 모델링 구성요소들로 프로그래밍적 설계하는 활동
Model Driven Design
개념설계의 결과물인 Domain Model을 중심으로 설계
DDD 계층구조
목적별 계층을 나누어 각각의 계층은 하나의 관심사에만 집중할 수 있도록 설계
올바른 계층 구조를 구현하기 위해서는
- 위의 계층에서 아래 계층에는 접근이 가능하지만 아래에서 위로는 불가능한 것을 기본으로 한다.
- 한 계층의 관심사와 관련된 어떤 것도 다른 계층에 배치되어선 안된다.
Presentation Layer(Controller)
사용자 요청에 대해 해석하고 응답하는 일을 책임지는 계층
유일하게 사용자가 접근가능한 계층으로 사용자에게 UI를 제공하거나 데이터를 응답하는 모든 클래스가 해당한다.
Application Layer(Service)
비즈니스 논리가 포함되있지 않고 SW가 수행할 작업을 정의하고 데이터의 상태변화 같은 실질적인 비즈니스 로직의 호출을 위해 도메인 계층과 인프라스트럭쳐 계층을 연결해주는 계층
Domain Layer(Model)
비즈니스 규칙, 비즈니스 로직에 대한 실질적인 도메인에 대한 정보를 갖고 있고 도메인의 역할과 책임을 지는 계층
지속성 무시 및 인프라 무시 원칙에 따라 데이터 세부정보를 지속은 애플리케이션 계층을 통해 인프라 계층에 위임한다.
Infarstructure Layer(Reposiotry)
도메인 엔티티에 있던 데이터를 데이터베이스나 기타 영구 저장소의 저장을 담당하는 계층
계층 구조의 장점
각 레이어의 응집도를 높히고, 레이어별 관심사에만 집중 할 수 있다.
핵심 비즈니스 로직을 순수하게 유지하기 때문에 유지보수와 확장성 측면에서 이득을 얻을 수 있다.
계층 구조의 단점
다른 관심사가 생길 경우 패키지 분리 및 코드 배치가 어렵다.
SQL 중심 설계와 DDD 설계의 비즈니스 로직 위치
SQL 중심 개발을 통해 서비스에는 흐름 제어 로직만 있고 비즈니스 규칙과 개념들은 SQL에 의존한다.
비즈니스 로직과 저장 기술이 강하게 결합되어 있는 경우는 비즈니스 로직의 변경 및 저장소를 변경할 때 유연하지 않다.
그렇다고 서비스에 모든 비즈니스 로직이 있다면 도메인 객체는 속성값을 갖고 움직이는 DTO와 별 다를바 없고, 속성값을 외부로 노출해야하기에 객체지향과 동떨어져있다.
따라서 도메인에 비즈니스 로직을 위치하고 서비스에선 도메인의 비즈니스 로직을 호출하도록 하는게 도메인이 자신의 책임을 다하고, 서비스의 메서드를 간단하게 할 수 있다.
참고
https://tech.kakao.com/2022/12/12/ddd-of-recommender-team/
https://devfunny.tistory.com/869
https://loopstudy.tistory.com/339
https://dev-coco.tistory.com/166
도메인 주도 설계로 시작하는 마이크로 서비스 개발 핵심개념과 패턴,설계,구현으로 배우는 DDD와 MSA