การจัดหากิจกรรมและส่วนที่เหลือ


17

ฉันเจอการออกแบบการจัดหากิจกรรมและฉันต้องการใช้ในแอปพลิเคชันที่ต้องการให้ไคลเอ็นต์ REST (RESTful แม่นยำ) อย่างไรก็ตามฉันล้มเหลวในการเชื่อมต่อสิ่งเหล่านี้เข้าด้วยกันเนื่องจาก REST ค่อนข้างคล้ายกับ CRUD และการจัดหากิจกรรมเป็นงานที่ต้องทำ ฉันสงสัยว่าคุณจะออกแบบการสร้างคำสั่งตามคำขอไปยังเซิร์ฟเวอร์ REST ได้อย่างไร ลองพิจารณาตัวอย่างนี้:

ด้วย REST คุณสามารถกำหนดสถานะใหม่ให้กับทรัพยากรที่เรียกว่าไฟล์ ในคำขอเดียวคุณสามารถส่งชื่อไฟล์ใหม่คุณสามารถเปลี่ยนโฟลเดอร์หลักและ / หรือเปลี่ยนเจ้าของไฟล์และอื่น ๆ

วิธีสร้างเซิร์ฟเวอร์เพื่อให้ฉันสามารถใช้การจัดหากิจกรรมได้ ฉันคิดถึงความเป็นไปได้เหล่านี้:

  1. ตรวจสอบบนเซิร์ฟเวอร์ซึ่งสาขาที่มีการเปลี่ยนแปลงและสร้างคำสั่งที่เหมาะสม ( RenameFileCommand, MoveFileCommand, ChangeOwnerCommand, ... ) และจัดส่งเหล่านี้ที อย่างไรก็ตามในการตั้งค่านี้แต่ละคำสั่งสามารถล้มเหลวในการปล่อยให้ผู้อื่นออกจากการทำธุรกรรมและจากการเปลี่ยนแปลง "atomic" เป็นทรัพยากร

  2. ส่งเพียงหนึ่งคำสั่ง ( UpdateFileCommand) และในการจัดการคำสั่งอย่างแม่นยำมากขึ้นในการรวม, ตรวจสอบว่ามีการเปลี่ยนแปลงเขตและส่งแต่ละเหตุการณ์แทน ( FileRenamedEvent, FileMovedEvent, OwnerChangedEvent, ... )

  3. อันนี้ฉันไม่ชอบเลย: ในคำขอไปยังเซิร์ฟเวอร์ฉันจะระบุในส่วนหัวของคำสั่งที่จะใช้เพราะ UI ยังคงเป็นงานที่ใช้ (การสื่อสารจะทำผ่าน REST) อย่างไรก็ตามมันจะล้มเหลวในการใช้งานการสื่อสาร REST อื่น ๆ (เช่นในแอพภายนอก) เนื่องจากพวกเขาไม่ผูกพันที่จะเปลี่ยนเพียงหนึ่งฟิลด์ในคำขอเดียว นอกจากนี้ฉันได้นำการเชื่อมต่อที่ค่อนข้างใหญ่เข้ากับแบ็กเอนด์ UI, REST และ ES

คุณจะเลือกอันไหนดีหรือมีวิธีไหนที่ดีกว่าในการจัดการกับสิ่งนี้?

หมายเหตุด้าน: แอพที่เขียนใน Java และ Axon Framework สำหรับการจัดหากิจกรรม


ไม่แน่นอนที่ 3 ฉันจะทำอันดับที่ 1 แต่ฉันต้องคิดเกี่ยวกับมัน
inf3rno

คุณมีคำถามว่าคำขอ HTTP ครั้งเดียวสามารถส่งผลให้หลายคำสั่งได้หรือไม่ ฉันเข้าใจดีหรือไม่ imho มันควรจะทำเช่นนั้น แต่ฉันไม่ได้อ่าน DDD มาระยะหนึ่งแล้วดังนั้นฉันต้องตรวจสอบโค้ดตัวอย่างเกี่ยวกับวิธีใช้สิ่งนี้
inf3rno

