DDD(Domain Driven Design) - Value Object (값 객체)

이미지
이번에 다룰 DDD 의 내용은 바로 값 객체이다. 반 버논에 도메인 주도 설계 구현에서는 되도록이면 엔터티가 아니라 값 객체를 사용해 모델링하도록 노력해야 한다고 말한다. 값 객체의 이점으로 책에서는 아래와 같이 언급한다. "측정하고 수량화하거나 설명해주는 값 타입은 생성, 테스트, 사용, 최적화, 유지 관리가 더 쉽다." 그렇다면  도메인 개념을 값으로 모델링해야 할지 알 수 있는 방법은 무엇인가? 아래와 같은 특징을 포함하는지 고려해야 한다. 도메인 내의 어떤 대상을 측정하고, 수량화하고, 설명한다. 불변성이 유지될 수 있다. 관련 특성을 모은 필수 단위로 개념적 전체를 모델링한다. 측정이나 설명이 변경될 땐 완벽히 대체 가능하다. 다른 값과 등가성(value equality) 을 사용해 비교할 수 있다. 협력자(collaborator) 에게 부작요이 없는 행동 (Side-Effect-Free Behavior) 을 제공한다. 측정, 수량화, 설명 -> 도메인 내에 있는 어떤 대상을 측정하고 수량화하고 설명하는 개념. ex) 사람에겐 나이가 있다. 나이는 실재하는 어떤 대상은 아니지만, 사람이 살아온 햇수를 측정하거나 수량화 한다. 불변성 -> 값 객체는 한 번 생성되면 변경할 수 없다. 보통 java 에서 객체를 생성할 때 특정 생성자 혹은 팩토리 패턴을 이용해서 생성후 객체의 변경을 할 수 있는 메서드를 제공하지 않는 방법으로 불변성을 유지할 수 있다. 만약 지금 설계하고 있는 객체가 자신의 행동으로 인해 변경돼야 한다고 생각한다면, 이는 값 객체가 아니라 엔터티로 설계해야 함을 의미한다. 개념적 전체 (Conceptual Whole) -> 값 객체는 하나 이상의 개별적 특성을 가질 수 있으며, 각 특성은 서로 연관되어 있다. 여러 특성이 설명하는 바를 모아 전체를 나타낸다.  ex) {50,000,000달러} 는 50,000,000 이라는 특성과 달러...

DDD(Domain Driven Design) - Entity (엔터티)

이미지
DDD 를 알기전에는 나역시 그랬고, 반 버논의 도메인 주도 설계 구현에서도 언급한 내용이 있다. 바로 "개발자는 도메인보다 데이터에 초점을 맞추려는 경향이 있다." 소프트웨어 개발에 관한 대부분의 접근법이 데이터베이스에 중점을 두기 때문에, DDD를 처음 접하는 사람에게 일어날 수 있는 현상이라고 한다. 나도 매우 동의한다. 지금까지 그렇게 해왔다. 풍부한 행동을 바탕으로 도메인 개념을 설계하지 않고, 데이터의 속성(컬럼)과 연결(외래 키)을 먼저 생각하려 한다. 이를 바탕으로 데이터 모델을 대응하는 객체로 투영하게 되는데, 이로 인해 게터와 세터로 가득찬 무기력한 도메인이 되버린다. 지금부터 엔터티란 무엇인가에 대해서 다루어 보려고한다. 1. 엔터티는 식별자 를 가진다. 2. 엔터티는 변화 가능성(mutability) 을 가진다. -> 엔터티는 고유한 대상으로 긴 시간에 걸쳐 계속해서 변화한다. 어떤 예를 들 수 있을까? 지금 재직 중인 회사에서 엔터티로 다룰 수 있다면, 제일 먼저 생각나는 엔터티는 Order(주문) 이다. 특정 식별자를 가진 주문의 상태는 계속해서 변화한다. 객체를 특성(attribute) 이 아니라 식별자에 따라 구분한다면, 모델을 정의할 때 이를 우선적으로 다루어야 한다고 한다. 클래스의 정의를 단순하게 유지하면서 수명주기의 지속성(continuity)과 식별자에 집중해야 한다고 한다. 형태나 히스토리에 상관없이, 각 객체를 구분하는 수단을 정의해야 한다고 한다. 이 모델에선 같은 대상이 된다(아마도 equals and hashcode 를 의미하는 것 같다)는 의미가 무엇인지 반드시 정의해야 함을 강조하고 있다. 앞서, 엔터티는 식별자를 가지고 변화 가능성을 가진다고 했다. 따라서 시간이 흘러도 고유성(uniqueness) 을 보장할 수 있도록, 식별자를 구현하는 방법들을 확보하는 것이 중요하다. 그렇다면, 식별자를 구현하는 방법에는 어떤것들이 있을까? 1. 사용자가 식별자를...

DDD(Domain Driven Design) - Repository 리파지토리

