ค่าที่คำนวณได้และการอ่านอย่างง่าย - ความเจ็บปวดที่จู้จี้สำหรับการออกแบบโดเมนของฉัน!


9

ปัญหาที่ฉันเผชิญอย่างต่อเนื่องคือวิธีจัดการกับค่าที่คำนวณโดยตรรกะของโดเมนในขณะที่ยังทำงานได้อย่างมีประสิทธิภาพกับที่เก็บข้อมูล

ตัวอย่าง:

ฉันกำลังส่งคืนรายการผลิตภัณฑ์จากที่เก็บของฉันผ่านบริการ รายการนี้ถูก จำกัด โดยข้อมูลเลขหน้าจากคำขอ DTO ที่ส่งโดยลูกค้า นอกจากนี้ DTO ยังระบุพารามิเตอร์การเรียงลำดับ (enum ที่เหมาะกับลูกค้า)

ในสถานการณ์ง่าย ๆ ทุกอย่างใช้งานได้ดี: บริการส่งเพจและเรียงลำดับนิพจน์ไปยัง repo และ repo ออกแบบสอบถามที่มีประสิทธิภาพไปยังฐานข้อมูล

ทุกอย่างพังทลายลงมาเมื่อฉันต้องเรียงลำดับค่าที่สร้างขึ้นในหน่วยความจำจากโมเดลโดเมนของฉัน ตัวอย่างเช่นระดับสินค้ามีวิธี IsExpired () ที่ส่งกลับค่าบูลตามตรรกะทางธุรกิจ ตอนนี้ฉันไม่สามารถจัดเรียงและเพจที่ระดับ repo ได้ทุกอย่างจะต้องทำในหน่วยความจำ (ไม่มีประสิทธิภาพ) และบริการของฉันจะต้องทราบความซับซ้อนของเวลาที่จะออก params เหล่านี้ไปยัง repo และเมื่อทำการเรียงลำดับ / การเพจ ตัวเอง

รูปแบบเดียวที่ดูเหมือนสมเหตุสมผลสำหรับฉันคือการจัดเก็บสถานะของเอนทิตีใน db (ทำให้ IsExpired () เป็นฟิลด์แบบอ่านอย่างเดียวและอัปเดตผ่านตรรกะโดเมนก่อนการบันทึก) ถ้าฉันแยกตรรกะนี้เป็นที่เก็บ "read model / dto" และ "report" ที่แยกต่างหากฉันจะทำให้แบบจำลองโลหิตจางมากกว่าที่ฉันต้องการ

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

ฉันชอบที่จะได้ยินว่าคนอื่นจัดการกับเรื่องนี้อย่างไรเพราะฉันแน่ใจว่ามันเป็นเรื่องธรรมดาในโครงการที่เกี่ยวข้องกับ DDD

คำตอบ:


3

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

การแยกโมเดลโดเมนคำสั่งและเคียวรีนั้นดำเนินการอยู่บ่อยครั้งและมีตัวย่อที่ดีที่คุณสามารถใช้ google ใน CQRS (การแยกความรับผิดชอบคำสั่งการค้นหา)

ใช้รูปแบบโดเมนแบบจำลอง, Udi Dahan

ในขณะที่ฉันประสบความสำเร็จในอดีตในการสร้างแบบจำลองวัตถุถาวรที่จัดการทั้งคำสั่งและแบบสอบถามมันมักจะยากที่จะปรับขนาดมันเป็นส่วนหนึ่งของระบบดึงรูปแบบในทิศทางที่แตกต่างกัน

ปรากฎว่าผู้พัฒนามักจะทำตามข้อกำหนดที่หนักหน่วงมากกว่าที่ธุรกิจต้องการ การตัดสินใจใช้เอนทิตีโมเดลโดเมนเพื่อแสดงข้อมูลแก่ผู้ใช้เป็นเพียงตัวอย่างเท่านั้น

[ ... ]

