DDD 집계의 직렬화 우수 사례


23

DDD에 따르면 도메인 로직은 직렬화, 객체 관계형 매핑 등과 같은 기술적 문제로 오염되어서는 안됩니다.

그렇다면 게터와 세터를 통해 공개적으로 노출시키지 않고 어떻게 집계 상태를 직렬화하거나 매핑합니까? 예를 들어 리포지토리 구현에 대한 많은 예를 보았지만 실제로는 모두 엔터티에 대한 공용 접근 자와 매핑을위한 값 개체에 의존했습니다.

공개 접근자를 피하기 위해 리플렉션을 사용할 수 있지만, IMO 도메인 개체는 여전히 직렬화 문제에 암시 적으로 의존합니다. 예를 들어 직렬화 / 매핑 구성을 조정하지 않고 개인 필드의 이름을 바꾸거나 개인 필드를 제거 할 수 없습니다. 따라서 도메인 논리에 중점을 두어야하는 직렬화를 고려해야합니다.

그렇다면 여기에 따라야 할 최선의 타협은 무엇입니까? 공개 접근 자와 함께 살지만 매핑 코드 이외의 용도로는 사용하지 않습니까? 아니면 내가 명백한 것을 그리워 했습니까?

DDD 도메인 객체 (엔터티 및 값 객체로 구성된 집합)의 상태를 직렬화하는 데 명시 적으로 관심이 있습니다. 이는 상태 비 저장 서비스가 간단한 데이터 컨테이너 개체에서 작동하는 일반 또는 전이 스크립트 시나리오의 직렬화와 관련이 없습니다 .

답변:


12

물건의 종류

논의의 목적으로, 우리의 객체를 세 가지 다른 종류로 나누겠습니다.

비즈니스 도메인 로직

이것들은 작업을 수행하는 객체입니다. 그들은 하나의 당좌 계좌에서 다른 당좌 계좌로 돈을 옮기고, 주문을 이행하며, 비즈니스 소프트웨어가 취할 것으로 예상 되는 다른 모든 행동을 합니다.

도메인 논리 객체에는 일반적으로 접근 자 (getter 및 setter)가 필요하지 않습니다. 오히려 생성자를 통해 종속성을 전달하여 객체를 만든 다음 메서드를 통해 객체를 조작하십시오 (텔레, 요청하지 않음).

데이터 전송 객체

데이터 전송 객체는 순수한 상태입니다. 비즈니스 로직이 포함되어 있지 않습니다. 그들은 항상 접근자가 있습니다. 불변의 방식으로 글을 쓰는지 여부에 따라 세터가 있거나 없을 수 있습니다 . 생성자에서 필드를 설정하면 객체의 수명 동안 값이 변경되지 않거나 접근자가 읽기 / 쓰기가됩니다. 실제로 이러한 개체는 일반적으로 변경 가능하므로 사용자가 편집 할 수 있습니다.

모델 객체보기

뷰 모델 객체에는 표시 가능 / 편집 가능한 데이터 표현이 포함됩니다. 여기에는 일반적으로 데이터 유효성 검사에 국한된 비즈니스 로직이 포함될 수 있습니다. 뷰 모델 개체의 예로는 고객 개체, 송장 헤더 개체 및 송장 품목이 포함 된 InvoiceViewModel이 있습니다. 뷰 모델 객체에는 항상 접근자가 포함됩니다.

따라서 필드 접근자를 포함하지 않는다는 점에서 "순수"할 수있는 유일한 개체는 Domain Logic 개체입니다. 이러한 개체를 직렬화하면 현재 "계산 상태"가 저장되므로 나중에 검색하여 처리를 완료 할 수 있습니다. 뷰 모델과 DTO는 자유롭게 직렬화 할 수 있지만 실제로는 데이터가 데이터베이스에 저장됩니다.

직렬화, 종속성 및 커플 링