ฉันพบตัวอย่าง แต่มันเป็น CRUD github.com/szjani/predaddy-issuetracker-sample/blob/3.0/src/hu/…ฉันจะถามผู้เขียนว่าความเห็นของเขาคืออะไรเขารู้เพิ่มเติมเกี่ยวกับ DDD มากกว่าฉัน
inf3rno

1
ของฉันคือคุณควรใช้หลายคำสั่งใน "หน่วยงาน" ถ้าคุณต้องการความมั่นคงทันที หากคุณกำลังพูดถึงความมั่นคงในที่สุดคำถามก็ไม่สมเหตุสมผลสำหรับฉัน อีกวิธีที่เป็นไปได้ในการส่ง CompositeCommand ซึ่งสามารถมีคำสั่งที่คุณต้องการเรียกใช้งานแบบอะตอม มันอาจเป็นคอลเล็กชั่นเรียบง่ายสิ่งเดียวที่สำคัญที่รถบัสสามารถจัดการได้อย่างเหมาะสม
inf3rno

1
ตามที่คุณควรพยายามบรรลุความสัมพันธ์ 1: 1 ระหว่างคำสั่งและคำขอ HTTP หากคุณไม่สามารถทำได้ (นั่นคือกลิ่นเหม็น) คุณควรใช้จำนวนมาก (ฉันเรียกมันว่าคอมโพสิต) เพื่อทำให้เป็นอะตอม
inf3rno

คำตอบ:


11

ฉันคิดว่าคุณอาจมีกระบวนการผู้ใช้ในการปรับใช้ไม่ตรงกันที่นี่

ครั้งแรก: ผู้ใช้จะต้องการดำเนินการหลายอย่างโดยสุจริตเปลี่ยนแปลงไฟล์พร้อมกันหรือไม่ การเปลี่ยนชื่อ (ซึ่งอาจรวมถึงการเปลี่ยนเส้นทางหรือไม่) การเปลี่ยนแปลงความเป็นเจ้าของและอาจเปลี่ยนแปลงเนื้อหาไฟล์ (เพื่อเหตุผลของการโต้แย้ง) ดูเหมือนเป็นการกระทำที่แยกจากกัน

ลองดูที่คำตอบคือ "ใช่" ผู้ใช้ของคุณต้องการเปลี่ยนแปลงเหล่านี้พร้อมกัน

ในกรณีที่ผมขออยากแนะนำให้กับการดำเนินการใด ๆ ที่จะส่งเหตุการณ์หลาย - RenameFileCommand, MoveFileCommand, ChangeOwnerCommand- เพื่อเป็นตัวแทนนี้เดียวประสงค์ของผู้ใช้

ทำไม? เพราะเหตุการณ์อาจล้มเหลว อาจเป็นของหายากมาก แต่ผู้ใช้ของคุณส่งการดำเนินการที่ดูปรมาณู - ถ้าหนึ่งในเหตุการณ์ดาวน์สตรีมล้มเหลวสถานะแอปพลิเคชันของคุณจะไม่ถูกต้อง

คุณยังเชื้อเชิญอันตรายจากการแข่งขันให้กับทรัพยากรที่แบ่งปันกันอย่างชัดเจนระหว่างผู้จัดการเหตุการณ์แต่ละคน คุณจะต้องเขียน "ChangeOwnerCommand" ในลักษณะที่ชื่อไฟล์และเส้นทางไฟล์ไม่สำคัญเพราะอาจล้าสมัยเมื่อถึงเวลาที่ได้รับคำสั่ง

เมื่อใช้ระบบ restful แบบไม่ขับเคลื่อนเหตุการณ์ด้วยการย้ายและเปลี่ยนชื่อไฟล์ฉันต้องการให้แน่ใจว่ามีความสอดคล้องกันโดยใช้บางอย่างเช่นระบบ eTag - ตรวจสอบให้แน่ใจว่าเวอร์ชันของทรัพยากรที่แก้ไขนั้นเป็นเวอร์ชันที่ผู้ใช้ดึงข้อมูลล่าสุดและล้มเหลว ได้รับการแก้ไขตั้งแต่นั้นมา แต่ถ้าคุณกำลังส่งคำสั่งหลายคำสั่งสำหรับการดำเนินการของผู้ใช้คนเดียวคุณจะต้องเพิ่มรุ่นทรัพยากรของคุณหลังจากแต่ละคำสั่ง - ดังนั้นคุณจึงไม่มีทางรู้ว่าทรัพยากรที่ผู้ใช้กำลังแก้ไขเป็นรุ่นเดียวกันกับทรัพยากรที่อ่านล่าสุด .