이미지
반 버논의 도메인 주도 설계 구현 이라는 책을 완독하고 나서 여러가지 정리할 점들이 있는데, 그 중 하나가 레포지토리 이다. 오늘은 리파지토리에 대해서 다루어 보려고 한다. 지금 재직중인 회사나 전회사에서 일할때도 Database 중심적 설계를 바탕으로 시스템을 구축했다. 그리고 내가 가보지 못한 대부분의 회사들도 아마도 DDD 를 실무에서 적용하고 있지 않을 것이라고 감히 추측해 본다. 물론 DDD 를 실질적으로 도입하고 있는 회사도 많을 것이다. 잡소리는 그만하고, 리파지토리에 대해서 다루어 보겠다. 반 버논의 도메인 주도 설계 구현에서 리파지토리에 아래와 같이 2 가지를 다루고 있다. - 컬렉션 지향 리파지토리 ( collection-oriented-repository ) - 영속성 지향 리파지토리 ( persistence-oriented-repository ) 먼저, 컬렉션 지향 리파지토리이다. 책에서는, 컬렉션 지향 리파지토리는 Set 컬렉션을 흉내 내야 한다고 한다. 이 말이 무슨 말이냐면, Set에 있는 같은 객체(equals and hashcode)의 인스턴스는 두 번 추가되로록 허용해서는 안 된다. 또한 리파지토리로부터 객체를 가져오게 하고 수정할 때 이를 리파지토리에 "재저장" 할 필요가 없다. 이를 단순하게 이해하기 위해서, 책에서 나온 예제를 살펴보겠다. 표준 java.util.HashSet 을 확장하고 고유 식별자로 특정 객체를 찾도록 해주는 새로운 타입상의 메서드를 생성한다고 한다. 확장 클래스로 CalendarRepository 라는 이름을 주어 인식할 수 있도록 해주었다. 하지만 이는 단순한 인메모리 HashSet 이다. 리파지토리에서 find 를 통해서 찾은 객체를 수정한 뒤, 명시적으로 다시 add 해주지 않는다. 수정내역은 해당 객체에서 바로 일어나기 때문이다. 이와 관련된 예제로 직접 작성해보았다. 아래에서 확인할 수 있듯이, me 라는 User 타입의 객체의 n...

Vanilla JS - select tag with namedItem

이미지
최근에 레거시를 유지 보수하면서, JS 및 JQuery 를 만지는 일이 있었다. 일을 하면서 select 태그의 option 태그를 selected 가 아닌, 특정 value 값을 기준으로 option 태그를 선택 후 해당 텍스트값을 가져와야 하는 작업이 필요했었다. 보통 select 태그를 사용하게 되면, selected 인 option 의 value 혹은 text 값을 핸들링 하는데, 해당 케이스는 보통 케이스와 달라서 아주 잠깐 당황했었다. 해결법은 물론 있다. 레거시를 만지면서, JQuery 를 최대한 걷어내고 있는데, JQuery 선택자를 이용하면 매우 간단하게 해결할 수 있다. 예를 들어, 아래와 같이 한 줄 이면 간단하게 해결이 가능하다. 근데, 요즘 JQuery 를 사용하지 않는데 이점이 더 큰것을 알아가고 있어서 JQuery 를 사용하지 않기로 결심했다. 따라서 namedItem 이라는 method 를 사용해보았다. https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/namedItem The  HTMLSelectElement.namedItem()  method returns the  HTMLOptionElement  corresponding to the  HTMLOptionElement  whose  name  or  id  match the specified name, or  null  if no option matches. name 혹은 id 속성을 이용해서 Element 를 선택한다. 아래에서 확인할 수 있듯이, Edge 와 IE 에서는 name 속성이 지원이 안된다고 한다. 따라서 id 속성을 이용하는것이 크로스 브라우징에 매우 유리하다. 그럼 우선 예제를 보자, 아래와 같이 fruits 라는 id 속성을 가진 sele...

Java - self-encapsulation (자가 캡슐화) 혹은 self-delegation (자가 위임)

이미지
반 버논의 도메인 주도 설계 구현(DDD Domain Driven Design)이라는 책을 요즘 보고있다. 여러가지 도움되는 개념도 많다. 그 중에 하나인 자가 캡슐화의 개념을 한 번 다뤄보겠다. 마틴 파울러 형님께서 '자가 캡슐화는 심지어 같은 클래스 내에서부터 모든 데이터로의 액세스가 접근자 메소드를 거쳐가도록 설계하는 방법이다.' 라고 말했다.  말로만 들어선 언뜻 이해하기 어렵다. 그래서 예제를 통해서 풀어나가려고 한다. 우선 User라는 Entity = aggregate root 가 존재한다. 식별자로써 Long 타입의 id 그밖의 중요한 username, password 와 값 객체인 Person 을 가지고 있다. 중요하게 볼 것은 기본 생성자와 setter 들의 접근 제어자이다. protected 로 선언했다. protected 로 선언한 이유는 같은 모듈안에서만 호출하도록 모듈간의 의존성을 제거하기 위함에도 있다. 더욱 강력하게 기본생성자를 private 으로 만들고, 파라미터 생성자만 protected 로 공개할 수도 있다. 그리고 setter 들도 또한 private 으로 만들어서 오직 파라미터 생성자만이 속성/특성을 설정할 수 있도록 한다면, 불변하게 만들수 있다. 또한 매개변수가 있는 생성자를 보면, 변수 할당을 자신의 내부 세터로 위임한다. 각 세터에게 상태의 일부를 설정하는 계약 조건을 결정토록 하고 있다. 각 세터는 Entity 를 대신해 개별적으로 null 이 아니라는 제약을 검사해서 인스턴스 계약을 집행한다. 이는 Assertion Guard 라고도 한다. 이 기법의 이점은 몇가지가 있다고 한다. 1. 객체의 인스턴스 변수를 추상화할 수 있도록 해준다. 2. 이를 통해 해당 객체를 담고 있는 많은 다른 객체에서 손쉽게 특성/속성을 가져오는 방법을 제공한다. 3. 또한 이를 통해 계약의 의한 설계를 이행한다. 4. 값의 불변성을 유지할 수 있다. 하지만 이 기법을 많이 ...