직렬화가 종속성을 생성하는 것은 사실이지만 호환 가능한 개체로 역 직렬화해야한다는 의미에서 직렬화 구성을 변경해야하는 것은 아닙니다. 좋은 직렬화 메커니즘은 일반적인 목적입니다. 값을 멤버에 매핑 할 수있는 한 속성이나 멤버의 이름을 변경해도 상관 없습니다. 실제로 이것은 직렬화 표현 (xml, json 등)이 새 객체와 호환 가능하도록 객체 인스턴스를 다시 직렬화해야 함을 의미합니다. 시리얼 라이저에 대한 구성 변경이 필요하지 않습니다.

객체가 직렬화되는 방식에 관심을 가져서는 안된다는 것은 사실입니다. 이러한 우려가 도메인 클래스에서 분리 될 수있는 한 가지 방법 인 이미 설명했습니다. 리플렉션. 그러나 serializer 개체를 serialize하고 deserialize하는 방법에 대해 염려 해야 합니다. 결국 그 기능입니다. 객체를 직렬화 프로세스에서 분리하는 방법은 직렬화를 범용 기능 으로 만들어 모든 객체 유형에서 작동 할 수 있도록하는 것입니다.

사람들이 혼란스러워하는 것 중 하나는 디커플링이 양방향으로 발생해야한다는 것입니다. 그렇지 않습니다. 방향으로 만 작동해야합니다 . 실제로는 완전히 분리 할 수 ​​없습니다. 항상 몇 가지 커플 링이 있습니다. 느슨한 결합의 목표는 모든 종속성을 제거하지 않고 코드 유지 관리를보다 쉽게 ​​만드는 것입니다.


디커플링에 대한 귀하의 의견에 동의합니다. 시리얼 라이저는 도메인 객체에 의존하며 괜찮습니다. 그러나 다른 방법은 아닙니다. 그러나 도메인 개체의 공개 접근 자에 대한 귀하의 견해에 동의하지 않습니다. 실제로 그들은 종종 그것들을 가지고 있습니다. 그러나 IMO는 깨끗한 객체 지향 디자인으로 도메인 로직을 구현하는 것이 바람직합니다. Tell, do n't ask . 그러나 여전히 매핑 목적 (ORM, 직렬화, GUI ...)을 위해서는 접근자가 필요합니다. 그리고 그것이 가능하다면 피하고 싶은 것입니다.
EagleBeak

접근자가없는 경우 필드에 어떻게 액세스 할 계획입니까?
Robert Harvey

실제로 저는 여러분이 설명하는 세 가지 종류의 개체 중 어느 것도 언급하지 않고 DDD 용어와 하위 개체 (엔티티, 가치 개체)에서 "집합" 합니다. 나는 지금 내 질문이 이것에 대해 충분히 명확하지 않다는 것을 알고 있습니다. 죄송합니다! 위의 편집 내용을 참조하십시오.
EagleBeak

1
이것은 기본적으로 해결되지 않은 문제입니다. DTO를 노출시키는 동시에 캡슐화, 디커플링 및 직렬화 / 인코딩을 할 수없는 것은 타협을 달성하는 한 가지 방법입니다. 그러나 훨씬 덜 방해적인 방법이 있습니다 : yegor256.com/2016/07/06/data-transfer-object.html
Basilevs

1
캡슐화가 떨어지면 누구나 친구 클래스를 구현하거나 사용하여 객체의 내부를 읽을 수 있습니다.
Basilevs

-1

직렬화의 기본 목적은 하나의 시스템에서 생성 된 데이터를 하나 이상의 호환 가능한 시스템에서 사용할 수 있도록하는 것입니다.

직렬화에 대한 가장 쉽고 강력한 접근 방식은 데이터를 구조를 단순하고 사용하기 쉬운 형식으로 유지하는 형식에 무관 한 형식으로 변환하는 것입니다. 예를 들어 가장 보편적 인 직렬화 형식 (예 : JSON, XML)은 잘 정의 된 텍스트 기반 형식을 사용합니다. 텍스트는 제작, 전송 및 소비가 간단합니다.

