티스토리 뷰
도메인에는 속성과 행동(메소드)가 포함된다.
클래스 다이어그램 만드는거 생각해보면 된다.
그런데,, 개발을 하다보면 엔티티 내부에 넣어놓기에는 어색한 메소드들이 생각보다 많다.
(예를 들어 회원가입 시 중복 검증, 회원 조회 등...)
이를 해결해주기 위해 나온 것이 "도메인 서비스" 계층이다
도메인 (User)
도메인 서비스 (UserSerivce)
위와 같은 도메인 안에 정의하기는 어색한 메소드들을 도메인 서비스 계층에 정의하여 자연스럽게 처리할 수 있도록 한다.
도메인 서비스는 자신의 행동을 바꿀 수 있는 인스턴스만의 값을 갖지 않는다는 것에서 도메인 객체와는 차이가 있다.
여기서 가장 중요한 것은..
생각해보면 도메인 서비스 계층에 모든 메소드들을 다 때려박아도 코드는 문제없이 돌아간다는 것이다..!!
도메인 서비스 계층에 모든 메소드들이 정의된다면, 도메인 객체에는 Getter와 Setter 메소드만 처량하게 남아있게 된다..
(이를 빈약한 도메인 모델(anemic domain model)이라고 부른다)
그 결과 도메인 객체는 그저 데이터를 담고있는 객체1 이 될뿐 도메인이 주도적으로 뭔가를 하지 못한다.
객체지향의 냄새가 더이상 나지 않게 되는것이다. 이러려고 도메인 주도 설계를 했나,, 자괴감 들고 괴로울 수 밖에 없어진다.
그렇기 때문에 책에서는 명확하게 도메인 서비스에 들어가야 한다! 는 느낌이 없으면 일단 엔티티에다 메소드를 만들어라! 고 적혀있긴 하나,,
막상 팀 프로젝트를 해보면서 개발을 하다보니 도메인 서비스 계층에 저절로 들어가게 된다.;;;
개발에 정답은 없다지만 이런걸 구분하는게 쉽지는 않은 것 같다.
만들다 보니 느낀 것으로는 회원을 예로 들면
회원 엔티티: 회원 생성(속성값), 수정(속성값)
회원 서비스: 회원 가입(), 회원 조회(), 회원 수정(), 회원 삭제() -- 말 그대로 CRUD
이런 식으로 만들어지는 것 같다.
특히 서비스 계층에서는 Repository를 끌고와서 객체를 DB에다가 저장을 해야하는 과정이 필요하다 보니 이렇게 설계를 하게 되는 것 같다. 엔티티 안에다가 Repository를 갖다 넣기에는 좀 아닌 것 같아서..
아무튼 그렇다.
개인적인 느낌으로는 Repository를 사용하는 메소드는 서비스 계층에 들어가는 것이 깔끔하지 않나 싶다.
그리고 다른 도메인 서비스를 같이 끌고와서 사용해야 하는 메소드들도 서비스 계층에 들어가는 것이 좋아보인다.
맞는지는 모르겠다.
------
리포지토리(Repository)
- 객체를 DB에 저장할 때 사용
- 도메인 객체를 저장하고 복원하는 퍼시스턴시.
- 인터페이스로 추상화 하여 구현. 구현체로는 메모리(HashMap같은)나 JpaRepository 같은거를 사용해도 되고, 하여튼 뭘 사용하든 간에 자기한테 주어진 책임만 완수하면 된다. (다형성)
리포지토리가 안에서 어떻게 돌아가면서 지지고 볶든 밖에 있는 서비스 계층은 작동 방식을 전혀 몰라도 된다. 그냥 믿고 맡기기만 하면 된다. (캡슐화) 딱 객체지향 냄새가 나는 스타일.
- 리포지토리에는 객체의 저장, 복원(조회)과 관계된 행위를 정의한다.
--------
애플리케이션 서비스
- 유스케이스를 구현하는 객체, 서비스
- 도메인 객체가 수행하는 테스크를 조율
- 애플리케이션 서비스에 도메인 규칙이 들어가면 안된다.
- 애플리케이션 서비스도 인터페이스로 설계, 구현할 수 있다. 하기만 한다면 훨씬 유연한 설계가 가능하겠지만,, 귀찮다는게 제일 큰 문제다. 개발에 있어서 귀찮다는게 너무 큰 것 같다.
그리고 사실 도메인 서비스랑 애플리케이션 서비스랑 하나로 합쳐도 되지 않나? 싶기는 하다
예시를 들면 아래와 같이 된다.
---
회원 엔티티: 회원 생성(), 수정()
회원 도메인 서비스: 회원 중복 검증()
회원 애플리케이션 서비스: 회원 가입(), 회원 조회(), 회원 수정(), 회원 삭제(),
---
회원 전화번호 중복 검증과 같이 도메인 규칙에 관한 부분은 도메인 서비스에 정의해놓고 사용하라는 뜻인 것 같다.
그렇게 하면 중복 검증 방식이 바뀌어도 한 군데만 수정하면 되기 때문이다.
그런 의도는 알겠으나 사실 잘 모르겠다.
애플리케이션 서비스 계층에다가 하나 메소드로 뽑아놓고 돌려써도 되는 문제 아닌가?
---
회원 엔티티: 회원 생성(), 수정()
회원 서비스: 회원 가입(), 회원 조회(), 회원 수정(), 회원 삭제(), 회원 중복 검증()
---
아직 내가 대형 프로젝트를 접해보지 않아서 생기는 고민일지도 모르겠다.
프로젝트의 규모를 보고 상황에 맞게 필요하다면 나눠서 사용하는 것이 좋지 않겠나 싶다.
이것 말고도 책에서는 응집도가 높은 개발을 위해 서로 관계가 없는 속성과 메소드는 분리하라고 설명하고 있다.
(LOCM, 모든 인스턴스 변수가 모든 메소드에서 사용되어야 한다)
높은 응집도.. 좋기는 한데 막상 이것도 해볼려고 하면 너무 쪼개는거 아닌가 싶기도 하고 또 무엇보다 귀찮다.
이것도 내가 아직 현업에서 개발환경을 접해보지 못해 하는 소리 아닌가 싶기는 한데 잘 모르겠다.
DB 테이블도 무턱대고 정규화 하는게 능사는 아닌것처럼.. 상황에 맞게 알잘딱깔센 하자
결론: 초기에는 합쳐서 개발하다가 상황에 맞게 필요성을 느끼면 분리하던가 하자. (뇌피셜)
물론 분리의 필요성을 느꼈다는 것은,, 리팩토링 작업에 상당한 시간이 걸릴 것이라는 의미이기는 하지만... 난 몰루
-------
애그리게이트(Aggreagte)
- 여러개의 객체가 모여 한 가지 의미를 갖는 하나의 객체를 이루는 것
- 객체가 모여 이룬 하나의 객체는 불변 조건을 유지해야 한다.
- 경계와 루트(Root)를 갖는다
- 외부에서 애그리게이트를 다루기 위해서는 반드시 루트를 통해서만 접근해야 한다
- 애그리게이트에 포함되는 객체는 루트 이외에는 노출되지 않음으로써 불변 조건을 유지할 수 있다(캡슐화?)
- 외부에서는 애그리게이트 내부에 있는 객체를 조작할 수 없다
- 외부에서 내부 객체를 직접 다루는 대신, 내부 객체를 감싸는 다른 객체에 요청하는 형태를 취한다 (이것을 데메테르의 법칙이라 한단다)
-- Team Aggregate --
Team.Members.add(member) (X)
Team.Join(user) (O) ---- member 객체를 감싸는 user 객체를 이용해 요청.
** 데메테르(디미터)의 법칙 **
어떤 컨텍스트에서 다음 객체의 메서드만을 호출할 수 있다
1. 객체 자신
2. 인자로 전달받은 객체
3. 인스턴스 변수
4. 해당 컨텍스트에서 직접 생성한 객체
=> 그냥 자기 일은 자기가 제일 잘 아니까 자기가 알아서 관리하라는 의미이다.
- 애그리게이트 내부 객체의 데이터는 함부로 외부에 공개해서는 안된다.
-> 그럼 DB에 저장은 어떻게함?
1. 팀원끼리 합의에 따른 보호 (이거는 접근, 사용하지 말자는 합의)
2. 노티피케이션 객체
# 애그리케이트의 경계는 어떻게 그을 것인가?
- 변경의 단위
- 애그리게이트는 작게 유지할수록 좋다 (클 수록 트랜잭션의 양이 많아진다)
-------
참고
'웹' 카테고리의 다른 글
ASCII와 UTF-8, 문자열 인코딩 (0) | 2022.08.13 |
---|---|
Spring에서 RequestCache 사용 시 이상한 경로로 redirect되는 현상에 대해.. (0) | 2022.04.16 |
AWS로 톰캣 웹서버 운영 중 받은 Log4j 취약점 공격?? (0) | 2022.04.07 |
도메인 주도 설계란 무엇일까 (2) - 도메인 객체와 예제 (0) | 2022.04.04 |
도메인 주도 설계란 무엇일까 (1) (0) | 2022.03.31 |