make it simple
article thumbnail

개요

  • 사이드 프로젝트를 시작하게 되었다. 처음부터 진행하는게 아닌 진행되어있는 프로젝트에 합류했다. 처음보는 패키지 구조였는데 한눈에 파악하기가 쉬웠고 오히려 이제까지 개발하던 구조보다 더 확장성 있고 가독성이 좋다고 느꼈다. 그 이유는 메인 도메인 안에 하위 도메인과 도메인이 가지고있는 비즈니스 로직들을 한번에 파악할 수 있어 도메인의 역할을 쉽게 파악할 수 있엇다. 알고보니 해당 구조는 DDD(Domain Driven Design)를 기반으로 만들어졌다. 사실 이전까지 DDD에 대해 많이 들어는 봤지만 실제로 적용해 본 적은 없었다.이제 프로젝트를 진행하면서 내가 DDD를 적용하고 개발을 해야되는데 많이 부족하다 느껴 도메인 주도 개발 시작하기 by 최범균 책으로 DDD를 공부하기 시작했다.

도메인이란?

  • 소프트웨어로 해결하고자 하는 문제 영역 ( ex: 온라인 서점)
  • 메인 도메인과 여러 하위 도메인이 존재한다.

  • 코딩을 하기전 이해관계자와 개발자는 도메인 지식을 갖추고 소통을 하며 개발을 해야한다. -> 커뮤니케이션이 중요
    • 도메인을 정확하게 이해하지 못하고 개발을 하면 Garbage in, Garbage Out(잘못된 값이 들어가면 잘못된 결과가 나온다 -> 요구사항을 잘 못이해해서 개발한 경우) 이 발생한다.

Domain

  • 도메인 모델에 set 메서드 넣지 말아야한다. -> set 메소드는 도메인의 핵심 개념이나 의도를 코드에서 사라지게 한다.
  • 도메인의 상태를 변경하는 메서드가 필요하면 네이밍을 직관적으로 작성 후 사용해야한다.
public class Order{
    public Order(Orderer order,List<OrderLine> orderLines, shippingINfo shippingInfo,
                 OrderState state){
       setOrderer(orderer);
       setOrderLines(orderLines);
       calculateTotalAmounts();
    }
    private void setOrderer(Orderer orderer){
    	if (orderer ==. null) throw new IllegalArgumentException("no orderer");
        this.orderer = orderer;
    }
    private void calculateTotalAmounts(){
        this.totalAmounts = orderLines.stream().mapToInt(x -> x.getAmounts()).sum();
    }
}
  • 위 코드는 주문 관련 도메인이다. 주문자를 넣는 setOrderer() 와 가격을 계산하는 calculateTotalAmounts()가 있다. 이러한 필요한  메서드들은 set 메서드를 올바르게 사용한 경우이다. 무조건적으로 set 메서드가 안 좋은건 아니다. 내부에서 데이터를 변경할 목적으로 사용할 경우 접근 범위를 private으로 주고 외부에서는 데이터를 변경할 목적으로 set 메서드를 사용할 수 없다.
  • 도메인 상태 변경을 하는 메소드의 네이밍은 계속 진화할 수 있다 -> 개발을 할 수록 도메인을 더 잘 이해하기 때문
  • 절대적으로 도메인에 사용하는 언어를 고민하고 또 고민해서 작성해야한다. 그래야 유지보수 측면이든 팀이랑 의사소통을 하던 파악하기가 편리하다.
public OrderState {
    STEP1, STEP2, STEP3, STEP4, STEP5, STEP6
}
  • 위 처럼 주문의 상태값을 저렇게 STEP으로 나열하면 작성한 사람만 알 수 있다.
public enum OrderState {
    PAYMENT_WAITING, PREPARING, SHIPPED, DELIVERING, DELIVERY_COMPLETED;
)
  • 위 처럼 단어를 정확히 명시를 하면 어떤 상태인지 파악하기가 쉽다.

Entity

  • 엔티티의 가장 큰 특징은 식별자를 갖는다. 식별자는 엔티티 객체마다 가지고 있는 고유의 값이다.
  • 식별자는 절대로 바뀌지가 않는다.
  • 식별자가 같으면 식별자를 이용해 equals()메소드와 hashcode() 메소드로 두 엔티티가 같다고 판단할 수 있다.
  • 식별자는 다음 중 한 가지 방식으로 생성된다.
    1. 특정 규칙에 따라 생성
    2. UUID나 Nano ID와 같은 고유 식별자 생성기 사용 
    3. 값을 직접 입력
    4. 일련번호 사용(시퀀스나 DB의 자동 증가 컬럼 사용 -> pk id

보통은 2번이나 4번 방법으로 많이 사용한다. UUID같은 경우에는 entity의 id값이 외부로 노출되지 않아 보안에 우수하며 또한   multi-db인 경우에는 유일성도 보장해주는 식별자다. 하지만 식별자를 UUID로 가지는 경우 시퀀스(id)에 비해 메모리를 많이 가져 간다. 상황에 맞게 전략적으로 잘 사용해야한다.

  • 의미를 명확하게 하기 위해  기본형이나 참조형 데이터 타입을 객체로 생성해서 사용할 수 있다. 
public class Money { 
    private int value;
	
    public Money(int value) { 
       this.money = money;
    }
)
public class OrderLine { 
    private Product product; 
    private Money price; 
    private int quantity; 
    private Money amounts;
     ...
  • 위 처럼 기본형인 int를 money라는 객체로 사용해서 OrderLine 클래스에서 명확하게 price는 money(돈, 숫자) 임을 알 수 있다. 개발자는 money라는 객체를 정수 타입 연산이 아닌 돈 계산이라는 의미로 코드를 작성할 수 있다.

결론 

길지만 개인적으로 중요한거 같아서 책에서 그대로 가져왔다.

  • 도메인에서 사용하는 용어의 의미를 명확하게 전달하는 영단어를 찾기 힘든 경우도 있고, 
    반대로 비슷한 의미의 영단어가 많으면 각 단어의 뉘앙스나 미세한 차이를 몰라서 선택하기 어려울 때도 있다. 도메인
    용어의 '상태'를 코드로 표현할 때 'state'와 'status' 중 어떤 단어를 사용할지 고민해야 하고, '종류'를 표현
    하기 위해 'kind'와 'type' 중 어떤 단어가 맞는지 고심할 때도 있다. 그냥 이해하기 쉽게 발음 나는 대로 gubun(구분)
    과 같은 이름을 사용하기도 한다.

    알맞은 영단어를 찾는 것은 쉽지 않은 일이지만 시간을 들여 찾는 노력을 해야 한다. 한영사전을 사용해서 적당한 단어를
    찾는 노력을 하지 않고 도메인에 어울리지 않은 단어를 사용하면 위 코드는 도메인과 점점 멀어지게 된다. 그러니 도메인
    용어에 알맞은 단어를 찾는 시간을 아까워하지말자.
  • 위에서 말하는 것처럼 네이밍이나 도메인에 대해 고민을 할 때 중요하다 생각한 후 개발했지만, 생각한것 만큼 시간을 사용하고 고민하고 또 고민하지 않은 것 같다. 이번 CH1을 통해 조금 더 개발할 때 도메인적으로 접근하고 고민하고 또 고민한 후에 코드를 작성해야겠다는 경각심이 생겼다.

reference: 

profile

make it simple

@keep it simple

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!