การแยกแบบจำลองโดเมน / การติดตานี้มักจะไม่สะดวกหรือไม่


13

ฉันเข้าสู่แนวคิดเกี่ยวกับการออกแบบที่ขับเคลื่อนด้วยโดเมน (DDD) และพบหลักการบางอย่างที่แปลกประหลาดโดยเฉพาะอย่างยิ่งเกี่ยวกับการแยกโดเมนและรูปแบบการคงอยู่ นี่คือความเข้าใจพื้นฐานของฉัน:

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

ภาพประกอบการไหล

ตอนนี้จากข้อสมมติข้างต้น

โฆษณา 2:

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

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

โฆษณา 3:

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

โฆษณา 5:

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

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

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

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

โดยทั่วไป:

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

ฉันขอขอบคุณการชี้แจงในหัวข้อนี้ สมมติฐานของฉันถูกต้องหรือไม่ หากไม่เป็นวิธีที่ถูกต้องในการแก้ปัญหาเหล่านี้คืออะไร?


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

2
สิ่งที่น่าผิดหวังยิ่งกว่านั้นคือคำถามเหล่านั้นมักถูกถามบ่อยๆ แต่สำหรับความรู้ของฉัน - มีตัวอย่างของการใช้งานศูนย์รวมและแหล่งเก็บข้อมูลที่เป็นของหนังสือ
Dusan

คำตอบ:


5

ความเข้าใจพื้นฐานของคุณถูกต้องและสถาปัตยกรรมที่คุณร่างออกมานั้นดีและใช้งานได้ดี

การอ่านระหว่างบรรทัดดูเหมือนว่าคุณมาจากรูปแบบการบันทึกที่เน้นการใช้งานฐานข้อมูลมากขึ้นใช่ไหม ในการที่จะนำไปใช้งานฉันต้องบอกว่าคุณต้องทำ

1:วัตถุโดเมนไม่จำเป็นต้องรวมกราฟวัตถุทั้งหมด ตัวอย่างเช่นฉันอาจมี:

public class Customer
{
    public string AddressId {get;set;}
    public string Name {get;set;}
}

public class Address
{
    public string Id {get;set;}
    public string HouseNumber {get;set;
}

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

2:ข้อ จำกัด ที่ไม่ซ้ำกันโดยทั่วไปคือขอบเขตของพื้นที่เก็บข้อมูลไม่ใช่วัตถุโดเมน อย่าฉีดที่เก็บข้อมูลลงใน Domain Objects นั่นคือการย้ายกลับไปยังระเบียนที่ใช้งานอยู่เพียงเกิดข้อผิดพลาดเมื่อบริการพยายามบันทึก

กฎทางธุรกิจไม่ใช่ "ไม่มีสองอินสแตนซ์ของผู้ใช้ที่มี SocialSecurityNumber เดียวกันสามารถมีอยู่ได้ในเวลาเดียวกัน"

มันเป็นสิ่งที่พวกเขาไม่สามารถอยู่บนพื้นที่เก็บข้อมูลเดียวกัน

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

ออมวันนี้ง่ายและไม่มีข้อ จำกัด เพิ่มเติมในรหัสของคุณ ต้องบอกว่าโดยส่วนตัวแล้วฉันชอบที่จะส่ง SQL ไม่ยากเลยที่คุณจะไม่พบปัญหาใด ๆ กับฟีเจอร์ ORM และคุณสามารถเพิ่มประสิทธิภาพได้ตามที่ต้องการ

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

คำถามทั่วไป

  1. ตรรกะการทำธุรกรรมไปในที่เก็บ แต่คุณไม่ควรมีอะไรมากมายถ้ามี แน่ใจว่าคุณต้องการบางอย่างถ้าคุณมีตารางลูกที่คุณกำลังวางวัตถุลูกของการรวม แต่ที่จะถูกห่อหุ้มทั้งหมดภายในวิธีการเก็บข้อมูล SaveMyObject

