DDDQ(Domain Driven Design Quickly) - 도메인 주도 설계란 무엇인가? 라는 책의 간단 요약 정리

모델 주도 설계

프로젝트 진행 과정을 도메인 모델을 통해서 밀접하게 연결시킨다.

기능, 분석, 설계, 구현등의 일련의 과정이 도메인 모델 을 통해서 이루어지고 상호 간 피드백이 활성화되어야 한다. 여기에 유비쿼터스 언어 를 적극적으로 사용한다. 또한, 코드는 모델을 밀접하게 반영한다.

도메인 모델 주도 설계를 이용하여 구현 시 OOP가 적합하다.

모델 주도 설계를 위한 블록

MODEL-DRIVEN DESIGN의 언어로 구성된 내비게이션 맵

이미지출처 : http://www.infoq.com/minibooks/domain-driven-design-quickly

계층형 아키텍처

Layred Architecture

이미지출처 : http://wikibook.co.kr/article/layered-architecture/

복잡성 제거를 위해서 레이어로 분할

  • 레이어 내 응집력 강화
  • 하위 레이어에만 의존적
  • 도메인 레이어를 두어서 도메인 자체 표현에 집중
  1. 사용자 인터페이스 (Presentation) : 표현
  2. 애플리케이션 레이어 (Service) : 위임, 처리
  3. 도메인 레이어 (Domain) : 비즈니스로직, 상태
  4. 인프라스트럭처 레이어 (Repository 등) : 영속화, 통신 등

엔티티(Entity)

  • 연속성 : 동일한 객체의 상태가 생명주기 내에서 변화하는 것
  • 유일성 : 생명주기 내 객체가 유일하게 지속될 수 있게 하는 것, 유일한 식별자 존재

엔티티의 구현 : 식별자를 만들어 내는 작업

DB테이블의 주식별자로 엔티티의 식별자를 만들어도 된다. - 주로 이렇게 한다.

값 객체(Value Object)

정의 : 도메인의 어떠한 측면을 표현하는 데 사용되지만 식별자가 없는 객체. 주로 수치와 같은 상대적으로 단순한 값을 표현하고 불변성(수정할 수 없음)을 가짐

  • 값 객체는 라이프사이클을 신경쓰지 않아도 된다. 즉 쉽게 생성되고 폐기할 수 있다.
  • 불변 객체
    • 만약 변경이 필요하다면 새로 만들거나 복사해서 변경한 후 반환한다 - 방어 복사
    • 참조 : http://download.oracle.com/global/kr/magazine/23winter_tech2.pdf

엔티티와 대조

  • 불변 != 상태가 변함 = 연속성
  • 식별자가 필요없음 != 식별자가 필요함 = 유일성

값 객체 자체로는 의미가 약하다. Entity 속성으로 많이 쓰이고 엔티티와 함께 존재할 때 완전한 의미를 가진다.

서비스(Service)

  • 인터페이스 행위(operation)와 위임
  • 도메인 객체의 행위로 포함하기 힘든 경우 서비스 행위로 정의 - 즉 도메인 객체의 역할로 할당하기 힘든 경우
  • 역으로 도메인 객체에 속하는 역할을 서비스 행위로 만들면 안된다 - 서비스 역할이 도메인 영역을 심하게 침범하면 계층 간 강결합이 일어난다.
  • 어떤 행위(계좌이체)에 대한 도메인 객체 간(송금계좌와 입금계좌) 느슨한 결합

특징

  1. 서비스에 의해 수행되는 오퍼레이션은 일반적으로 엔티티 또는 값 객체에 속할 수 없는 도메인의 개념을 나타낸다.
  2. 수행되는 오퍼레이션은 도메인의 다른 객체를 참조한다.
  3. 오퍼레이션은 상태를 저장하지 않는다. (stateless)

모듈(Module)

도메인 모델의 구조화된 일부분

모듈화 : 관련된 개념과 작업을 조직화하여 복잡도를 감소시키는 기법

  • 모듈 기반 높은 응집도 > 모듈 간 결합도는 낮아짐
    • 통신 응집도 : 같은 데이타
    • 기능 응집도 : 유사한 행위

모듈에 유비쿼터스 언어로 된 이름을 부여하라

집합(Aggregate)