이러한 형식 중 하나를 사용하는 것이 이상적이지 않은 두 가지 이유가 있습니다.

  1. 능률

    모든 데이터를 텍스트 기반으로 변환하는 데는 고유 비용이 있습니다. 텍스트가 모든 다른 형태의 데이터를 표현하는 가장 효율적인 방법이라면 데이터 유형이 존재하지 않을 것입니다. 또한 이러한 형식의 구조는 데이터의 하위 집합을 비동기 적으로 또는 부분적으로 검색하는 데 이상적이지 않습니다.

    예를 들어, XML과 JSON은 사용중인 데이터가 처음부터 끝까지 쓰여지고 읽힐 것이라고 가정합니다. 메모리가 부족한 매우 큰 데이터 세트를 처리하려면 데이터를 소비하는 시스템에서 데이터를 부분적으로 처리하는 기능이 필요할 수 있습니다. 이 경우, 데이터를 처리하기 위해 특수 목적 직렬화 / 직렬화 구현이 필요할 수 있습니다.

  2. 정도

    의도 된 유형에서 데이터에 무관 한 유형으로 데이터를 직렬화 / 역 직렬화하는 데 필요한 캐스팅은 정밀도 손실을 초래합니다.

객체와 데이터의 이진 표현을 생성하는 것이 가장 효율적이고 정확한 솔루션이라고 주장 할 수 있습니다. 가장 큰 단점은 데이터를 소비하고 생산하는 모든 시스템의 구현이 호환성을 유지해야한다는 것입니다. 이론 상으로는 간단한 제약이지만 생산 시스템이 시간이 지남에 따라 변화 / 진화하는 경향이 있기 때문에 실제로 유지 관리하는 것은 악몽입니다.

그것으로 말했다. 도메인 별 세부 정보에서 직렬화 / 직렬화를 분리하면 일반적으로 범용 형식이보다 강력하고 다양한 시스템에서 더 잘 지원되며 유지 보수 오버 헤드가 거의 또는 전혀 필요하지 않기 때문에 일반적으로 의미가 있습니다.


죄송하지만이 질문에 대한 답변이 아닙니다. 직렬화의 이유나 다양한 형식의 장단점이 아니라 직렬화에서 도메인 객체를 분리하는 것입니다. 비공개 상태를 공개적으로 노출시키지 않고 도메인 객체를 어떻게 직렬화합니까?
EagleBeak

@EagleBeak 아, 나는 당신의 걱정이 특별히 개인 회원을 다루는 것에 대해 몰랐습니다. 귀하의 경우에는 수신 시스템이 도메인 객체가 생성 된 것과 동일한 규칙 / 구조를 따르는 것으로 바이너리로 직렬화하거나 직렬화 전에 공개 데이터 만 추출하는 논리를 작성할 수 있습니다.
Evan Plaice

'일반적인'가정은 범용 형식 (예 : xml, json)으로 직렬화되는 데이터가 공개되고 ACL 또는 이와 동등한 다른 요소를 통해 API를 통해 권한이 제어된다고 가정합니다. 범용 직렬화 / 역 직렬화는 한 시스템에서 다른 시스템으로 이동하는 비즈니스 논리에서 데이터를 분리하는 선에 더 많이 속합니다.
Evan Plaice

나는 공개 접근자가 일반적으로 직렬화 될 객체에서 가정되는 것에 동의합니다. 그러나 나는 이것이 이것이 DDD와 어떻게 관련되는지, 그리고 도메인 로직 캡슐화에 대한 초점에 대해 더 알고 싶습니다. 모든 DDD 실무자는 직렬화를 위해 공개 접근자를 통해 도메인 모델의 상태를 노출합니까 (예시하지 마십시오)? 나는 그것을 의심한다. 제발 내가 틀리지 마 귀하의 의견을 보내 주셔서 감사합니다. 다른 측면에 관심이 있다는 것입니다. (지금까지 나는 내 질문이 너무 막연한 생각하지 않지만, 로버트 하비의 대답하고 당신은 내가 그것에 대해 생각하고 있어요 ..)
EagleBeak에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.