สิ่งที่ฉันหมายถึงคือ - ถ้าคนอื่นดำเนินการอื่นในไฟล์ในเวลาใกล้เคียงกัน คำสั่ง 6 คำสั่งสามารถเรียงซ้อนกันในลำดับใดก็ได้ หากเรามีเพียง 2 คำสั่งอะตอมมิกคำสั่งก่อนหน้านี้อาจประสบความสำเร็จและคำสั่งในภายหลังอาจล้มเหลว "ทรัพยากรได้รับการแก้ไขตั้งแต่ถูกดึงครั้งสุดท้าย" แต่ไม่มีการป้องกันสิ่งนี้เมื่อคำสั่งไม่ใช่อะตอมดังนั้นระบบจึงถูกละเมิด

ที่น่าสนใจมีการเคลื่อนไหวไปยังสิ่งที่ต้องการสถาปัตยกรรมตามเหตุการณ์ในส่วนที่เหลือเรียกว่า "ส่วนที่เหลือโดยไม่ต้องใส่" แนะนำในเรดาร์เทคโนโลยี ThoughtWorks, มกราคม 2015 มีบล็อกมากอีกต่อไปเกี่ยวกับการเป็นส่วนที่เหลือโดยไม่ต้อง PUT ที่นี่

โดยพื้นฐานแล้วแนวคิดก็คือ POST, PUT, DELETE และ GET นั้นใช้ได้กับแอปพลิเคชั่นขนาดเล็ก แต่เมื่อคุณต้องเริ่มสมมติว่าการโพสต์และลบและโพสต์และลบอาจถูกตีความที่ปลายอีกด้านหนึ่ง (เช่น "เมื่อฉันลบทรัพยากรที่เกี่ยวข้องกับบัญชีธนาคารของฉันบัญชีจะถูกปิด") และวิธีแก้ปัญหาที่เสนอคือการรักษาส่วนที่เหลือในวิธีที่มาเพิ่มเติม เช่นช่วยให้โพสต์เจตนาของผู้ใช้เป็นทรัพยากรเหตุการณ์เดียว

อีกกรณีหนึ่งนั้นง่ายกว่า หากผู้ใช้ของคุณไม่ต้องการดำเนินการเหล่านั้นพร้อมกันอย่าปล่อยให้พวกเขา โพสต์เหตุการณ์สำหรับความตั้งใจของผู้ใช้แต่ละคน ตอนนี้คุณสามารถใช้การกำหนดเวอร์ชัน etag บนทรัพยากรของคุณ

สำหรับแอพพลิเคชั่นอื่น ๆ ซึ่งใช้ API ที่แตกต่างกันมากกับทรัพยากรของคุณ กลิ่นนั้นเหมือนปัญหา คุณสามารถสร้างส่วนหน้าของ API เก่าบน RESTful API ของคุณและชี้ไปที่ส่วนหน้าได้หรือไม่ คือเปิดเผยบริการที่ดำเนินการอัปเดตหลายไฟล์เป็นลำดับผ่านเซิร์ฟเวอร์ REST หรือไม่

หากคุณไม่ได้สร้างส่วนต่อประสาน RESTful ที่ด้านบนของโซลูชันเก่าหรือสร้างส่วนต่อประสานที่อยู่ด้านบนของโซลูชัน REST และพยายามรักษา API ทั้งสองที่ชี้ไปที่แหล่งข้อมูลที่ใช้ร่วมกันคุณจะพบอาการปวดหัวที่สำคัญ