관계의 단순화

  1. 모델의 핵심 사항이 아닌 관계가 있다면 그 관계를 제거한다.
  2. 다수성(N)의 숫자는 제약사항(constraint)-또는 한정자(qualifier)-을 추가하여 감소시킨다
  3. 많은 경우 양방향 관계는 단방향 관계로 대처될 수 있다.

관계의 단순화를 거친다고 할 지라도 객체 사이에는 아직도 많은 복잡한 관계가 존재한다. 여기에서 모든 객체의 관계가 일관성을 유지하는 것은 매우 어렵다.

관계의 일관성

  • 데이터 무결성 보장
  • 불변식?? 강제

집합으로 관계의 일관성을 유지하자

  • 각 집합은 하나의 root를 지닌다.
  • root는 엔티티
  • root는 집합된 다른 객체들에 대한 참조를 가지고 있다.
  • root를 통해서만 객체의 외부에서 접근가능
    • 즉, 다른 객체들은 집합에 속한 객체들을 직접 변경할 수가 없음
    • 오직 root를 통해서면 내부 객체들의 변경을 요청할 수 있음
    • root를 통한 행위는 제어가 가능하다. - 이 제어를 통해서 관계의 일관성 을 유지할 수 있다.
    • 만약 외부에서 내부 객체의 참조를 요청하면 복사해서 전달하면 된다. - 방어 복사

예제

Aggregate Example

  • Customer : 집합의 root
  • 나머지 객체들은 값 객체(Value Object)

팩토리(Factory)

복잡한 엔티티나 집합을 생성하는 행위를 root 엔티티를 통해서 생성하는 것은 해당 엔티티의 책임으로 부적절하다.

하나의 객체를 생성하는 것은 그 차제로 주요 오퍼레이션에 해당하지만, 복잡하게 조합된 오퍼레이션을 이미 생성된 객체가 부담하는 것은 적절하지 않다. 이러한 책임(복잡한 객체를 생성하는 것) 생성된 객체와 결합시키는 것은 이해하기 어려운 조악한 설계를 낳는다.

복잡한 객체 생성의 절차를 캡슐화할 수 있는 새로운 개념 = 팩토리

팩토리는 객체 생성에 필요한 지식을 캡슐화하는 데 사용되며 집합(과 같이 복잡한 객체)를 생성하는 데 특히 유용하다.

팩토리는 생성과 관련된 책임을 진다. 모델에는 포함이 되면서 도메인 책임을 가지지 않는다.

구현방법

팩토리를 사용할 때 중요한 점은 객체 생성의 책임 뿐만 아니라 제약조건과 불변식에 관한 규칙 도 포함된다

  • 값 객체 팩토리 값 객체에 대한 불변성을 지원해야한다.
  • 엔티티 팩토리는 엔티티 유일성을 위해서 식별자 생성의 책임도 가질 수 있다.

팩토리가 대신 생성자를 이용해야 하는 경우

  • 생성 작업이 복잡하지 않다.
  • 객체의 생성이 다른 객체의 생성과 연관되어 있지 않으며 모든 속성이 생성자를 통해 전달되어야 한다.
  • 클라이언트가 구현에 관심이 있어서, 사용할 전략(Strategy) 패턴을 선택하려고 한다.
  • 클래스가 바로 해당 타입이다. 관련된 계층 구조가 없어서 concrete 구현 목록에서 선택할 필요가 없다.

팩토리는 새로운 객체를 생성하는 책임을 가진다. DB에 존재하는 객체 메모리에 올리는 작업(일종의 조회)과 구분되어야 한다.

리파지토리(Repository)

도메인과 인프라스트럭쳐(ex:DB)의 계층 분리

  • DB를 통해서 객체를 조회하는 책임을 단순하게 해결할려면 도메인을 사용하는 클라이언트에서 DB를 조회하면 된다.
  • 하지만 그로 인해 도메인 자체가 인프라스트럭쳐에 강결합이 이루어진다. 그리고 도메인의 격리 를 위배하게 되어서 도메인 모델을 위태롭게 한다.
  • 그리고 엔티티와 값 객체는 단순한 데이터 컨테이너(DTO)가 되버리고 도메인 로직은 인프라스트럭쳐와 클라이언트 코드로 옮겨가게 된다. 모델은 위태로워 지고 클라이언트 코드는 파멸로 간다.
  • 도메인과 인프라스트럭쳐가 강결합인 상태에서 DB를 변경한다면?

