The document discusses Domain-Driven Design (DDD). It explains that DDD focuses on properly modeling the problem domain and using this domain model to drive the software design. This involves developing a ubiquitous language within the bounded context of the domain model and ensuring consistency between this language, the domain model, and the software code. Patterns like entity, value object, aggregate, and repository can be used, but the domain model is the most important pattern in DDD.
배민찬(https://www.baeminchan.com) 서비스의 백엔드 시스템 중 일부가 지난 1년간 어떤 고민과 아이디어, 결과물을 만들어냈는지 공유하려고 합니다. 발표 중 언급되는 용어나 도구에 대해 일반적인 정의나 간단한 설명은 언급되나 자세히 다루지 않습니다. 사용된 도구들로 어떻게 이벤트 기반 분산 시스템을 만들었는지에 대한 이야기가 중심입니다.
Introducción a Doctrine 2 ORM.
Una introducción y uso básico de Doctrine 2 ORM en PHP sin utilizar frameworks, a través de un proyecto sencillo usado como ejemplo.
El codigo PHP del proyecto se puede descargar de su repositorio de Github: (https://github.com/gonfert/cine.git)
Presentación realizada para la X Symfony Zaragoza
JPA and Hibernate are specifications and frameworks for object-relational mapping (ORM) in Java. JPA is a specification for ORM that is vendor-neutral, while Hibernate is an open-source implementation of JPA. Both use annotations to map Java classes to database tables. JPA queries use JPAQL while Hibernate supports both JPAQL and its own HQL. Additional features covered include relationships, inheritance mapping strategies, custom types, and querying.
마이크로서비스 스타일로 만들어진 시스템을 모노리틱 스타일로 이관한 사례와 함께 스프링을 이용해 모듈형 모노리스(modular monoliths)를 만든 경험을 바탕으로 모노리틱/마이크로서비스 보다 본질적인 문제를 제기하고, 문제 해결을 위한 아이디어와 코드를 공유합니다.
https://github.com/arawn/building-modular-monoliths-using-spring
이 자료는 2019년 KSUG 세미나에서 진행한 "잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다"를 기반으로 몇가지 내용을 추가하고, 전개 방식을 다듬어 조금 더 친절하게 만들어졌습니다.
A walkthrough the main principles to reach solid NodeJS Applications with TypeScript language, Jest as Test Runner and NestJS as framework for structure.
자프링(자바 + 스프링) 외길 12년차 서버 개발자가 코프링(코틀린 + 스프링)을 만난 후 코틀린의 특징과 스프링의 코틀린 지원을 알아가며 코프링 월드에서 살아남은 이야기…
코드 저장소: https://github.com/arawn/kotlin-support-in-spring
SpringBoot with MyBatis, Flyway, QueryDSLSunghyouk Bae
This document provides an overview and tutorials for using MyBatis with Spring Boot. It introduces the mybatis-spring-boot-starter dependency, and covers setting up MyBatis mappers using annotation and XML styles. It also demonstrates MyBatis configuration in Spring Boot, database migrations with Flyway, and MyBatis testing. Additional sections explain concepts like repositories, Java configuration, and using QueryDSL with MyBatis.
The document discusses Node.js and Express.js concepts for building web servers and applications. It includes examples of creating HTTP servers, routing requests, using middleware, handling errors, templating with views and layouts, and separating code into models and routes.
This is a basic tutorial on Spring core.
Best viewed when animations and transitions are supported, e.g., view in MS Powerpoint. So, please try to view it with animation else the main purpose of this presentation will be defeated.
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Edureka!
This Edureka "Node.js tutorial" will help you to learn the Node.js fundamentals and how to create an application in Node.js. Node.js is an open-source, cross-platform JavaScript runtime environment for developing a diverse variety of server tools and applications. Below are the topics covered in this tutorial:
1) Client Server Architecture
2) Limitations of Multi-Threaded Model
3) What is Node.js?
4) Features of Node.js
5) Node.js Installation
6) Blocking Vs. Non – Blocking I/O
7) Creating Node.js Program
8) Node.js Modules
9) Demo – Grocery List Web Application using Node.js
배민찬(https://www.baeminchan.com) 서비스의 백엔드 시스템 중 일부가 지난 1년간 어떤 고민과 아이디어, 결과물을 만들어냈는지 공유하려고 합니다. 발표 중 언급되는 용어나 도구에 대해 일반적인 정의나 간단한 설명은 언급되나 자세히 다루지 않습니다. 사용된 도구들로 어떻게 이벤트 기반 분산 시스템을 만들었는지에 대한 이야기가 중심입니다.
Introducción a Doctrine 2 ORM.
Una introducción y uso básico de Doctrine 2 ORM en PHP sin utilizar frameworks, a través de un proyecto sencillo usado como ejemplo.
El codigo PHP del proyecto se puede descargar de su repositorio de Github: (https://github.com/gonfert/cine.git)
Presentación realizada para la X Symfony Zaragoza
JPA and Hibernate are specifications and frameworks for object-relational mapping (ORM) in Java. JPA is a specification for ORM that is vendor-neutral, while Hibernate is an open-source implementation of JPA. Both use annotations to map Java classes to database tables. JPA queries use JPAQL while Hibernate supports both JPAQL and its own HQL. Additional features covered include relationships, inheritance mapping strategies, custom types, and querying.
마이크로서비스 스타일로 만들어진 시스템을 모노리틱 스타일로 이관한 사례와 함께 스프링을 이용해 모듈형 모노리스(modular monoliths)를 만든 경험을 바탕으로 모노리틱/마이크로서비스 보다 본질적인 문제를 제기하고, 문제 해결을 위한 아이디어와 코드를 공유합니다.
https://github.com/arawn/building-modular-monoliths-using-spring
이 자료는 2019년 KSUG 세미나에서 진행한 "잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다"를 기반으로 몇가지 내용을 추가하고, 전개 방식을 다듬어 조금 더 친절하게 만들어졌습니다.
A walkthrough the main principles to reach solid NodeJS Applications with TypeScript language, Jest as Test Runner and NestJS as framework for structure.
자프링(자바 + 스프링) 외길 12년차 서버 개발자가 코프링(코틀린 + 스프링)을 만난 후 코틀린의 특징과 스프링의 코틀린 지원을 알아가며 코프링 월드에서 살아남은 이야기…
코드 저장소: https://github.com/arawn/kotlin-support-in-spring
SpringBoot with MyBatis, Flyway, QueryDSLSunghyouk Bae
This document provides an overview and tutorials for using MyBatis with Spring Boot. It introduces the mybatis-spring-boot-starter dependency, and covers setting up MyBatis mappers using annotation and XML styles. It also demonstrates MyBatis configuration in Spring Boot, database migrations with Flyway, and MyBatis testing. Additional sections explain concepts like repositories, Java configuration, and using QueryDSL with MyBatis.
The document discusses Node.js and Express.js concepts for building web servers and applications. It includes examples of creating HTTP servers, routing requests, using middleware, handling errors, templating with views and layouts, and separating code into models and routes.
This is a basic tutorial on Spring core.
Best viewed when animations and transitions are supported, e.g., view in MS Powerpoint. So, please try to view it with animation else the main purpose of this presentation will be defeated.
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Edureka!
This Edureka "Node.js tutorial" will help you to learn the Node.js fundamentals and how to create an application in Node.js. Node.js is an open-source, cross-platform JavaScript runtime environment for developing a diverse variety of server tools and applications. Below are the topics covered in this tutorial:
1) Client Server Architecture
2) Limitations of Multi-Threaded Model
3) What is Node.js?
4) Features of Node.js
5) Node.js Installation
6) Blocking Vs. Non – Blocking I/O
7) Creating Node.js Program
8) Node.js Modules
9) Demo – Grocery List Web Application using Node.js
This document provides an overview of key concepts in Domain-Driven Design (DDD) including the ubiquitous language, bounded contexts, value objects, entities, repositories, collections, mappers, identity maps, units of work, and services. It explains that DDD is a set of principles and patterns that help developers create elegant systems by focusing on the core domain and language of the business. It also emphasizes separating business processes into bounded contexts and using ubiquitous language consistently throughout the code.
Domain Driven Design (DDD) is a topic that's been gaining a lot of popularity in both the Java and .NET camps recently. Entities, value types, repositories, bounded contexts and anti-corruption layers -- find out what all the buzz is about, and how establishing a domain model can help you combat complexity in your code.
Richard Dingwall is a .NET developer and blogger with a passion for architecture and maintainable code.
He is currently working at Provoke Solutions as lead developer on a six-month project introducing test-driven development (TDD) and domain-driven design (DDD) to a large ASP.NET ERP system.
An hour-long talk given at Wellington .NET user group, Sept 23 2009.
Domain Driven Design main concepts
This presentation is a summary of the book "Domain Driven Design" from InfoQ.
Here is the link: http://www.infoq.com/minibooks/domain-driven-design-quickly
1. 짜친 세미나, DDD 쌩기초 이야기
- 거의 Final Version
최범균 ([email protected])
자바캔 카페(http://cafe.daum.net/javacan)
자바캔 블로그(http://javacan.tistory.com)
2. TOC
• 객체와 연관
– 객체와 연관
• DDD 쌩 기초
– 레이어 구성
– DDD 빌딩 블록
• DDD와 ORM
• DDD 구현 이야기
– ORM 이용 구현하기
• 도메인 모델 구현
• 리포지토리의 구현
– 어플리케이션 레이어 서비스 구현
– UI 영역(컨트롤러) 구현
• 참고 자료
2
5. 클래스: 객체의 정의
• 기능을 public 메서드로 정의
– 데이터는 외부에 드러내지 않고 기능 정의만 제공
• getter/setter 메서드의 최소화
• 다른 객체를 사용하는 방법
– 필드를 이용해서 다른 객체를 레퍼런스로 참조
• 연관(Association)이라고 표현
– 메서드에서 필요한 시점에 객체를 생성해서 사용
5
6. 객체 간 연관의 예
필드
public class Employee { Organization org = new Organization(…);
private String name;
private Organization organization; Employee e1 = new Employee(…);
... Employee e2 = new Employee(…);
public void setOrganization(Organization org) {
this.organization = org; org.add(e1);
} org.add(e2);
}
필드
public class Organization {
private String name;
private List<Employee> employees;
...
public void add(Employee emp) {
this.employees.add(emp);
emp.setOrganization(this);
}
}
6
7. 연관의 방향성
• 방향성의 종류
– 단 방향: 두 객체 중 한 객체만 레퍼런스 가짐
– 양 방향: 두 객체가 서로에 대한 레퍼런스 가짐
• 양 방향 예
emp1:Employee org1:Oragnization rule1:Rule
organization=org1 employees = [emp1, emp2]
rule = rule1
emp2:Employee
organization=org1
7
8. 연관의 종류
• Many-To-One
– 예, 다수의 Employee가 한 Organization과 연관
• One-To-Many
– 예, 한 Organization이 다수의 Employee와 연관
– 콜렉션으로 구현: Collection, Set, List, Map
• One-To-One
– 예, 한 Oranization이 한 Rule과 연관
• Many-To-Many
– 콜렉션
8
9. 모든 객체가 메모리 있다면… (1)
• 연관된 객체들을 이용해서 기능을 구현
• 예1, Rule의 교체: 연관된 객체 교환으로 구현
Organization org = …; // 어딘가에서 구함 // Organization의 메서드
Rule newRule = new Rule(…); public void changeRule(Rule newRule) {
org.changeRule(newRule); this.rule = newRule;
}
• 예2, 팀 이동: 양방향 연관을 처리
Organization org2 = …; // 어딘가에서 구함 // Employee의 메서드
Employee emp1 = …; // 어딘가에서 구함 public void transferTo(Organization org) {
emp1.changeTeam(org2); Organization oldOrg = this.organization;
this.organization = org;
oldOrg.remove(this);
}
// Organization의 메서드
public void remove(Employee e) {
employees.remove(e);
}
9
10. 모든 객체가 메모리 있다면… (2)
• 연관된 객체들을 이용해서 기능을 구현
• 예3, Rule의 확인: 연관된 객체를 구해 확인
Organization org = …; // 어딘가에서 구함 // Organization의 메서드
Rule rule = org.getRule(); public Rule getRule() {
if (rule != null) { return this.rule;
rule.check(someData); }
} // Rule의 메서드
publiic void check(Data data) { … }
• 예4, Rule의 확인: 내부적으로 위임
Organization org2 = …; // 어딘가에서 구함 // Organization의 메서드
org.checkRule(someData); public void checkRule(Data data) {
if (rule == null) {
return;
}
rule.check(data);
}
10
11. 모든 객체가 메모리 있다면… (3)
• 객체를 메모리에 보관/검색 위한 방법 필요
– 객체마다 고유 식별값 필요
• 메모리 상의 레퍼런스 이용은 한계
• 고유 식별 값을 갖는 객체를 Entity라 함
– 객체 보관하고 제공해주는 기능 필요
• DDD에서는 이를 Repository로 추상화
public interface OrganizationRepository {
public void save(Organization org);
public Organization findById(Integer id);
}
Organization org = organizationRepository.findById(id);
org.checkRule(…);
11
12. 객체의 라이프사이클
• 객체 생성 - 사용 - 소멸
– 동일 라이프사이클을 갖는 객체들의 군 존재
emp1:Employee org1:Oragnization rule1:Rule
organization=org1 employees = [emp1, emp2]
rule = rule1
emp2:Employee
organization=org1
org1이 삭제되면
rule1도 삭제
org1이 삭제되도
emp2는 삭제 안 됨
12
14. DDD(Domain Driven Design)
• 도메인 모델로부터 디자인하기
• 도메인 모델의 중요성 강조
– 도메인 모델을 최대한 설계에 반영
• 예, Ubiquitous Language (용어 최대한 반영)
– 모델이 깨지지 않는 방법 제시 (일관성 유지)
• 예, Bounded Context, Anticorruption Layer 등
• 이를 위한 기본 설계 기법 제시
– 레이어 구성
– 도메인 레이어의 기본 빌딩 블록
14
15. DDD 구현 위한 필수 쌩 기초
발췌: Domain Driven Design (Eric Evans)
15
16. Layered Architecture
사용자에게 정보 출력
User Intreface 사용자의 요청을 해석 하위 레이어에 전달
어플리케이션의 상태를 관리 / Thin Layer
Application 비즈니스 로직/객체 상태를 포함하지 않음
실제 비즈니스 처리는 도메인에 요청
도메인에 대한 정보를 포함
Domain 비즈니스 객체의 상태를 포함
비즈니스 로직을 제공
다른 레이어를 위한 지원 라이브러리
Infrastructure 영속성 구현
16
17. 도메인 모델의 기본 구성 요소
• Entity
• Value
• Aggregate
• Repository
• Service
17
18. 도메인 모델의 기본 구성 요소, Entity
• 주요 특징
– 모델을 표현
– 고유의 식별 값을 가짐
– 모델과 관련된 비즈니스 로직을 수행
– 자신만의 라이프 사이클을 가짐
• 예, 평가 시스템에서의 Entity
– Employee(직원)
– Organization(조직)
18
19. 도메인 모델의 기본 구성 요소, Value
• 고유의 키 값을 갖지 않음
• 데이터를 표현하기 위한 용도로 주로 사용
– 개념적으로 완전한 데이터 집합 <<Entity>>
– (주로) Immutable 임 Employee
자신에게 알맞은 로직을 제공
-id : Integer
– -name : String
– Entity의 속성으로 사용 -address : Address
-organization : Organization
• 자신의 라이프사이클을 갖지 않음
• 엔티티를 따름 1
• 예
– Address(주소) 1
<<Value>>
• 데이터: 우편번호, 주소1, 주소2 Address
– Money(돈): -zipcode : String
• 데이터: 금액, 화폐 단위 -address1 : String
-address2 : String
• 로직: 더하기, 곱하기 등
19
20. 도메인 모델의 기본 구성 요소, Aggregate
• Aggregate
– 관련된 객체들의 묶음
• Aggregate의 특징
– 데이터 변경시 한 단위로 처리 됨
• 비슷한 또는 거의 유사한 라이프사이클을 갖는 객체들
– 특히, 삭제 시 함께 삭제됨
– Aggregate는 경계를 가짐
• 기본적으로, 한 Aggregate에 속한 객체는 다른 Aggregate에
속하지 않음
• Aggregate 필요성
– 많은 도메인 모델을 가능한 간단하고 이해가능한 수
준으로 만들 필요
– 연관의 개수를 줄임으로써 복잡도 감소
20
22. 도메인 모델의 기본 구성 요소, Aggregate 루트
• Aggregate는 루트를 가짐
• Aggregate 루트 역할
– Aggregate의 내부 객체들을 관리
– Aggregate 외부에서 접근할 수 있는 유일한 객체
• Aggregate의 내부 Entity/Value는 루트를 통해 접근
– Aggregate에 대한 알맞은 기능을 수행
• 예, 주문 관련 Aggregate 루트인 Order의 기능
– 주문 취소, 배송지 주소 변경, 주문 상품 변경
• 내부 객체들의 연관을 탐색해서 기능 구현
22
23. Entity, Value, Aggregate 도출 예, 도메인 분석
• 도메인: 평가
– 직원의 평가
– 평가는 성과 평가와 역량 평가로 구성
– 성과와 역량에 대해
• 본인 평가, 1차 평가, 2차 평가 존재
– 성과 평가 시,
• 성과 항목 목록을 입력하고 각 항목에 대한 평가 내용을 입력
– 역량 평가 시,
• 미리 정의된 역량 항목에 대한 평가 내용을 입력
23
24. Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표
성과 목적 결과 가중치 본인 평가 1차 평가 2차 평가
평가
전산 고도화 위키 도입 30 의견 / A 의견 / A 의견 / B
그룹웨어 구축
보안 강화 DB 보안 강화 60 의견 / B 의견 / B 의견 / B
보안 프로세스 도입
팀역량강화 팀 세미나 5회 10 의견 / B 의견 / B 의견 / A
영어 참여율 80%
역량 역량 항목 본인 평가 1차 평가 2차 평가
평가
성취 목표 지향 의견 / A 의견 / A 의견 / B
협동 의견 / A 의견 / A 의견 / B
학습 능력 의견 / B 의견 / B 의견 / B
고객 지향 의견 / A 의견 / S 의견 / A
24
26. Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표
perfEvalSet: PerfEvalSet self:PerfEv
alSet
성 목적 결과 가중치 본인평가 1차 평가 2차 평가
과
----- ----- 30 의견 / A 의견 / A 의견 / B
self
PerfItem
<<Value>> <<Entity>>
PerfEvalSet RaterPerfEval
PerfItem first
----- ----- 60 의견 / B 의견 / B 의견 / B
-self : RaterPerfEval -ratee : Employee
RaterEval -first : RaterPerfEval -rater : Employee
-second : RaterPerfEval self -itemEvals : List<PerfItemRaterEval>
----- ----- 10 의견 / B 의견 / B 의견 / A
1
-done : boolean
<<Entity>> 1
<<Aggregate Root>>
역 역량 항목 본인평가 1차 평가 PersonnelEval 평가
2차
량 -id : Integer <<Value>>
PerfItem
----- 의견 / A 의견 / A : Employee / B
-employee 의견 1
-goal : String
PerfItemRaterEval
-perfEvalSet : PerfEvalSet -grade : Grade
CompeItem 의견 / A : List<PerfItem> B
1..*
----- 의견 / A 의견 /
-result : String
-perfItems -comment : String
RaterEval +evaluatePerfBySelf()
-perfItem : PerfItem
----- 의견 / B 의견 / B
+evaluatePerfByFirst() / B
의견
+evaluatePerfBySecond() 1
----- 의견 / A 의견 / S 의견 / A <<Value>>
self
RaterCompeEval
1
CompefEvalSet -ratee : Employee
first
-self : RaterCompeEval -rater : Employee
self:CompeEv -first : RaterCompeEval -itemEvals : List<CompeItemRaterEval>
alSet -second : RaterCompeEval -done : boolean
compeEvalSet:CompeEvalSet
second
PersonnelEval CompeItemRaterEval
-grade : Grade
-comment : String
26
27. 도메인 기능 구현 예 - 본인 성과 평가 기능
• 본인 평가하기 기능 → 평가 Aggregate의 기능
– 본인 평가하기를 구현하려면
• PersonnelEval의 perfEvalSet 필드로 연결된
• PerfEvalSet의 self 필드로 연결된
• RaterPerfEval을 설정
– 피평가자(ratee), 평가자(rater), 각 항목 평가(itemEvals)
self
<<Entity>> <<Value>> <<Entity>>
<<Aggregate Root>> PerfEvalSet RaterPerfEval
1 first
PersonnelEval -self : RaterPerfEval -ratee : Employee
-id : Integer 1 -first : RaterPerfEval -rater : Employee
-employee : Employee -second : RaterPerfEval self -itemEvals : List<PerfItemRaterEval>
-perfEvalSet : PerfEvalSet -done : boolean
-perfItems : List<PerfItem>
+evaluatePerfBySelf()
+evaluatePerfByFirst() 1 PerfItem
<<Value>>
+evaluatePerfBySecond() 1..* -goal : String
PerfItemRaterEval
-result : String
-grade : Grade
-comment : String
-perfItem : PerfItem
27
28. 도메인 기능 구현 예 - 본인 성과 평가 기능
public class PersonnelEval {
private PerfEvalSet perfEvalSet;
public void evaluatePerfBySelf(List<PerfItemRaterEval> evals, boolean done) {
perfEvalSet.setSelf(employee, evals, done);
}
…
} Aggregate Root가 Aggregate의 다른 객체에 위임
public class PerfEvalSet {
private RaterPerfEval self;
public void setSelf(Employee ratee, List<PerfItemRaterEval> evals, boolean done) {
if (self == null) {
self = new RaterPerfEval(rater, ratee);
}
self.change(evals, done);
}
…
}
28
29. 도메인 기능 구현 예 - 본인 성과 평가 기능
public class RaterPerfEval {
private Employee ratee;
private Employee rater;
private List<PerfItemRaterEval> evals;
private boolean done;
public RaterPerfEval(Employee ratee, Employee rater) {
this.ratee = ratee;
this.rater = rater;
}
public void change(List<PerfItemRaterEval> evals, boolean done) {
this.evals.clear(); PerfItemRaterEval은 Value이고 Immutable 임:
this.evals.addAll(evals); 데이터 값 변경이 아닌, 기존 데이터 삭제 후 새로 추가
this.done = done;
}
…
}
29
30. 도메인 기능 구현 예 - 본인 성과 평가 완료 여부
• 본인 평가 완료 여부 → 평가 Aggregate의 기능
– 본인 평가 완료 여부를 구현하려면
• PersonnelEval의 perfEvalSet 필드로 연결된
• PerfEvalSet의 self 필드로 연결된
• RaterPerfEval에게 문의
self
<<Entity>> <<Value>> <<Entity>>
<<Aggregate Root>> PerfEvalSet RaterPerfEval
1 first
PersonnelEval -self : RaterPerfEval -ratee : Employee
public class PersonnelEval {
-id : Integer 1 -first : RaterPerfEval -rater : Employee
-employee : Employee -second : RaterPerfEval -itemEvals : List<PerfItemRaterEval>
private PerfEvalSet perfEvalSet;
self
-perfEvalSet : PerfEvalSet -done : boolean
-perfItems : List<PerfItem> public boolean isSelfPerfEvaluationDone() {
+evaluatePerfBySelf() return perfEvalSet.isSelfDone();
PerfItem
+evaluatePerfByFirst()
}
1
<<Value>>
+evaluatePerfBySecond() -goal : String
}
1..*
PerfItemRaterEval
-result : String
-grade : Grade
-comment : String
-perfItem : PerfItempublic class PerfEvalSet {
public isSelfDone() {
return self == null ? false : self.isDone();
}
}
30
31. 도메인 모델의 기본 구성 요소, Repository
• Entity를 보관하는 장소
• 기본 규칙:
– Aggregate 당 한 개의 Repository 인터페이스
– Aggregate의 CRUD 기본 단위는 루트!
• 예외, 성능 상 이유로 Aggregate에 속한 다른 엔티티에 직접
접근할 필요가 있는 경우 별도 DAO 구현
– 예, 리포트 집계 등
• Repository의 기본 인터페이스
– save(루트): 한 Aggregate의 저장
– List<루트> findByName(): 특정 조건으로 검색
– delete(루트): 한 Aggregate의 삭제
31
32. Specification을 통한 검색
• Specification
– Repository에서 Entity를 검색하기 위한 필터
• DDD에서의 Specification 구현의 모습
public interface Specification<T> {
public boolean satisfy(T entity);
}
public class SomeCustomerRepository implements CustomerRepository {
public List<Customer> findBySpecification(Specification<Customer> spec) {
List<Customer> all = findAll();
List<Customer> result = new ArrayList<Customer>();
for (Customer c : all) {
if (spec.satisfy(c)) { 개념적으로는 맞지만,
result.add(c); 모든 Entity 로딩 시,
} 성능 문제 발생
}
return result;
}
}
32
33. Specification의 조합
• Specification은 서로 조합이 될 때 유용함
– 다수의 Specification을 and/or로 연결
도메인에 맞는 검색 조건 표현
Specification<Customer> ageGtSpec = new AgeGraterThanSpec(20);
Specification<Customer> locationSpec = new LocationEqSpec(Location.SEOUL);
Specification<Customer> ageLocSpec = Specs.and(ageGtSpec, locationSpec);
검색 조건 조합
List<Customer> custmoers = customerRepository.findBy(ageLocSpec);
Composite Pattern (또는 트리 구조) 이용하여 구현
33
34. 도메인 모델의 기본 구성 요소, 도메인 레이어의 Service
• 한 Entity나 Aggregate에 속하지 않은 도메인 기
능을 도메인 서비스로 분리
– 예, 계좌 이체
• 계좌 이체는 한 계좌 엔티티 객체가 수행할 수 없는 도메인
기능
• 도메인 서비스의 구현
– 다른 도메인 구성 요소 이용해서 기능 구현
• 타 레이어의 서비스와 구분
34
35. DDD 쌩기초의 접근법
• 도메인 모델 중심 접근 필요
• 객체 연관 중심 접근 필요
– 도메인 기능 구현 시, 도메인 객체 간 연관으로 풀기
• SQL을 머리에서 버릴 것 (특히, JOIN!)
35
37. 메모리는 영원하지 않음
• 안정적인 데이터 관리 위해 객체를 물리적인 기
록 장치에 보관할 필요
• 객체 모델과 일치하는 물리적 데이터 저장소는
흔치 않음
– OODB는 시장에서 실패
– RDBS는 딱 들어맞지 않음
– 기타 NoSQL 역시 정확하게 OO와 일치하진 않음
37
38. 차이의 예: 객체 모델과 ER의 대표적인 차이
객체 모델 관계 모델
연관 방향성 양방향 단방향
레퍼런스(필드) 이용 Foreign Key 이용
콜렉션 연관 List, Set, Map 등 콜렉션 사용 Foreign Key 사용
Join/Collection 테이블 사용
다형성 인터페이스/상속 사용 없음
38
39. ORM의 필요성
• DDD를 즐겁게 하려면
– 객체를 이용한 모델링 뿐만 아니라,
– 객체 모델과 데이터 모델 간 좋은 매핑 도구 필요
• 추천 프레임워크
– JPA (자바의 ORM 표준 스펙)
• 객체와 RDB 사이의 모든 매핑을 거의 소화
– 또한, Spring Data 추천
– DB 연동 코드 작성을 위한 노가다 감소
– Spring Data MongoDB 등을 통한 NoSQL과의 매핑 처리
39
44. ORM을 이용한 DB와의 매핑: Entity & Value
• Entity 당 한 개의 테이블 매핑
• Entity 간 참조
– 대부분 단방향의 Foreign Key로 처리
– 경우에 따라 Join 테이블 이용 구현
• Entity 간 참조는 최대한 단방향으로
– 꼭 필요한 경우에만 양방향
• Value
– 엔티티와 한 테이블에 함께 존재
• Value 콜렉션의 경우 Collection 테이블로 Value 구현
44
46. Entity & Value 테이블 매핑 예
• Entity와 같은 테이블 사용하는 Value
@Entity @Embeddable
@Table(name = "EMPLOYEE") public class Address {
public class Employee {
@Column(name = "ADDR_1")
@Id private String address1;
@Column(name = "EMPLOYEE_ID")
private String id; @Column(name = "ADDR_2")
private String address2;
@Column(name = "NAME") }
private String name;
@Embedded
private Address address; EMPLOYEE
...
} EMPLOYEE_ID
NAME
ORGANIZATION_ID
ADDR1
ADDR2
46
47. Entity & Value 테이블 매핑 예
• Value의 List 콜렉션: 콜렉션 테이블 사용
@Entity @Embeddable
@Table(name = "RATER_PERF_EVAL") public class PerformanceItemRaterEval {
public class RaterPerformanceEval { @Column(name = "GRADE_VALUE")
private String gradeValue;
@Id
@Column(name = "RATER_PERF_EVAL_ID") @Column(name = "COMMENT")
private Integer id; private String comment;
…
@ElementCollection }
@CollectionTable(name = "RATER_PERF_ITEM_EVAL",
joinColumns = @JoinColumn(
name = "RATER_PERF_EVAL_ID"))
@OrderColumn(name = "LIST_INDEX")
private List<PerformanceItemRaterEval> itemEvals;
47
48. Repository의 구현
• 인터페이스로 Repository 정의
– 각 ORM 구현체에 알맞게 구현
• 구현 클래스는 Infrastructure 레이어에 위치
public interface PersonnelEvalRepository {
public PersonnelEval findByEmployee(Employee emp);
PersonnelEval save(PersonnelEval eval);
}
public class JpaPersonnelEvalRepository implements
PersonnelEvalRepository {
@PersistenceContext
private EntityManager em;
public PersonnelEval findByEmployee(Employee emp) {
TypedQuery<PersonnelEval> query = em.createQuery(
"select p from PersonnelEval p " +
"where p.employee = :emp", PersonnelEval.class);
query.setParameter("emp", emp);
return query.getSingleResult();
}
public PersonnelEval save(PersonnelEval eval) {
em.persist(eval);
}
}
48
49. Specification의 실제 구현
• Specification으로부터 조건 생성 기능 필요
– CriteriaQuery 생성 or JP QL의 where 절 생성
public class JpaEmployeeRepository implements EmployeeRepository {
@PersistenceContext
private EntityManager em;
public List<Employee> findBySpecification(Specification spec) {
TypedQuery<Employee> query = em.createQuery(
"select e from Employee e " + "where " + Specs.toJPQL(spec),
Employee.class);
spec.setParameters(query);
return query.getResultList();
}
}
– Specification을 직접 구현하는 데는 노력 필요
49
50. Spring Data JPA
Repository
자동 생성
Spring Data
JPA
Spcification
지원
50
51. Spring Data JPA 이용 Repository 구현
• Repository를 위한 메서드 Convention 정의
– 인터페이스로부터 런타임 시, 구현 객체 자동 생성
public interface EmployeeRepository extends Repository<Employee, String> {
Employee findById(String userId);
Employee findByName(String name);
@Query("select e from Employee e left join e.organization o "+
"where e.rateeTypeValue <> 'NOT_RATEE' order by o.name asc, e.name asc")
List<Employee> findAllRatees();
}
51
52. Spring Data JPA 이용 Repository 구현, Spec 지원
• Specification을 위한 기능 제공
– 검색 조건 표현 위한 Specification 인터페이스 제공
public class EmployeeSpecs {
public static Specification<Employee> rateeType(final RateeType e) {
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get(Employee_.rateeTypeValue), e.name());
}
};
} 조건을 도메인 용어로 표현
public static Specification<Employee> nameLike(final String name) {
return new Specification<Employee>() {
@Override
public Predicate toPredicate(Root<Employee> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get(Employee_.name), "%" + name + "%");
}
};
}
}
52
53. Spring Data JPA 이용 Repository 구현, Spec 지원
• Specification을 위한 기능 제공
– Repository 메서드에 Specificiation 지정 가능
public interface EmployeeRepository extends Repository<Employee, String> {
List<Employee> findAll(Specification<Employee> spec);
}
public interface EmployeeRepository
extends Repository<Employee, String>, JpaSpecificationExecutor<Employee> {
// JpaSpecificationExecutor에 기본 메서드 정의
}
53
54. Spring Data JPA 이용 Repository 구현, Spec 지원
• Specification과 Repository의 사용 예
– Repository 메서드에 Specificiation 지정 가능
Criteria와 같은 유연함을 제공
영속 레이어에 대한 의존 제거
(QueryDSL은 EntityManager를 필요)
Specifications<Employee> spec =
Specifications.where(
EmployeeSpecs.rateeType(RateeType.NOT_RATEE)).and(
EmployeeSpecs.nameLike("김"));
List<Employee> findAll = employeeRepository.findAll(spec);
54
55. Lazy & Eager Loading
• Entity 간 연관에서 쓰임 고려한 설정 필요
Employee를 가져올 때, 연관된 Organization도 함께 로딩?
Eager Loading
Employee emp = employeeRepository.findById("madvirus");
Organization org = emp.getOrganization();
org.getName();
이 때, Organization과 매핑된 테이블에서 데이터 로딩?
Lazy Loading
55
57. 전체 레이어 별 구성 요소
데이터 조회 목적
Repository 접근해서 도메인 객체 구함
도메인 모델을 DTO로 변환해서 제공
데이터 읽기 위한 트랜잭션 범위 지정
도메인 기능 실행 요청
트랜잭션 범위 지정
57
58. 애플리케이션 레이어 구현
• 애플리케이션 서비스의 정의
– 사용자에게 기능 제공 위한 인터페이스 정의
• 기능명/기능정의 메서드/입력 파라미터/리턴 결과로 구성
• 도메인을 이용한 구현
– Repository에서 Entity를 가져와
– Entity에 기능을 요청 또는 Entity로부터 정보 조회
• 트랜잭션 범위 지정
– 트랜잭션 시작/커밋/롤백 제어
58
59. 애플리케이션 레이어 구현 - 서비스 정의 예
public interface ReturnEvaluationService {
public ReturnResult returnSelfPerfEval(String rateeId, String raterId);
}
처리 결과를 표현 기능 실행에 필요한 입력
public interface SelfPerformanceEvaluationService {
SelfPerEvalResult evaluate(SelfPerEvalRequest request);
}
59
60. 애플리케이션 레이어 구현 - 서비스 구현 예
public class DomainReturnEvaluationService implements ReturnEvaluationService {
private PersonnelEvalRepository personnelEvalRepository;
@Transactional 스프링 트랜잭션 기능 사용
@Override
public ReturnResult returnSelfPerfEval(String rateeId, String raterId) {
PersonnelEval personnelEval = checkValidRaterAndGet(rateeId, raterId);
personnelEval.returnSelfPerfEval();
return new ReturnResult(rateeId, personnelEval.getEmployee().getName());
}
도메인 객체 사용
private PersonnelEval checkValidRaterAndGet(String rateeId, String raterId) {
PersonnelEval personnelEval = personnelEvalRepository
.findByEmployeeId(rateeId);
if (!personnelEval.getEmployee().checkFirstRater(raterId)) {
throw new RuntimeException("1차 평가자만 반려 가능");
}
return personnelEval;
}
…
}
60
61. UI 레이어의 구현
• UI 레이어의 역할 두 가지
– 사용자의 기능 실행 요청을 애플리케이션 레이어에
전달하기
• 서비스가 요구하는 데이터를 전달하면 끝
• 서비스의 처리 결과를 뷰에 보여주면 끝
– 사용자에게 데이터 보여주기
• 도메인 데이터를 어떻게 뷰에 전달할 것인가?
61
62. UI 레이어 구현, 역할 1 - 서비스에 요청 전달하기
• 컨트롤러에서 서비스에 실행 위임
– 서비스의 입력 값 처리
• 커맨드 객체로 받기 (입력 Form으로부터 요청 객체 생성)
• 컨트롤러에서 직접 생성
@RequestMapping(method = RequestMethod.POST)
public String submit(ModelMap modelMap, SelfPerEvalRequest request) {
SelfPerEvalResult result = evaluationService.evaluate(request);
modelMap.addAttribute("result", result); 커맨드 객체로 사용
return "eval/self/selfPerfResult";
}
@RequestMapping("/review/returnSelfPerfEval")
public String returnPerfEval(@RequestParam("rateeId") String rateeId, ModelMap modelMap) {
ReturnResult result = returnEvaluationService.returnSelfPerfEval(rateeId, SecurityUtil.getId());
modelMap.addAttribute("result", result);
return "review/returnPerfResult";
컨트롤러에서 직접 생성
}
62
63. UI 레이어 구현, 역할 2 - 데이터 보여주기
• UI 레이어에 데이터를 가져오는 기능 구현
– 읽어올 데이터가 많다면,
• 컨트롤러와 분리된 별도 객체로 구현
63
64. DataLoadingService의 구현
• 도메인 레이어를 이용한 구현
– Repository로부터 필요한 엔티티 구함
• 검색 조건 조합 필요시 Specification을 이용
– 엔티티로부터 UI에 필요한 데이터 추출
• 방법 1, 엔티티를 그대로 리턴하기
• 방법 2, DTO를 이용해서 데이터 전달
• 방법에 따라 트랜잭션 경계가 달라짐
public class DomainEmployeeDataLoader implements EmployeeDataLoader {
@Transactional
public SomeReturn load(String empId) {
Employee emp = employeeRepository.findById(empId);
checkNull(emp);
return new SomeReturn(emp);
}
…
}
64
65. 데이터 보여줄 때, 도메인 객체의 노출 문제!
• 도메인 객체를 그대로 UI 레이어에 노출 시 문제
– 도메인 기능이 노출 → 안정성의 문제
• UI 레이어에서 도메인 객체가 제공하는 기능을 실행하면….
– 레이어를 두는 이유가 사라짐!!
– 연관된 객체 접근 시
• JPA의 영속성 컨텍스트 범위가 UI 레이어로 확장되어야 함
• 또는 DataLoader에서 미리 읽어야 함 (연관이 Lazy인 경우)
<%-- 도메인 객체 노출 시, 문제 가능성 --%> organization이 Lazy면
트랜잭션 범위 확장 필요
<%= employee.getOrganization().getName() %>
<% employee.changePassword("", "newPassword"); %> OSIV, No!
65
66. 개인적 의견: DTO 내지 상위의 읽기 전용 인터페이스 사용
• UI에서 필요로 하는 데이터만 담고 있는 DTO
– DataLoader에서 도메인 객체를 DTO로 변환처리
// DataLoader
PersonnelEval eval = personnelEvalRepository.findById(id);
ViewDataDTO dto = convert(eval); // DTO: 기본 데이터 타입 사용, getter만 제공
return dto;
• Getter만 갖는 상위 Interface
– 리플렉션 통해서 메서드 실행이 가능하므로 비추
// DataLoader
public PersonnelEvalIF load() { // PersonnelEvalIF는 read only 메서드만 제공
PersonnelEval eval = personnelEvalRepository.findById(id);
return eval;
}
66
67. DTO를 만드는 방법
• 1, 도메인 객체에 getter를 만들어서 값 읽어오기
– 구현 쉬움
– 프로퍼티에 대한 getter 메서드 생성 필요
– getter 메서드가 증가
• 2, 도메인 객체로부터 값을 받을 수 있는 Builder
를 만들어서 DTO 객체 생성하기
– 구현은 다소 복잡
– 단일 Builder 인터페이스를 이용한 DTO 생성 가능
– getter 메서드의 최소화
67
69. Action!
• 도메인 모델 개발
– 객체 간 연관으로 사고하는 연습
– ORM(JPA) 이용 매핑 처리
• 레이어 간 명확한 역할 구분
– 모든 도메인 로직은 도메인 레이어에 모이도록
• 도메인 로직이 전 레이어에 퍼지지 않도록!
• 리포지토리 구현
– Spring Data 이용하면 좀 더 편리
– Spring Data의 Specification 활용
69