IntelliJ 인텔리제이 - Git commit squash (Interactively Rebase)

이미지
Git 을 이용해서 진행하는 개발 업무를 하다보면, 급한 이슈로 인해서 현재 작업하던 것을 제쳐두고 해당 이슈를 처리해야 할 일이 있다. 그러면 해당 작업을 불가피하게 commit 혹은 stash 를 이용하여 현재까지 작업한 상태를 보존해야 한다. 여담으로, 개인적으로 stash 를 상당히 비추한다. 그 이유는, commit 이 안된 stash 의 경우 실수로 날려버리면 복구가 불가능하다. 실제로 업무를 하다가 실수로 기존 stash 를 clear 해버려서 하루종일 작업한게 날아갈 뻔해서 진땀을 한바가지 흘린 적이 있다. 다행히도 commit 을 했어서, commit hash 를 통해서 복구를 했었다. 따라서 stash 보단 commit 을 자주하여, squash 를 애용하겠다고 생각했다. 다시 돌아와서 얘기하자면, 급한 이슈가 자주 발생하면 할수록, 도중에 흐름이 끊겨서 설계한 대로 commit 단위를 쪼개기가 어려워지고 의미있는 commit message 작성이 어려워진다. 따라서 commit 단위를 관리하기 위해서 squash 를 통해 commit 메세지를 관리하는 방법을 블로깅 해보려고 한다. 단적인 예로 아래와 같이 Pageable 이라는 feature 에 대해서 3가지로 나눠졌다. 해당 예제는 여러사람들과 같이 협업이 아니라 혼자 진행하고 있는 사이드 프로젝트라서 브랜치가 하나이다. 또한 전제로 이 기능은 매우 간단하며, 하나의 commit 으로 관리되는것이 더 효율적이라고 판단된 사항이다. 따라서 3개의 commit 을 하나로 통합하는 예제이다. 그렇다면 이제 진행해 보자. 아래와 같이 commit 내역에 오른쪽 클릭을 하고, interactively rebase from here.. 를 선택한다. 아래와 같이 하나의 commit 내역만 대상에 뜬다. 따라서 HEAD~3 을 합치고 싶은경우, HEAD~3 의 commit 을 다시 오른쪽 클릭하고 동일하게 진행해준다. 아래와 같이 HEAD~3 co...

Strategy Pattern In Spring (feat. JPA)

이미지
최근에 Medium 에서 아주 신기한 글을 봤다. spring 에서 전략 패턴을 구사하는 내용인데, 새로운 DI 방법을 보고 너무 신기했다. 혼자 다른 곳에 적용하고 싶어서 이것저것 건들다가 손을 댔는데, 예제가 허접하다. 양해 부탁한다. 우선, 해당 글 링크 https://medium.com/javarevisited/implementing-the-strategy-pattern-with-spring-de2bad3abc2f 전략 패턴이란 해당 글에서 이렇게 설명한다. The   Strategy Pattern   is a behavioral design pattern that enables selecting an algorithm at runtime. 런타임에서 알고리즘을 선택하는 행동적인 패턴이라고 한다. 처음 듣는다면, 설명 만으로 한번에 이해하기 조금 어려울 수 있다. 해당 글에서는  e-commerce   주문 영역을 다루고 있다. 필자가 구현해본 예제는 조금 전략패턴에 맞지 않는 도메인과 구조일 수 있다는 점 다시 한 번 양해를 구한다. 전자제품, 의류, 음식, 책은 Product 를 상속받은 구조이며, TABLE_PER_CLASS 전략으로 각각의 테이블로 구성하도록 설계했다. 아래에서 Product 를 확인할 수 있다. 그리고 아래에는 Product 를 상속받은 Book class 의 구조이다. Author, Weight, Size 는 @Embedded 를 사용하여 구현하였다. Electronics, Clothing, Food class 는 생략하겠다. 그렇다면, 어디서 전략패턴을 구사하고 있는가를 이제 보자. 필자가 가장 신기했던 부분이 바로, 아래에 있다. productCode PathVariable 을 이용하여 ProductType enum 을 이용하여 serviceName 을 가져오고 service 들이 있는 Map 에서 원하는 service 를...