(영속화 된) 객체 참조를 얻는 로직을 캡슐화하기 위해 리파지토리를 사용

  • 클라이언트(도메인 로직)는 객체를 가져오는 인터페이스만 필요할 뿐이다.
  • 인프라스트럭쳐 또한 은닉되므로 클라이언트는 인프라스트럭쳐와 결합도가 낮아진다.
  • 자연스럽게 모델은 명확해 지고 본연 도메인 로직에 집중된다.

Repository 요청 구조

명세(Specification) 를 이용한 복잡한 검색 지원

참조 Url : http://vandbt.tistory.com/4

팩토리와 리파지토리 비교
  • 둘은 모델 중심 설계의 패턴이며, 생명주기를 관리한다.
  • 팩토리는 객체의 생성 (無 -> 有)
  • 리파지토리는 영속화된 객체를 조회

리파지토리를 이용한 영속화 흐름도

리파지토리와 팩토리를 이용한 흐름도

  1. Customer 객체 생성을 팩토리에 요청한다.
  2. 생성된 Customer 객체를 반환받는다.
  3. 생성된 Customer(C0123) 객체의 추가(영속화)를 리파지토리에 요청한다.
  4. 리파지토리 내부(구현체)에서 DB 입력을 실행한다.

DDDQ(Domain Driven Design Quickly) - 도메인 주도 설계란 무엇인가? 라는 책의 간단 요약 정리

공통 언어의 필요성

공통 언어가 없다면?

  • 각 전문 분야 용어와 서로 다른 언어에 따른 의사소통이 어려움
  • 번역 비용
    • 예를 들어 개발자는 A 라는 용어를 쓰는데 도메인 전문가는 이해가 안되므로 도메인 전문가에게 설명을 위한 다른 용어로 표현
    • 번역 자체 비용 뿐만 아니라 용어의 혼재까지 발생해서 복잡도가 상승함
  • 자신만의 방언

솔루션

  • 도메인 모델 기반 언어 : 모델을 표현할 때 사용하는 용어
  • 다이어그램에 적혀진 언어를 프로젝트 의사소통 시에도 소리내어 사용
  • 이 언어를 유비쿼터스 언어(보편 언어) 라 부른다.

만약 해당 언어나 모델을 도메인 전문가가 잘 이해하지 못하면 그 부분은 잘못되어 있을 가능성이 매우 높다.

유비쿼터스 언어 만들기

항공기 관제 예제의 용어와 핵심개념

  1. 비행기, 출발지, 목적지
  2. 비행기, 항로
  3. 비행기, 항로, 고정지점, 위도, 고도
  4. 비행기, 항로, 고정지점, 위도, 고도, 비행계획, 속도
  5. 비행, 비행계획, 항로, 고정지점, 2차원 좌표

결론 : 개발자, 도메인 전무가로 구성된 설계팀은 자신들의 행동을 통합하고, 모델 작성과 작성된 모델의 코드화를 도와줄 언어가 필요하다

DDDQ(Domain Driven Design Quickly) - 도메인 주도 설계란 무엇인가? 라는 책의 간단 요약 정리

소프트웨어 개발이 어려운 이유는 현실세계 문제의 복잡성에서 시작된다

도메인

  • 자동화된 비즈니스 프로세스
  • 현실세계의 문제
  • 하나의 도메인은 세상의 어떤 것
  • 그래서 복잡함 - 본질적 복잡성

본질적(필연적) 복잡성 : 소프트웨어 구현하고자 하는 기능에 대한 복잡성

우연적 복잡성 : 소프트웨어를 구현하는 행위(언어, 툴, 라이브러리 등)에 따른 복잡성

도메인 모델

  • 소프트웨어 기능을 위해서 도메인 전문가의 지식에서 선택적으로 추상화하여 엄격하게 조직화한 것
  • 다이어그램 등으로 전달하고자하는 아이디어
    • 다이어그램이나 그림은 모델을 가시적으로 표현하고 전달하는 역할일 뿐
  • 복잡성을 다루는 도구이자 추상화의 결과
  • 도메인 전문가와 개발자(개발자들 간에도) 사이의 소통의 중심
    • 지속적인 피드백이 가능하고 최신상태를 유지해야 의미가 있다.
    • 기능(요구사항) - 도메인 모델(유연한 설계) - 구현이 자연스럽게 연결. 즉, 기능과 구현의 자연스로운 통로
    • 소프트웨어 구현에 자연스럽게 녹아들어야 한다.

