Command 자체에서 메소드를 처리하는 대신 클래스 CommandHandler를 Handle ()로 분리하는 이유


13

다음 과 같이 S # arp 아키텍처를 사용하여 CQRS 패턴의 일부를 구현 했습니다.

public class MyCommand
{
    public CustomerId { get; set; }

    // some other fields
}

public class MyCommandHandler<MyCommand> : ICommandHandler<MyCommand, CommandResult>
{
    Handle(MyCommand command)
    {
        // some code for saving Customer entity

        return CommandResult.Success;
    }
}

Command데이터 처리 방법 을 모두 포함하는 클래스 가 없는지 궁금합니다 . 명령 속성과 별도로 명령 처리 논리를 테스트해야하는 일종의 테스트 가능성 이점이 있습니까? 또는 다른 구현으로 하나의 명령을 처리 해야하는 비즈니스 요구 사항이 자주 ICommandHandler<MyCommand, CommandResult>있습니까?


나는 같은 질문을 가지고 가치가있다 : blogs.cuttingedge.it/steven/posts/2011/…
rdhaundiyal

답변:


14

재밌는 질문입니다.이 질문은 엔지니어 중 한 명과 제가 작업하고있는 통신 라이브러리에 대해했던 것과 똑같은 대화를 상기시켜주었습니다.

명령 대신 Request 클래스가 있었고 RequestHandlers가있었습니다. 디자인은 당신이 묘사 한 것과 매우 흡사합니다. 혼동의 일부는 영어 단어 "command"를보고 즉시 "verb, action ... 등"을 생각한다는 것입니다.

그러나이 디자인에서는 명령 (또는 요청)을 문자로 생각하십시오. 또는 우편 서비스가 무엇인지 모르는 사람들은 전자 우편을 생각하십시오. 그것은 단순히 내용이며, 그 내용이 어떻게 행동해야 하는가와 분리되어 있습니다.

왜 이렇게 하시겠습니까? 대부분의 간단한 경우, 명령 패턴은 이유가 없으며이 클래스가 직접 작업을 수행하도록 할 수 있습니다. 그러나 동작 / 명령 / 요청이 일정 거리를 이동해야하는 경우 디자인 에서처럼 분리를 수행하는 것이 좋습니다. 예를 들어, 소켓 또는 파이프, 또는 도메인과 인프라 사이. 또는 아키텍처에서 명령이 지속적이어야합니다 (예 : 명령 처리기는 일부 시스템 이벤트, 200 개의 명령이 도착하고 처음 40 개의 프로세스가 종료 된 후 한 번에 1 개의 명령을 수행 할 수 있음). 이 경우 간단한 메시지 전용 클래스를 사용하면 메시지 부분 만 JSON / XML / binary / 무엇으로 직렬화하고 명령 처리기가 처리 할 준비가 될 때까지 파이프 라인에 전달하는 것이 매우 간단 해집니다.

CommandHandler에서 Command를 분리 할 때의 또 다른 장점은 이제 병렬 상속 계층 구조 옵션이 있다는 것입니다. 예를 들어, 모든 명령은 직렬화를 지원하는 기본 명령 클래스에서 파생 될 수 있습니다. 그리고 유사성이 많은 20 개 중 4 개의 명령 핸들러가있을 수 있습니다. 이제 처리기 기본 클래스에서 파생 할 수 있습니다. 한 클래스에서 데이터 및 명령 처리를 수행해야한다면 이러한 유형의 관계는 빠르게 제어 할 수 없게됩니다.

디커플링의 또 다른 예는 명령에 입력이 거의 필요하지 않은 경우 (예 : 2 개의 정수 및 문자열) 처리 논리가 복잡하여 중간 멤버 변수에 데이터를 저장하려는 경우에 복잡 할 수 있습니다. 50 개의 명령을 대기열에 넣는 경우 모든 중간 저장소에 메모리를 할당하지 않으려 고 CommandCommand와 Command를 분리합니다. 이제 50 개의 경량 데이터 구조를 큐에 넣고 더 복잡한 데이터 스토리지는 명령을 처리하는 CommandHandler에 의해 한 번만 (또는 N 핸들러가있는 경우 N 번) 할당됩니다.


요점은이 문맥에서 명령 / 요청이 원격 / 지속되지 않는 것 등이 아니라는 점입니다. 직접 처리됩니다. 그리고 두 가지를 분리하면 상속에 어떻게 도움이되는지 알 수 없습니다. 실제로 어렵게 만듭니다. 마지막 단락도 그리워요. 객체 생성은 비용이 많이 들지 않으며 50 개의 명령은 무시할 수 있습니다.
Euphoric

