2016-05-10 8 views
7

मैं डोमेन संचालित डिज़ाइन अवधारणाओं के लिए बिल्कुल नया हूं और डोमेन लॉजिक के लिए कमांड और कमांड हैंडलर के साथ कमांड बस का उपयोग करते समय एक एपीआई में उचित प्रतिक्रियाओं को वापस करने में समस्या आई है।कमांड बस से डेटा कैसे प्राप्त करें?

मान लें कि हम एक डोमेन संचालित डिजाइन दृष्टिकोण के साथ एक एप्लिकेशन बना रहे हैं। हमारे पास बैक एंड एंड फ्रंट एंड पार्ट है। बैक एंड में हमारे सभी डोमेन लॉजिक एक खुला एपीआई के साथ हैं। फ्रंट एंड एप्लिकेशन को अनुरोध करने के लिए एपीआई का उपयोग करता है।

हम कमांड बस में मैप किए गए कमांड और कमांड हैंडलर के साथ हमारे डोमेन तर्क बना रहे हैं। हमारी डोमेन निर्देशिका के तहत हमारे पास CreatePostCommand नामक एक पोस्ट संसाधन बनाने के लिए एक आदेश है। यह कमांड बस के माध्यम से अपने हैंडलर CreatePostCommandHandler पर मैप किया गया है।

final class CreatePostCommand 
{ 
    private $title; 
    private $content; 

    public function __construct(string $title, string $content) 
    { 
     $this->title = $title; 
     $this->content= $content; 

    } 

    public function getTitle() : string 
    { 
     return $this->title; 
    } 

    public function getContent() : string 
    { 
     return $this->content; 
    } 
} 

final class CreatePostCommandHandler 
{ 
    private $postRepository; 

    public function __construct(PostRepository $postRepository) 
    { 
     $this->postRepository = $postRepository; 
    } 

    public function handle(Command $command) 
    { 
     $post = new Post($command->getTitle(), $command->getContent()); 
     $this->postRepository->save($post); 
    } 
} 

हमारे एपीआई में हमारे पास एक पोस्ट बनाने के लिए एक अंतराल है। यह हमारी अनुप्रयोग निर्देशिका के तहत PostController में createPost विधि को रूट किया गया है।

final class PostController 
{ 
    private $commandBus; 

    public function __construct(CommandBus $commandBus) 
    { 
     $this->commandBus = $commandBus; 
    } 

    public function createPost($req, $resp) 
    { 
     $command = new CreatePostCommand($command->getTitle(), $command->getContent()); 
     $this->commandBus->handle($command); 

     // How do we get the data of our newly created post to the response here? 

     return $resp; 
    } 
} 

अब हमारे createPost विधि में हम अपने प्रतिक्रिया ऑब्जेक्ट में हमारे नव निर्मित पोस्ट के डेटा लौटाने के लिए तो हमारे सामने के छोर आवेदन नव निर्मित संसाधन के बारे में पता कर सकते हैं चाहता हूँ। यह परेशानी है क्योंकि हम जानते हैं कि परिभाषा के अनुसार कमांड बस को किसी भी डेटा को वापस नहीं करना चाहिए। तो अब हम एक भ्रमित स्थिति में फंस गए हैं जहां हम नहीं जानते कि प्रतिक्रिया ऑब्जेक्ट में हमारी नई पोस्ट कैसे जोड़ें।

मुझे यकीन है कि यहां से इस समस्या के साथ आगे बढ़ने के लिए कैसे नहीं हूँ, कई सवाल मन में आते हैं:

  • वहाँ जवाब में पोस्ट की डेटा लौटाने के लिए एक सुंदर तरीका है?
  • क्या मैं कमांड/कमांड हैंडलर/कमांडबस पैटर्न को गलत तरीके से कार्यान्वित कर रहा हूं?
  • क्या यह कमान/कमांडहैंडलर/कमांडबस पैटर्न के लिए बस गलत उपयोग केस है?
+0