도메인 전문가 : 현실세계의 문제(업무)를 가장 잘 이해하는 해당분야 전문가 (ex:은행원, 항공관제사 등)

개발자 : 설계자, 개발자 등 소프트웨어를 구축하는 이

소프트웨어

  • 소프트웨어는 도메인의 핵심개념과 각 구성요소를 담고 있어야 하고 그들 간의 관계를 정확하게 실체화해야 한다.
  • 소프트웨어는 도메인을 모델링해야 한다

(도메인 모델을 통한) 좋은 설계는 개발을 가속화 하고, 동시에 개발 프로세스에서 받는 피드백이 설계를 강화한다.

도메인 지식 쌓기

일반화(Generalization)

  • 추상화의 한 기법
  • 공통적인 부분을 골라내는 것

개념 (Concept)

  • Type

도메인에 대한 개발자의 분석적인 자세는 도메인 전문가들과 토의하는 도중에 도메인의 핵심 개념(Concept) 을 발굴해 내는데 도움이 된다.

개발자와 도메인 전문가들은 도메인 모델을 함께 만들어 낸다.

도메인과 소프트웨어는 도메인 모델을 통해서 철저하게 혼합되어야 한다.

유비쿼터스 언어

공통 언어의 필요성

공통 언어가 없다면?

  • 각 전문 분야 용어와 서로 다른 언어에 따른 의사소통이 어려움
  • 번역 비용
    • 예를 들어 개발자는 A 라는 용어를 쓰는데 도메인 전문가는 이해가 안되므로 도메인 전문가에게 설명을 위한 다른 용어로 표현
    • 번역 자체 비용 뿐만 아니라 용어의 혼재까지 발생해서 복잡도가 상승함
  • 자신만의 방언

솔루션

  • 도메인 모델 기반 언어 : 모델을 표현할 때 사용하는 용어
  • 다이어그램에 적혀진 언어를 프로젝트 의사소통 시에도 소리내어 사용
  • 이 언어를 유비쿼터스 언어(보편 언어) 라 부른다.

만약 해당 언어나 모델을 도메인 전문가가 잘 이해하지 못하면 그 부분은 잘못되어 있을 가능성이 매우 높다.

유비쿼터스 언어 만들기

항공기 관제 예제의 용어와 핵심개념

  1. 비행기, 출발지, 목적지
  2. 비행기, 항로
  3. 비행기, 항로, 고정지점, 위도, 고도
  4. 비행기, 항로, 고정지점, 위도, 고도, 비행계획, 속도
  5. 비행, 비행계획, 항로, 고정지점, 2차원 좌표

결론 : 개발자, 도메인 전무가로 구성된 설계팀은 자신들의 행동을 통합하고, 모델 작성과 작성된 모델의 코드화를 도와줄 언어가 필요하다

시스템 환경설정

Preference

트랙패드

  • 탭 클릭 활성화 : 기본 클릭은 힘듬

Touchpad-tabClick

디스플레이

  • 해상도 재조정

Display

키보드

  • 모든 F1, F2 등의 키를 표준 기능 키로 사용 활성화 : 개발 시 단축키 편의
  • 키 반복 및 지연 설정 : 빠른 입력이 가능하게

Keyboard-keyboard

  • 한/영키 단축키 변경 (Swap) : 지연 없는 빠른 한/영 전환

Keyboard-keymap

Spotlight

  • 단축키 변경 : 기본 단축키가 ⌃ Space인데, IDE 에서 자동완성 단축키로 사용되기 때문에 변경요망
  • 본인은 ⇧⌘ Space로 수정했다.

Spotlight-search

손쉬운 사용

  • 확대/축소 기능 활성화

EasyUse

배터리

  • 배터리 퍼센트 표기 활성화

Bettery

쉘 환경설정

PATH 설정

  • ~/bin 폴더를 설정해서 사용자 스크립트나 바로가기를 관리한다.
vi ~/.bash_profile

# path
PATH=$PATH:~/bin;
export PATH

# :wq

ll alias

  • OS X 에서는 ll 명령어가 지원되지 않아서 alias로 생성한다.
vi ~/.bash_profile

# alias
alias ll="ls -lGaf"

# :wq

Homebrew

  • 만약 Homebrew를 사용한다면 Github 인증관리를 위한 키를 등록한다.
  • brew 실행 시 Github API Rate limit exceeded 와 같은 오류가 발생하므로 설정해야함.
  • 참조링크 : https://gist.github.com/christopheranderton/8644743