สำหรับผู้ที่มีอายุมากพอที่จะจดจำแนวทางปฏิบัติที่ดีที่สุดเกี่ยวกับการใช้ COM + ทำให้เราสามารถสร้างส่วนประกอบแยกต่างหากสำหรับการอ่านอย่างเดียวและตรรกะการอ่าน - เขียน ที่นี่เรามีทศวรรษต่อมาด้วยเทคโนโลยีใหม่เช่น Entity Framework แต่หลักการเหล่านั้นยังคงถือ

CQRS กับนักแสดง Akka และนางแบบ Debasish Ghosh

Greg Young ได้นำเสนอเซสชันที่ยอดเยี่ยมเกี่ยวกับ DDD และ CQRS ในปี 2008 เขากล่าวว่า "รูปแบบเดียวไม่เหมาะสมสำหรับการรายงานการค้นหาและพฤติกรรมการทำธุรกรรม" เรามีโมเดลอย่างน้อยสองรุ่น - รุ่นหนึ่งที่ประมวลผลคำสั่งและฟีดจะเปลี่ยนเป็นโมเดลอื่นซึ่งให้บริการแบบสอบถามและรายงานของผู้ใช้ พฤติกรรมการทำธุรกรรมของแอปพลิเคชันได้รับการดำเนินการผ่านรูปแบบโดเมนที่หลากหลายของการรวมและที่เก็บข้อมูลในขณะที่การสืบค้นจะได้รับบริการโดยตรงจากตัวแบบข้อมูลที่ถูกทำให้เป็นมาตรฐาน

CQRS มาร์ตินฟาวเลอร์

การเปลี่ยนแปลงที่ CQRS นำเสนอคือการแยกโมเดลเชิงแนวคิดออกเป็นโมเดลแยกต่างหากสำหรับการอัปเดตและการแสดงผลซึ่งเรียกว่า Command และ Query ตามลำดับโดยใช้คำศัพท์ของ CommandQuerySeparation เหตุผลก็คือสำหรับปัญหาต่าง ๆ โดยเฉพาะอย่างยิ่งในโดเมนที่ซับซ้อนมากขึ้นการมีรูปแบบแนวคิดเดียวกันสำหรับคำสั่งและแบบสอบถามนำไปสู่รูปแบบที่ซับซ้อนมากขึ้นซึ่งไม่ดี

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


2

SPECIFICATION

ฉันรู้ว่าคุณได้รับคำตอบแล้ว แต่คุณถามเกี่ยวกับ DDD และการจับคู่ที่ตรงกันสำหรับสิ่งนี้คือสิ่งที่ Evans เรียกว่า 'ข้อมูลจำเพาะ':
ลิงก์ google books โดยตรง
หากลิงก์นั้นใช้งานไม่ได้ตรวจสอบหนังสือในผลลัพธ์เหล่านี้
หน้า 226 ถ้าคุณมีหนังสือ

บนหน้า 227 มี 3 ใช้สำหรับข้อมูลจำเพาะ: การตรวจสอบ Seletion การสร้างวัตถุพิเศษใหม่ ของคุณคือ 'การเลือก' - IsExpired

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

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

ดังนั้นคำตอบคือให้วางตรรกะทั้งสองชุดไว้ในสเปค รุ่นในหน่วยความจำเห็นได้ชัดว่าเป็นรุ่นเก็บข้อมูลเช่นกัน หากคุณกำลังใช้ตัวอย่างเช่น n-hibernate คุณสามารถใช้ภาษาคิวรีแบบบิวด์อินสำหรับเวอร์ชันที่เก็บข้อมูล

มิฉะนั้นคุณจะต้องสร้างวิธีการเก็บข้อมูลพิเศษสำหรับสเปคนี้ที่ใช้จากวัตถุสเปค การเรียกใช้คอลเลกชันของวัตถุที่ตรงกับสเปคจะผ่านสเปคไม่ใช่ที่เก็บ และอย่างน้อยโค้ดก็ร้องว่า 'ฉันอยู่ใน 2 แห่งอย่าลืมมัน' กับผู้ดูแลในอนาคต มีตัวอย่างที่ยอดเยี่ยมในหน้า 231-232 สำหรับการแก้ปัญหาที่คล้ายกันมาก