  2. อัปเดตเป็นกลุ่ม ใช่คุณควรแก้ไขแต่ละวัตถุจากนั้นเพิ่มเมธอด SaveMyObjects (รายการวัตถุ) ในที่เก็บของคุณเพื่อทำการอัปเดตจำนวนมาก

    คุณต้องการให้วัตถุโดเมนหรือบริการโดเมนมีตรรกะ ไม่ใช่ฐานข้อมูล นั่นหมายความว่าคุณไม่สามารถทำ "อัปเดตชื่อชุดลูกค้า = x โดยที่ y" เพราะสำหรับทุกสิ่งที่คุณรู้ว่าวัตถุลูกค้าหรือ CustomerUpdateService ทำสิ่งแปลก ๆ 20 อย่างเมื่อคุณเปลี่ยนชื่อ


คำตอบที่ดี คุณพูดถูกฉันใช้รูปแบบการบันทึกที่แอคทีฟซึ่งเป็นเหตุผลว่าทำไมรูปแบบที่เก็บดูเหมือนแปลกตั้งแต่แรกเห็น อย่างไรก็ตามวัตถุโดเมน "ยัน" AddressIdไม่ใช่( แทนAddress) ขัดแย้งกับหลักการ OO หรือไม่
Double M

ไม่, คุณยังคงมีออบเจ็กต์ที่อยู่, ไม่ใช่ลูกของลูกค้า
Ewan

การทำแผนที่วัตถุโฆษณาโดยไม่มีการติดตามการเปลี่ยนแปลงsoftwareengineering.stackexchange.com/questions/380274/…
Double M

2

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

จุดที่ 2: (โหลดกราฟวัตถุแบบเต็ม)

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

ดังที่คุณกล่าวไปแล้ววิธีแก้ปัญหาที่ชัดเจนคือมีวิธีการติดตาสำหรับแต่ละกรณีการใช้งาน แต่ถ้าคุณยังคงใช้ ORM สำหรับสิ่งนั้น ORM จะบังคับให้คุณบรรจุทุกอย่างลงใน data-objects ซึ่งนอกเหนือจากการไม่เชิงวัตถุจริงๆแล้วก็ไม่ใช่การออกแบบที่ดีที่สุดสำหรับบางกรณีการใช้งาน

ถ้าฉันต้องการอัปเดตบางรายการเป็นกลุ่ม เหตุใดฉันจึงต้องแสดงวัตถุสำหรับบันทึกทั้งหมด เป็นต้น

ดังนั้นวิธีแก้ปัญหาคือไม่ใช้ ORM สำหรับกรณีใช้งานซึ่งมันไม่เหมาะสม ใช้งานกรณีศึกษา "ตามธรรมชาติ" ซึ่งบางครั้งไม่ต้องการ "นามธรรม" เพิ่มเติมของข้อมูล (วัตถุ - ข้อมูล) หรือสิ่งที่เป็นนามธรรมเหนือ "ตาราง" (ที่เก็บ)

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

จุดที่ 3: (ตรวจสอบข้อ จำกัด )

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

จุดที่ 5: (ORMs)

แน่นอนว่าเป็นข้อกำหนดเบื้องต้นที่จำเป็นในการแยกการดำเนินการจัดเก็บข้อมูลที่เป็นรูปธรรมจากรหัสโดเมน อย่างไรก็ตามมันมีค่าใช้จ่ายสูงเช่นนี้หรือไม่?

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

คำถามทั่วไป 1: (ธุรกรรม)

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

ข้อ จำกัด อื่น ๆ นั้นเป็นของปลอมอย่างสมบูรณ์

คำถามทั่วไป 2: (การปฏิบัติการจำนวนมาก)

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

ข้อกำหนดในการแยก "ตรรกะ" ออกจาก SQL นั้นมาจาก ORM พวกเขาต้องพูดอย่างนั้นเพราะพวกเขาไม่สามารถสนับสนุนได้ มันไม่ได้ "เลวร้าย" โดยเนื้อแท้

สรุป

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

ในทำนองเดียวกัน dataobject-repository abstraction ของ DDD นั้นไม่ได้ดีที่สุดเสมอไป ฉันยังจะไปไกลเพื่อบอกว่าพวกเขาไม่ค่อยออกแบบที่ดีที่สุด

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


จุดที่น่าสนใจมากในนั้นขอบคุณสำหรับการยืนยันสมมติฐานของฉัน คุณพูดว่ายังมีอีกหลายวิธีที่จะคงอยู่ คุณสามารถแนะนำรูปแบบการออกแบบของนักแสดงที่จะใช้กับฐานข้อมูลกราฟ (ไม่มี ORM) ซึ่งจะให้ PI หรือไม่
Double M

1
จริง ๆ แล้วฉันจะถามว่าคุณต้องการแยก (และชนิดใด) ในตอนแรก การแยกต่อเทคโนโลยี (เช่นฐานข้อมูล, UI ฯลฯ ) ทำให้ "ความอึดอัดใจ" ที่คุณพยายามหลีกเลี่ยงโดยอัตโนมัติเพื่อประโยชน์ในการเปลี่ยนเทคโนโลยีฐานข้อมูลได้ง่ายขึ้น อย่างไรก็ตามค่าใช้จ่ายเป็นการเปลี่ยนแปลงทางตรรกะทางธุรกิจที่ยากขึ้นเนื่องจากแพร่กระจายผ่านชั้นต่างๆ หรือคุณสามารถแยกตามฟังก์ชั่นธุรกิจซึ่งจะทำให้การเปลี่ยนแปลงฐานข้อมูลยากขึ้น แต่การเปลี่ยนลอจิกง่ายขึ้น คุณต้องการแบบไหน
Robert Bräutigam

1
คุณสามารถรับประสิทธิภาพที่ดีที่สุดหากคุณเพิ่งสร้างแบบจำลองโดเมน (เช่นฟังก์ชั่นทางธุรกิจ) และไม่ทำให้ฐานข้อมูลเป็นนามธรรม (ไม่ว่าจะเป็นเชิงสัมพันธ์หรือกราฟก็ไม่สำคัญ) เนื่องจากฐานข้อมูลไม่ได้ถูกแยกออกจาก use-case, use-case สามารถใช้เคียวรี / การอัพเดตที่ดีที่สุดที่ต้องการและไม่จำเป็นต้องผ่านโมเดลวัตถุบางอย่างที่น่าอึดอัดใจเพื่อให้ได้สิ่งที่ต้องการ
Robert Bräutigam

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

1
ในฐานะนักพัฒนา Java Enterprise ฉันสามารถบอกคุณได้ว่าเราพยายามแยกการคงอยู่ออกจากตรรกะในช่วงสองทศวรรษที่ผ่านมา มันไม่ทำงาน ก่อนอื่นการแยกไม่สำเร็จอย่างแท้จริง แม้กระทั่งทุกวันนี้มีทุกสิ่งที่เกี่ยวข้องกับฐานข้อมูลในวัตถุ "ธุรกิจ" ที่คาดคะเนส่วนใหญ่เป็น id ฐานข้อมูล (และบันทึกย่อของฐานข้อมูลจำนวนมาก) ประการที่สองอย่างที่คุณพูดบางครั้งตรรกะทางธุรกิจจะถูกดำเนินการบนฐานข้อมูลอย่างใดอย่างหนึ่ง ประการที่สามนั่นคือเหตุผลที่เรามีฐานข้อมูลเฉพาะเพื่อให้สามารถถ่ายตรรกะบางอย่างที่ทำได้ดีที่สุดเมื่อมีข้อมูล
Robert Bräutigam
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.