ฉันสามารถเห็นความไม่ตรงกันอย่างไรก็ตามโดย REST โดยหลักการแล้วมันเป็นไปได้ที่จะอัพเดทสถานะของหลาย ๆ ฟิลด์โดยการใส่สถานะใหม่ไปยังทรัพยากร (โดยการเป็นตัวแทนบางส่วน) นี่คือวิธีการทำงานของ REST ตามคำจำกัดความ - การถ่ายโอนสถานะแบบเป็นตัวแทนข้อเสียคือความตั้งใจของผู้ใช้จะหายไปในกระบวนการ นอกจากนี้ REST เกือบเป็นมาตรฐานสำหรับ API ภายนอก ฉันแค่ต้องการออกแบบแอพเพื่อที่ฉันจะได้ใช้ทั้งสองอย่าง การเอา PUT ออกเป็นเหมือนวิธีแก้ปัญหาเนื่องจาก ES จากสิ่งที่ฉันเห็นคำสั่ง update หนึ่งคำสั่งที่ปล่อยเหตุการณ์หลายเหตุการณ์สามารถทำได้ตราบใดที่คำสั่งและการจัดการเหตุการณ์อยู่ในธุรกรรมเดียว
แดง

Etag เป็นสิ่งที่ฉันต้องการจะทำต่อไป นอกจากนี้ลิงก์ของคุณไปยัง "บล็อกโพสต์อีกต่อไป" ก็เหมือนกับลิงค์แรก
แดง

ฉันจะกลับมาที่นี่อีกหลังจากพิจารณาด้วยความคิดที่มากขึ้น แน่นอนว่าการลบ PUT ไม่ใช่แค่ "วิธีแก้ปัญหาสำหรับ ES" เท่านั้น ฉันแก้ไขลิงก์บล็อกแล้ว
ความสมบูรณ์แบบ

4

ตอนนี้ฉันวิ่งเข้าไปในบทความต่อไปนี้ซึ่งสนับสนุนให้ระบุชื่อคำสั่งในคำขอไปยังเซิร์ฟเวอร์ในส่วนหัวของประเภทเนื้อหา (ในขณะที่ตามประเภทสื่อ 5 ระดับ)

ในบทความพวกเขาพูดถึงสไตล์ RPC ไม่ดีสำหรับ REST และแนะนำให้ขยายประเภทเนื้อหาเพื่อระบุชื่อคำสั่ง:

วิธีการหนึ่งที่พบบ่อยคือการใช้ทรัพยากรสไตล์ RPC เช่น / api / InventoryItem / {id} / เปลี่ยนชื่อ แม้ว่าสิ่งนี้จะช่วยขจัดความจำเป็นในการใช้คำกริยาตามอำเภอใจ แต่เป็นการขัดต่อการนำเสนอที่เน้นทรัพยากร เราจำเป็นต้องได้รับการเตือนว่าทรัพยากรเป็นคำนามและคำกริยา HTTP เป็นคำกริยา / การกระทำและข้อความอธิบายตนเอง (หนึ่งในหลักคำสอนของ REST) ​​เป็นเครื่องมือในการถ่ายทอดแกนข้อมูลและเจตนาอื่น ๆ อันที่จริงคำสั่งในเพย์โหลดของข้อความ HTTP ควรจะเพียงพอที่จะแสดงการดำเนินการใด ๆ โดยพลการ อย่างไรก็ตามการพึ่งพาร่างกายของข้อความนั้นมีปัญหาของตัวเองเนื่องจากร่างกายมักจะส่งเป็นลำธารและบัฟเฟอร์ร่างกายอย่างครบถ้วนก่อนที่จะระบุการกระทำเป็นไปไม่ได้เสมอหรือฉลาด

PUT /api/InventoryItem/4454c398-2fbb-4215-b986-fb7b54b62ac5 HTTP/1.1
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Content-Type:application/json;domain-model=RenameInventoryItemCommand`

บทความอยู่ที่นี่: http://www.infoq.com/articles/rest-api-on-cqrs

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับประเภทสื่อ 5 ระดับที่นี่: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html


แม้ว่าพวกเขาจะเปิดเผยกิจกรรมโดเมนไปยัง REST API ซึ่งฉันจะพิจารณาการปฏิบัติที่ไม่ดี แต่ฉันชอบวิธีการแก้ปัญหาเพราะมันไม่ได้สร้าง "โปรโตคอล" ใหม่เพียงอย่างเดียวสำหรับ CQRS ไม่ว่าจะเป็นการส่งชื่อคำสั่งในเนื้อหาหรือพิเศษ ส่วนหัวและยังคงเป็นจริงกับหลักการสงบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.