vi ~/.bash_profile

# alias
export HOMEBREW_GITHUB_API_TOKEN=???????????????????????????????

# :wq

Homebrew Install

Java

  • 만약 Java를 설치한다면 JAVA_HOME를 설정하는 것이 좋다.
  • 실제 JAVA_HOME 정보는 OS 버전별로 바뀔 수 있으니 유의하자.
vi ~/.bash_profile

# java
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"

# :wq

Java Install

외부 플러그인 설치 방법

  1. Preferences > Plugins 에서 찾고자할 플러그인을 검색 - 그림 1-1
  2. 중앙 하단 Browse repositories... 클릭 - 그림 1-1
  3. 좌측 검색된 목록에서 설치할 플러그인을 선택하고 우측 상세에서 Install plugin 클릭 - 그림 1-2
  4. 확인 창이 뜨면 확인을 누르고, Restart Intellij IDEA 클릭 - 그림 1-3

그림 1-1 그림 1-1

그림 1-2 그림 1-2

그림 1-3 그림 1-3

Lombok plugin

  • CTW 기반 반복성 코드 생성 라이브러리

Lombok plugin을 플러그인 검색을 통해서 설치

Annotation Processors 설정

Lombok를 IDE에서 사용하기 위해서 Annotation Processors를 활성화 그림 1-4

Lombok plugin 설정

Lombok를 IDE에서 사용하기 위해서 Lombok 환경설정에서 사용 옵션을 활성화 그림 1-5

Grep Console

  • 콘솔 출력을 가독성 있게 보여줌

Grep Console을 플러그인 검색을 통해서 설치

JavaDoc

  • JavaDoc 헬퍼 플러그인

JavaDoc을 플러그인 검색을 통해서 설치

Checkstyle

  • 코딩컨벤션제어

Checkstyle-IDEA을 플러그인 검색을 통해서 설치

PMD

  • 정적코드분석

PMDPlugin을 플러그인 검색을 통해서 설치

Findbugs

  • 정적코드분석

Findbugs-IDEA을 플러그인 검색을 통해서 설치

Atlassian Connector

  • Atlassian 제품(JIRA, Bamboo, Crucible, FishEye) 연동 플러그인
  • 개인적으로 JIRA 연동을 위해서 설치함. 다른 종류의 ITS를 사용한다면 해당 플러그인이나 기본 Task 플러그인 사용요망

Atlassian Connector for IntelliJ IDE를 플러그인 검색을 통해서 설치

Eclipse Code Formatter

  • IntelliJ를 이클립스 기본 코딩 스타일로 적용
  • 이클립스 사용자와 협업을 한다면 설정을 추천
  • 형상관리툴에서 코드포맷(특히 import) 이슈를 많이 해결해 준다.

Eclipse Code Formatter를 플러그인 검색을 통해서 설치

설정참조

Eclipse Code Formatter Configuration

Markdown support

  • 마크다운 미리보기 등 지원
  • github를 사용하면 유용함

Save Action

  • 저장 시 Auto import, Reformat (⌥⌘L, ⌥⇧⌘L) 을 자동화
  • Code style 설정 따라감.

Presentation Assistant

  • IDE 하단에 단축키를 노출시켜줌 (win, mac 둘 다)
  • 코딩 시연, 스터디, 강좌, 페어프로그래밍 등에 유용함

Presentation Assistant

https://plugins.jetbrains.com/plugin/7345-presentation-assistant

Nyan Progress Bar

  • 고양이 프로그래스 바

Nyan Progress Bar

https://plugins.jetbrains.com/plugin/8575-nyan-progress-bar

Key Promoter X

  • 단축키 사용 유도 플러그인

Key Promoter X animation

https://plugins.jetbrains.com/plugin/9792-key-promoter-x

Java Stream Debugger

  • 디버그 상황에서 Stream을 각 연산자 별로 모니터링

Java Stream Debugger

https://plugins.jetbrains.com/plugin/9696-java-stream-debugger

GsonFormat

  • json 문자열을 java 객체로 변환 - 이건 대박

GsonFormat animation

https://plugins.jetbrains.com/plugin/7654-gsonformat

Rainbow Brackets

  • 각종 괄호류 들을 구분하기 쉽게 색깔 별로 분류

https://plugins.jetbrains.com/plugin/10080-rainbow-brackets