@ 유포 릭 : 컨텍스트가 무엇인지 어떻게 알 수 있습니까? S # arp 아키텍처가 특별한 것이 아니라면 클래스 선언 몇 개만보고 나머지 응용 프로그램에서 어떻게 사용되는지 전혀 모릅니다. 50과 같이 선택한 숫자가 마음에 들지 않으면 초당 50과 같은 것을 선택하십시오. 충분하지 않으면 초당 1000을 선택하십시오. 방금 예제를 제공하려고했습니다. 아니면 이 문맥에서 그는 많은 명령을 가질 것이라고 생각하지 않습니까?
DXM

예를 들어, 정확한 구조는 weblogs.asp.net/shijuvarghese/archive/2011/10/18/…에 있습니다. 그리고 어디에도 당신이 한 말이 있습니다. 그리고 속도에 관한 문제는 프로파일 링없이 '성능'인수를 사용한다는 것입니다. 그러한 처리량에 대한 요구 사항이있는 경우 일반 아키텍처를 사용하지 않고보다 전문적인 것을 구축하십시오.
Euphoric

1
이것이 마지막 요점인지 확인해 보겠습니다. OP는 예를 요구했습니다. 예를 들어, 먼저 간단한 방법을 디자인하고 응용 프로그램이 작동 한 다음 확장하고 명령 패턴을 사용하는 장소를 확장합니다. 라이브로 이동하여 10,000 대의 머신이 서버와 통신하고 서버는 여전히 원래 아키텍처를 사용하고 문제를 프로파일 링하고 식별 한 다음 명령 처리와 명령 데이터를 분리 할 수 ​​있지만 프로파일 링 후에 만 ​​가능합니다. 답변에이 모든 것을 포함 시키면 정말 더 행복해 질까요? 그는 예를 물었고 나는 그에게 하나를 주었다.
DXM

... 방금 게시 한 블로그 게시물을 살펴 보았고 내가 쓴 것과 일치하는 것처럼 보입니다. 명령이 멀리 이동 해야하는 경우 분리하십시오. 블로그에서 그는 기본적으로 다른 파이프, 소켓, 메시지 대기열, esb 등의 명령 버스를 언급하는 것 같습니다
DXM

2

일반적인 명령 패턴 은 단일 클래스에서 데이터와 동작을 갖는 것입니다. 이런 종류의 '명령 / 처리기 패턴'은 약간 다릅니다. 일반적인 패턴과 비교할 때 유일한 장점은 명령이 프레임 워크에 의존하지 않는다는 이점이 있습니다. 예를 들어, 명령에 DB 액세스가 필요할 수 있으므로 일종의 DB 컨텍스트 또는 세션이 있어야합니다. 즉, 이는 프레임 워크에 따라 다릅니다. 그러나이 명령은 도메인의 일부일 수 있으므로 Dependency Inversion Principle 에 따라 프레임 워크에 의존하지 않기를 원합니다 . 동작에서 입력 및 출력 매개 변수를 분리하고 디스패처를 연결하여이를 해결할 수 있습니다.

반면에, 당신은 상속과 명령 구성의 이점을 잃게 될 것입니다. 그것이 진정한 힘이라고 생각합니다.

또한 작은 이쑤시개. 이름에 Command가 있다고해서 CQRS에 포함되지는 않습니다. 그것은 훨씬 더 근본적인 것입니다. 이런 종류의 구조는 명령과 쿼리로 동시에 제공 될 수 있습니다.


링크 weblogs.asp.net/shijuvarghese/archive/2011/10/18/… 을 보았지만 S # arp Arch 코드에 버스 신호가 표시되지 않습니다. 따라서 필자의 경우 이러한 분리는 클래스를 확산시키고 논리를 밝게합니다.
rgripper

1
@rgripper 그렇다면 당신은 제대로 검색하지 않았습니다. github.com/sharparchitecture/Sharp-Architecture/blob/…github.com/sharparchitecture/Sharp-Architecture/blob/…
Euphoric

흠, 지적 해 주셔서 감사합니다. 그런 다음 ICommandProcessor가있는 코드에서 IOC가되어 CommandProcessor (명령 처리기의 IOC를 만드는 자체)-진흙 투성이의 컴포지션으로 인해 내 경우는 조금 더 나쁩니다. 그리고이 프로젝트에는 명령을 내기 위해 두 명 이상의 직원을위한 비즈니스 사례가없는 것 같습니다.
rgripper
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.