สเปคคือการรั่วไหล / การเลื่อนหลุดของ 'ความบริสุทธิ์' ของ DDD มันอาจยังไม่ตอบสนองความต้องการของคุณสำหรับวัตถุประสงค์ที่หลากหลาย ตัวอย่างเช่น ORM อาจสร้าง SQL ที่ไม่ดี อาจมีการเข้ารหัสพิเศษมากเกินไป ดังนั้นคุณอาจต้องเรียกวิธีการเก็บข้อมูลว่ามันเกือบจะเหมือนกับการวาง SQL ไว้ในสเปค แน่นอนว่าสิ่งเลวร้าย แต่อย่าลืมโปรแกรมของคุณต้องทำงานด้วยความเร็วที่สมเหตุสมผล ไม่จำเป็นต้องชนะรางวัลความบริสุทธิ์ DDD ดังนั้นความจริงของการเปลี่ยนดาต้าสโตร์อาจหมายถึงการผ่าตัดแบบเก่าแม้ว่าโปรแกรม ยังเป็นสิ่งที่ไม่ดี แต่ไม่เลวร้ายเท่ากับโปรแกรมช้า (aka SUCKing) หากการใช้งานฐานข้อมูลต่าง ๆ เป็นความจริงคุณจะต้องทำซ้ำกฎธุรกิจสำหรับแต่ละดาต้าสโตร์สำหรับแต่ละสเปค อย่างน้อยคุณมีนิ้วของคุณในเรื่องและคุณสามารถใช้รูปแบบกลยุทธ์เมื่อคุณสลับที่เก็บ แต่ถ้าคุณใช้ฐานข้อมูลที่เฉพาะเจาะจงจำไว้แล้วYAGNI

เกี่ยวกับ CQRS: คำพูดของพรานล่าสัตว์โดย pdr ด้านบนยังคงเป็นความจริงที่นี่: "การมีรูปแบบแนวคิดเดียวกันสำหรับคำสั่งและคำสั่งจะนำไปสู่รูปแบบที่ซับซ้อนมากขึ้นซึ่งไม่ดี" ... และคุณอาจจำเป็นต้องใช้ CQRS แต่มันมีราคาแพงกว่ามากจากมุมมองการพัฒนาและการบำรุงรักษา หากคุณเป็นผู้จำหน่ายบรรจุภัณฑ์ในการแข่งขันกับผู้อื่นอาจจ่ายให้ หากคุณกำลังเขียนแอป LOB ที่กำหนดเองสำหรับลูกค้าหนึ่งรายการถ่ายภาพเพื่อความสมบูรณ์แบบเป็นตัวเลือกที่แย่ คุณจำเป็นต้องตัดสินใจว่าค่าในการมีตัวแบบที่สมบูรณ์หรือส่วนใหญ่จะคุ้มค่ากับความพยายามพิเศษหรือไม่ สเปคเป็นการประนีประนอมที่ดีเพราะช่วยให้คุณสามารถแยกส่วนนี้ออกจากส่วนเล็ก ๆ ของโปรแกรมที่ต้องการได้ด้วยความเร็ว (การพัฒนา) และความเรียบง่ายของรุ่นเดียว โชคดี!


นั่นทำให้รู้สึกที่สมบูรณ์แบบ ฉันคิดว่าฉันต้องกัดกระสุนและอ่านหนังสือของ Evans :-) ฉันเห็นแล้วว่าการมีความเข้าใจตื้น ๆ เกี่ยวกับแนวคิดเหล่านี้สามารถทำให้คุณเป็นอัมพาตได้!
drogon

0

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

DDD ไม่ได้หมายความว่าที่เก็บข้อมูลของคุณต้องโง่ - เพียงหมายความว่าโดเมนของคุณต้องรู้วิธีพูดคุยกับที่เก็บของคุณ

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