संभावित डुप्लिकेट [सीक्यूआरएस कमांड के लिए एपीआई से क्या वापस किया जाना चाहिए?] (Http://stackoverflow.com/questions/29916468/what-should-be-returned-from-the-api-for-cqrs- आदेश) – guillaume31

उत्तर

8

सबसे पहले, ध्यान दें कि अगर हम आदेश हैंडलर के लिए सीधे नियंत्रक तार, हम एक ऐसी ही समस्या का सामना:

public function createPost($req, $resp) 
    { 
     $command = new CreatePostCommand($command->getTitle(), $command->getContent()); 
     $this->createPostCommandHandler->handle($command); 

     // How do we get the data of our newly created post to the response here? 
     return $resp; 
    } 

बस अविवेक की एक परत पेश कर रहा है, तो आप से नियंत्रक दसगुणा करने की इजाजत दी इवेंट हैंडलर, लेकिन जिस समस्या में आप चल रहे हैं वह अधिक मौलिक है।

मुझे यकीन है कि यहाँ

टीएल से इस समस्या के साथ आगे बढ़ने के लिए कैसे नहीं हूँ, डा -, डोमेन क्या पहचानकर्ता का उपयोग करने के लिए बता नहीं बल्कि डोमेन क्या पहचानकर्ता इस्तेमाल किया था पूछ की तुलना में।

public function createPost($req, $resp) 
    { 
     // TADA 
     $command = new CreatePostCommand($req->getPostId() 
       , $command->getTitle(), $command->getContent()); 

     $this->createPostCommandHandler->handle($command); 

     // happy path: redirect the client to the correct url 
     $this->redirectTo($resp, $postId) 
    } 

संक्षेप में, ग्राहक के बजाय डोमेन मॉडल या हठ परत, नई इकाई की आईडी पैदा करने की जिम्मेदारी का मालिक है। एप्लिकेशन घटक कमांड में पहचानकर्ता को पढ़ सकता है, और अगले राज्य संक्रमण को समन्वयित करने के लिए इसका उपयोग कर सकता है।

आवेदन, इस कार्यान्वयन में, डोमेन प्रतिनिधित्व के लिए डीटीओ प्रतिनिधित्व से संदेश का अनुवाद कर रहा है।

एक वैकल्पिक कार्यान्वयन आदेश पहचानकर्ता का उपयोग करता है, और कहा कि आदेश से पहचान है कि इस्तेमाल किया जाएगा

 $command = new CreatePostCommand(
       $this->createPostId($req->getMessageId()) 
       , $command->getTitle(), $command->getContent()); 

Named UUIDs उत्तरार्द्ध मामले में एक आम पसंद कर रहे हैं निकला है; वे निर्धारक हैं, और छोटी टकराव की संभावनाएं हैं।

अब, यह जवाब धोखाधड़ी का कुछ है - हमने वास्तव में केवल यह दिखाया है कि हमें इस मामले में कमांड हैंडलर के परिणाम की आवश्यकता नहीं है।

आम तौर पर, हम एक होना पसंद करेंगे; पोस्ट/रीडायरेक्ट/डोमेन मॉडल को अपडेट करने के लिए उपयोग करने के लिए एक अच्छा मुहावरे है, लेकिन जब ग्राहक संसाधन प्राप्त करता है, तो हम यह सुनिश्चित करना चाहते हैं कि उन्हें एक संस्करण मिल रहा है जिसमें वे अभी भी किए गए संपादन शामिल हैं।

यदि आपके पढ़ने और लिखने रिकॉर्ड की एक ही पुस्तक का उपयोग कर रहे हैं, तो यह कोई समस्या नहीं है - जो भी आप पढ़ते हैं वह हमेशा सबसे हालिया संस्करण उपलब्ध है।

हालांकि, डोमेन संचालित डिज़ाइन में एक सामान्य वास्तुशिल्प पैटर्न है, जिस स्थिति में लेखन मॉडल (पोस्ट को संभालना) रीड मॉडल पर रीडायरेक्ट करेगा - जो आम तौर पर स्टेल डेटा प्रकाशित कर रहा है। तो आप अनुरोध प्राप्त करने में न्यूनतम संस्करण शामिल करना चाह सकते हैं, ताकि हैंडलर अपने पुराने कैश को रीफ्रेश करना जानता हो।

क्या प्रतिक्रिया में पोस्ट के डेटा को वापस करने का एक शानदार तरीका है?

वहाँ आप अपने प्रश्न के साथ प्रदान की कोड नमूने में एक उदाहरण है:

public function createPost($req, $resp) 

इसके बारे में सोचो: $ अनुरोध http अनुरोध संदेश, जो मोटे तौर अपने आदेश के अनुरूप है की एक प्रतिनिधित्व है, और $ resp अनिवार्य रूप से डेटा संरचना के लिए एक हैंडल है जिसे आप अपना परिणाम लिख सकते हैं।

दूसरे शब्दों में, कॉलबैक पास करें या परिणाम कमांड को अपने आदेश के साथ पास करें, और कमांड हैंडलर विवरण भरें।

बेशक, यह आपकी बस सहायक कॉलबैक पर निर्भर करता है; गारंटी नहीं है।

एक अन्य संभावना, जो आपके कमांड हैंडलर के हस्ताक्षर को बदलने की आवश्यकता नहीं है, यह है कि नियंत्रक कमांड हैंडलर द्वारा प्रकाशित घटनाओं की सदस्यता लेता है। आप आदेश और घटना के बीच correlation id समन्वयित करते हैं, और उस परिणाम ईवेंट को खींचने के लिए इसका उपयोग करें जो आपको चाहिए।

बारीकियों बहुत ज्यादा फर्क नहीं है - जब आदेश प्रसंस्करण संदेश बस के लिए लिखा जा सकता है, या एक मेलबॉक्स में नकल, या उत्पन्न घटना ....

+0

हालांकि मैं मानता हूं कि यह एक संभावित समाधान है, मैं आपके द्वारा दिए गए कारणों से पूरी तरह से नहीं हूं। आपको 'Create' कमांड idempotent बनाने की आवश्यकता क्यों होगी? यदि लक्ष्य इसे दोहराने योग्य है, तो आप किस मामले में इसे दोहराना चाहते हैं (उसी आईडी के साथ, वह है)? – guillaume31

+0

इसके अलावा, मैं आवेदन (सेवा?) और कमांड हैंडलर के बीच आपके द्वारा किए गए भेद पर बेचा नहीं गया है, और इसके प्रभाव हैं। क्या इसका मतलब यह है कि नियंत्रक आपके मामले में आवेदन सेवा है? क्या आप डोमेन में कमांड हैंडलर रखते हैं? – guillaume31

+0

@ guillaume31 एक टिकाऊ सेवा बस का उपयोग करते समय, आप किसी भी संदेश हैंडलर में डुप्लिकेट परिवर्तनों को रोकने के लिए idempotency चाहते हैं। उस कमांड हैंडलर में डीडीडी में एक आवेदन सेवा की भूमिका है। – MikeSW

2

मैं इस दृष्टिकोण का उपयोग कर रहा हूँ और मैं कमांड परिणाम लौट रहा हूँ। हालांकि, यह एक समाधान है जो केवल काम करता है यदि कमांड हैंडलर एक ही प्रक्रिया का हिस्सा हैं। असल में, मैं मध्यस्थ का उपयोग कर रहा हूं, नियंत्रक और कमांड हैंडलर इसका एक उदाहरण प्राप्त करता है (आमतौर पर एक कन्स्ट्रक्टर निर्भरता के रूप में)।

छद्म कोड नियंत्रक

var cmd= new MyCommand(); 
var listener=mediator.GetListener(cmd.Id); 
bus.Send(cmd); 
//wait until we get a result or timeout 
var result=listener.Wait(); 
return result; 

छद्म कोड आदेश हैंडलर समारोह

var result= new CommandResult(); 
add some data here 
mediator.Add(result,cmd.Id); 

है कि कैसे आप तत्काल प्रतिक्रिया मिलता है। हालांकि, इसका उपयोग किसी व्यवसाय प्रक्रिया को लागू करने के लिए नहीं किया जाना चाहिए।

बीटीडब्ल्यू, इसका डीडीडी से कोई लेना देना नहीं है, यह मूल रूप से एक संदेश संचालित सीक्यूएस दृष्टिकोण है जो इसे डीडीडी ऐप में उपयोग किया जा सकता है।

+0

स्पष्ट नहीं है कि कमांड हैंडलर को एक ही प्रक्रिया का हिस्सा क्यों होना चाहिए; यह एक सीधी आगे संदेश विनिमय की तरह दिखता है, जो प्रक्रिया सीमाओं में काम करता है। – VoiceOfUnreason

+0

@VoiceOfUnreason क्योंकि प्रक्रिया सीमाओं को पार करने वाली हर चीज में लंबे समय तक चलने की क्षमता है और सबकुछ बहुत जटिल हो जाता है। यह एक साधारण समाधान है जो उस बाधा के साथ बहुत अच्छा काम करता है – MikeSW

संबंधित मुद्दे