บริการควรส่งคืน DTO เสมอหรือพวกเขาสามารถส่งคืนโมเดลโดเมนได้หรือไม่


174

ฉันกำลังออกแบบแอพพลิเคชั่นขนาดใหญ่อีกครั้งเราใช้สถาปัตยกรรมหลายชั้นที่ใช้ DDD

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

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

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

Article Domain vs DTO กับ ViewModel - อย่างไรและเมื่อไหร่ที่จะใช้พวกเขา? (และบทความอื่น ๆ ) มีลักษณะคล้ายกับปัญหาของฉันมาก แต่ไม่ตอบคำถามนี้ บทความฉันควรใช้ DTO ในรูปแบบพื้นที่เก็บข้อมูลกับ EF หรือไม่ ก็คล้ายกัน แต่ไม่ได้จัดการกับ DDD

คำเตือน: ฉันไม่ได้ตั้งใจที่จะใช้รูปแบบการออกแบบใด ๆ เพียงเพราะมันมีอยู่และเป็นแฟนซีในขณะที่ฉันต้องการที่จะใช้รูปแบบการออกแบบที่ดีและการปฏิบัติเพราะมันช่วยในการออกแบบโปรแกรมโดยรวมช่วยแยก ของความกังวลแม้ tohugh โดยใช้รูปแบบเฉพาะไม่จำเป็นต้อง "" อย่างน้อยในขณะนี้

เช่นเคยขอบคุณ


28
สำหรับคนที่โหวตอย่างใกล้ชิด - คุณอยากจะอธิบายไหมว่าทำไมคุณถึงปิดคำถามนี้ตามความเห็น?
Robert Goldwein

20
@Aron "การตรวจสอบรหัสเป็นคำถามและคำตอบสำหรับการแบ่งปันรหัสจากโครงการที่คุณกำลังดำเนินการเพื่อการตรวจสอบโดยเพื่อน" - คำถามของฉันไม่ได้เกี่ยวกับรหัสดังนั้นมันจะปิดหัวข้อที่นั่น; SO: "มุ่งเน้นไปที่คำถามเกี่ยวกับปัญหาจริงที่คุณประสบรวมถึงรายละเอียดเกี่ยวกับสิ่งที่คุณได้ลองแล้วและสิ่งที่คุณพยายามทำ" - ฉันมีปัญหาผู้เชี่ยวชาญเฉพาะด้านซึ่งฉันพยายามแก้ไข คุณช่วยอธิบายให้ชัดเจนยิ่งขึ้นว่าเกิดอะไรขึ้นกับคำถามนี้เนื่องจากคำถามมากมายเกี่ยวกับสถาปัตยกรรมและคำถามเหล่านี้ก็โอเคแล้วดังนั้นฉันจึงสามารถหลีกเลี่ยงความเข้าใจผิดเพิ่มเติมได้หรือไม่
Robert Goldwein

7
ขอบคุณที่ถามคำถามนี้ คุณชอบฉันและทำให้ชีวิตของฉันง่ายขึ้นและมีความสุขมากขอบคุณ
Loa

9
@ RobertGoldwein ไม่ต้องสนใจ SO Close Mafia คำถามของคุณนั้นถูกกฎหมาย
hyankov

3
ขอบคุณมากสำหรับการถามคำถามนี้
salman

คำตอบ:


177

รู้สึกไม่ถูกต้องเมื่อโมเดลโดเมนออกจากชั้นธุรกิจ (ชั้นบริการ)

คุณรู้สึกเหมือนกำลังดึงความกล้าออกมาใช่ไหม? Martin Fowler ระบุว่า Service Layer เป็นตัวกำหนดขอบเขตของแอพพลิเคชั่น กล่าวอีกนัยหนึ่งมันปกป้องโดเมน

บางครั้งบริการต้องส่งคืนวัตถุข้อมูลที่ไม่ได้กำหนดไว้ในโดเมน

คุณสามารถให้ตัวอย่างของวัตถุข้อมูลนี้ได้หรือไม่?

หากเราควรยึดติดกับ DTO อย่างเคร่งครัดควรกำหนดไว้ในเลเยอร์บริการหรือไม่

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

ตกลงหรือไม่ที่จะส่งคืนโมเดลโดเมนไปยังตัวควบคุมหรือเราควรใช้ DTO เพื่อการสื่อสารกับเลเยอร์บริการเสมอหรือไม่

DTO เป็นวัตถุตอบกลับ / คำขอมันสมเหตุสมผลถ้าคุณใช้เพื่อการสื่อสาร หากคุณใช้โมเดลโดเมนในเลเยอร์การนำเสนอของคุณ (MVC-Controllers / View, WebForms, ConsoleApp) ดังนั้นเลเยอร์การนำเสนอจะถูกผนวกเข้ากับโดเมนของคุณอย่างแน่นหนาการเปลี่ยนแปลงใด ๆ ในโดเมนจะทำให้คุณต้องเปลี่ยนคอนโทรลเลอร์

ดูเหมือนว่าจะไม่เหมาะสมที่จะสร้าง DTO ที่เหมือนกับโดเมน)

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

DTO อาจเพิ่มความซับซ้อนให้กับแอปพลิเคชันของคุณ แต่เลเยอร์ของคุณก็เช่นกัน DTO เป็นคุณสมบัติราคาแพงของระบบของคุณซึ่งไม่ได้มาฟรี

ทำไมต้องใช้ DTO

บทความนี้ให้ทั้งข้อดีและข้อเสียของการใช้ DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

สรุปดังนี้

ควรใช้เมื่อใด

  • สำหรับโครงการขนาดใหญ่
  • อายุการใช้งานของโครงการคือ 10 ปีขึ้นไป
  • การประยุกต์ใช้เชิงกลยุทธ์เชิงภารกิจ
  • ทีมใหญ่ (มากกว่า 5)
  • นักพัฒนามีการกระจายทางภูมิศาสตร์
  • โดเมนและงานนำเสนอแตกต่างกัน
  • ลดการแลกเปลี่ยนข้อมูลค่าใช้จ่าย (วัตถุประสงค์ดั้งเดิมของ DTO)

เมื่อไม่ใช้

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

ข้อโต้แย้งต่อต้าน DTO

อาร์กิวเมนต์ด้วย DTO

  • หากไม่มี DTO งานนำเสนอและโดเมนจะถูกผนวกเข้าด้วยกันอย่างแน่นหนา (สิ่งนี้ใช้ได้สำหรับโครงการขนาดเล็ก)
  • ความเสถียรของอินเตอร์เฟส / API
  • อาจจัดเตรียมการปรับให้เหมาะสมสำหรับเลเยอร์การนำเสนอโดยส่งกลับ DTO ที่มีเฉพาะแอตทริบิวต์ที่จำเป็นอย่างยิ่ง เมื่อใช้linq-projectionคุณไม่จำเป็นต้องดึงเอนทิตีทั้งหมด
  • เพื่อลดต้นทุนการพัฒนาให้ใช้เครื่องมือสร้างรหัส

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

1
การพิจารณาประสิทธิภาพที่สำคัญคือรูปแบบของโดเมนหรือ DTO ที่ส่งคืนจากบริการของคุณ ด้วย EF หากคุณตระหนักถึงแบบสอบถามเพื่อส่งคืนคอลเลกชันของโมเดลโดเมน (ด้วย. ToArray () หรือ ToList () เป็นต้น) ให้คุณเลือกคอลัมน์ทั้งหมดเพื่อเติมวัตถุที่รับรู้ หากคุณฉาย DTO ในแบบสอบถามแทน EF ก็ฉลาดพอที่จะเลือกเฉพาะคอลัมน์ที่จำเป็นในการเติมข้อมูล DTO ของคุณซึ่งอาจเป็นข้อมูลที่น้อยกว่ามากในการถ่ายโอนในบางกรณี
snort

10
คุณสามารถแมปวัตถุของคุณด้วยมือ ฉันรู้ว่าสิ่งที่น่าเบื่อ แต่ใช้เวลา 2-3 นาทีต่อรูปแบบและมีความเป็นไปได้ที่จะนำปัญหามากเมื่อคุณใช้เป็นจำนวนมากของการสะท้อน (AutoMapper ฯลฯ )
Razvan Dumitru

1
ขอบคุณสำหรับการตอบอย่างง่าย ๆ และด้วยเนื้อหาดังกล่าว คุณชอบฉันมากและทำให้ชีวิตของฉันง่ายขึ้นและมีความสุขมากขอบคุณ
Loa

1
เราได้ยกเลิกโครงการ 10 ล้านเพราะมันช้า ... ทำไมมันช้า ถ่ายโอนวัตถุ DTO ทั่วทุกสถานที่โดยใช้การเลือกใหม่ ระวัง. Automapper ยังใช้การสะท้อนกลับ
RayLoveless

11

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

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

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

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


1
ขอโทษด้วยกับเรื่องนั้น! คุณสามารถดูได้ที่นี่ehsanghanbari.com/blog/Post/7/…
Ehsan

10

จากประสบการณ์ของฉันคุณควรทำสิ่งที่เป็นประโยชน์ "การออกแบบที่ดีที่สุดคือการออกแบบที่ง่ายที่สุด" - Einstein ด้วยความที่เป็น ...

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

ไม่เป็นไร! หากคุณมี Domain Domain, DTO's และ View Models รวมถึงตารางฐานข้อมูลคุณมีฟิลด์ทั้งหมดในแอปพลิเคชันซ้ำซ้อนใน 4 ตำแหน่ง ฉันทำงานในโครงการขนาดใหญ่ที่ Domain Entities และ View Models ทำงานได้ดี ข้อยกเว้นเพียงอย่างเดียวคือหากมีการเผยแพร่แอปพลิเคชันและชั้นบริการอยู่บนเซิร์ฟเวอร์อื่นซึ่งต้องใช้ DTO เพื่อส่งข้ามสายเพื่อเหตุผลในการทำให้เป็นอนุกรม

ถ้าเป็นเช่นนั้นจะเป็นการดีที่จะปรับรูปแบบโดเมนตามบริการที่ต้องการ (ตรงไปตรงมาฉันไม่คิดอย่างนั้นเพราะบริการควรกินสิ่งที่มีโดเมน)

โดยทั่วไปฉันจะเห็นด้วยและปฏิเสธเพราะรูปแบบโดเมนโดยทั่วไปเป็นภาพสะท้อนของตรรกะทางธุรกิจและมักจะไม่ได้รับรูปร่างโดยผู้บริโภคของตรรกะนั้น

หากเราควรยึดติดกับ DTO อย่างเคร่งครัดควรกำหนดไว้ในเลเยอร์บริการหรือไม่ (ฉันคิดอย่างนั้น)

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

โชคดี!


8

ฉันมางานปาร์ตี้สายนี้ แต่นี่เป็นคำถามทั่วไปและสำคัญที่ฉันรู้สึกว่าถูกบังคับให้ตอบ

โดย "services" คุณหมายถึง "Application Layer" ซึ่งอธิบายโดย Evan ในสมุดสีฟ้าหรือไม่ ฉันจะถือว่าคุณทำในกรณีนี้คำตอบคือพวกเขาไม่ควรส่งคืน DTO ฉันขอแนะนำให้อ่านบทที่ 4 ในสมุดสีฟ้าหัวข้อ "การแยกโดเมน"

ในบทนั้นอีแวนส์พูดเกี่ยวกับเลเยอร์ต่อไปนี้:

แบ่งพาร์ติชันโปรแกรมที่ซับซ้อนออกเป็นเลเยอร์ พัฒนาการออกแบบภายในแต่ละเลเยอร์ที่เหนียวแน่นและขึ้นอยู่กับเลเยอร์ด้านล่างเท่านั้น

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

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

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

ตัวอย่างเช่นจะเกิดอะไรขึ้นหากระบบของคุณเชื่อมต่อกับระบบหรือประเภทไคลเอนต์อื่น ๆ แต่ละระบบต้องการ DTO ของตัวเอง คุณจะรู้ได้อย่างไรว่า DTO ใดที่วิธีการบริการแอปพลิเคชันของคุณควรกลับมา? คุณจะแก้ไขปัญหานี้อย่างไรหากภาษาที่คุณเลือกไม่อนุญาตให้ใช้วิธีการมากเกินไป (วิธีบริการในกรณีนี้) ตามประเภทผลตอบแทน และแม้ว่าคุณจะคิดหาวิธีทำไมละเมิด Application Layer ของคุณเพื่อสนับสนุนข้อกังวลของเลเยอร์การนำเสนอ

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

ที่ที่ฉันทำงานอยู่บริการต่าง ๆ ใน Application Layer return object domain เราไม่ได้พิจารณาเรื่องนี้เป็นปัญหาตั้งแต่ Interface (UI คือ / Presentation) ชั้นขึ้นอยู่กับชั้น Domain ซึ่งเป็นด้านล่างมัน นอกจากนี้การพึ่งพานี้จะถูกย่อให้เล็กสุดเป็นประเภทการอ้างอิง "อ้างอิงเท่านั้น" เนื่องจาก:

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

b) วิธีการเกี่ยวกับบริการใน Application Layer ยอมรับว่าเป็นอินพุต (ข้อมูลดิบ) ที่ป้อนเข้าเท่านั้น (ค่าข้อมูล) หรือพารามิเตอร์วัตถุ (เพื่อลดจำนวนพารามิเตอร์ที่จำเป็น) ที่กำหนดไว้ในชั้นนั้น บริการแอปพลิเคชันไม่เคยยอมรับวัตถุโดเมนเป็นอินพุต

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


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

ฉันคิดว่าฉันจะรับตำแหน่งของคุณ บริการแอปพลิเคชันส่งคืนโมเดลโดเมน เลเยอร์อะแดปเตอร์พอร์ต (REST การนำเสนอและอื่น ๆ ) จากนั้นแปลเป็นรูปแบบของตัวเอง (ดูรุ่นหรือการนำเสนอ) การเพิ่มโมเดล DTO ระหว่างแอ็พพลิเคชันและพอร์ตอะแด็ปเตอร์ดูเหมือนว่าเกินความจำเป็น การส่งคืนโมเดลโดเมนยังคงเป็นไปตามกรมทรัพย์สินทางปัญญาและตรรกะของโดเมนจะยังคงอยู่ในบริบทที่มีขอบเขต (ไม่จำเป็นต้องอยู่ภายในขอบเขตของแอปพลิเคชัน
Michael Andrews

@MichaelAndrews ดีใจที่ได้ยินว่าคำตอบของฉันช่วยได้ Re: คำถามของคุณเกี่ยวกับวัตถุที่ส่งคืนเป็นแบบอ่านอย่างเดียววัตถุเหล่านั้นไม่ได้เป็นแบบอ่านอย่างเดียว (เช่นไม่เปลี่ยนรูป) สิ่งที่ฉันหมายถึงคือมันไม่ได้เกิดขึ้นในทางปฏิบัติ (อย่างน้อยในประสบการณ์ของฉัน) หากต้องการอัปเดตวัตถุโดเมน Interface Layer จะต้องมีก) อ้างอิงที่เก็บข้อมูลของวัตถุโดเมนหรือ b) โทรกลับเข้าไปใน Application Layer เพื่ออัปเดตวัตถุที่เพิ่งได้รับ อย่างใดอย่างหนึ่งเหล่านี้เป็นการละเมิดที่ชัดเจนของการปฏิบัติ DDD ที่ดีที่ฉันพบว่าพวกเขาจะบังคับตนเอง อย่าลังเลที่จะกำจัดคำตอบหากคุณสนใจ
BitMask777

คำตอบนี้ง่ายสำหรับฉันด้วยเหตุผลหลายประการ อันดับแรกเราสามารถนำ Application Layer เดียวกันมาใช้ซ้ำกับ UIs หลายตัว (APIs, Controllers) และแต่ละอันสามารถแปลงโมเดลได้ตามที่เห็นสมควร ประการที่สองถ้าเราต้องเปลี่ยน model-to-DTO ในแอพ เลเยอร์นั่นหมายถึง DTO ถูกกำหนดในแอพ เลเยอร์ซึ่งหมายความว่า DTO เป็นส่วนหนึ่งของบริบทที่ถูกผูกมัดของเรา (ไม่จำเป็นต้องเป็นโดเมน!) - นี่แค่รู้สึกผิด
Robotron

1
ฉันเพิ่งจะถามคำถามติดตามคุณแล้วเห็นว่าคุณตอบแล้ว: "บริการแอปพลิเคชันไม่เคยยอมรับวัตถุโดเมนเป็นอินพุต" ฉันจะ +1 อีกถ้าทำได้
Robotron

5

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

แต่ละวิธีการบริการกำหนดสัญญาของตนเองและดังนั้นจึงง่ายต่อการรักษาเมื่อเวลาผ่านไป ฉันหวังว่า.


1
หลังจากหลายปีเราก็มาถึงข้อสรุปเดียวกันด้วยเหตุผลที่คุณพูดถึงที่นี่
Robert Goldwein

@ RobertGoldwein เยี่ยมมาก! ตอนนี้ฉันรู้สึกมั่นใจมากขึ้น :-)
Niklas Wulff

@NiklasWulff: ดังนั้น Dtos ที่เป็นปัญหาตอนนี้เป็นส่วนหนึ่งของสัญญา Application Layer เช่นเป็นส่วนหนึ่งของ core / domain ประเภทการคืน Web API เกี่ยวกับอะไร? คุณเปิดเผย Dtos ที่กล่าวถึงในคำตอบของคุณหรือคุณได้กำหนด View Models ที่กำหนดไว้ในเลเยอร์ Web API หรือไม่ หรือจะพูดให้แตกต่างคุณทำแผนที่ Dtos to View Models หรือไม่?
Robotron

1
@Robotron เราไม่มี Web API เราใช้ MVC ใช่แล้วเราแมป dto: s กับโมเดลมุมมองอื่น บ่อยครั้งที่โมเดลการดูมีสิ่งอื่น ๆ จำนวนมากที่จะแสดงหน้าเว็บดังนั้นข้อมูลจาก dto: s เป็นส่วนหนึ่งของโมเดลการดูเท่านั้น
Niklas Wulff

4

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

เนื่องจากรูปแบบโดเมนมีคำศัพท์ ( ภาษาที่ใช้กันแพร่หลาย ) สำหรับแอปพลิเคชันของคุณทั้งหมดจะเป็นการดีกว่าที่จะใช้รูปแบบโดเมนอย่างกว้างขวาง

เหตุผลเดียวในการใช้ ViewModels / DTOs คือการนำรูปแบบ MVC ไปใช้ในแอปพลิเคชันของคุณเพื่อแยกView(เลเยอร์การนำเสนอใด ๆ ) และModel(โมเดลโดเมน) ในกรณีนี้การนำเสนอและรูปแบบโดเมนของคุณจะถูกรวมเข้าด้วยกันอย่างหลวม ๆ

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

ฉันสมมติว่าคุณพูดถึงบริการ Application / Business / Domain Logic

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

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

คำถามคือ - ถ้าเราใช้โมเดลการดูอย่างเคร่งครัดเป็นไรหรือไม่ที่จะส่งคืนโมเดลโดเมนไปยังตัวควบคุมหรือเราควรใช้ DTO เพื่อการสื่อสารกับชั้นบริการเสมอหรือไม่

ฉันจะบอกว่ามันก็พอที่จะคืนหน่วยงานโดเมนในกรณี 99,9%

เพื่อที่จะลดความซับซ้อนของการสร้างและการทำแผนที่ DTOs หน่วยงานโดเมนของคุณลงในพวกเขาคุณสามารถใช้AutoMapper


4

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

สิ่งที่สำคัญมากของโมเดลโดเมนคือมันง่ายที่จะเปลี่ยน สิ่งนี้ทำให้เรามีความยืดหยุ่นกับความต้องการที่เปลี่ยนแปลงของโดเมน


2

ฉันขอแนะนำให้วิเคราะห์คำถามสองข้อนี้:

  1. เลเยอร์ส่วนบนของคุณ (เช่นมุมมอง & มุมมองโมเดล / ตัวควบคุม) ใช้ข้อมูลในลักษณะที่แตกต่างจากที่เลเยอร์โดเมนแสดงหรือไม่ หากมีการทำแผนที่จำนวนมากหรือแม้แต่ตรรกะที่เกี่ยวข้องฉันขอแนะนำให้ทบทวนการออกแบบของคุณ: มันอาจจะใกล้เคียงกับวิธีการใช้ข้อมูลจริง

  2. เป็นไปได้มากน้อยเพียงใดที่คุณจะเปลี่ยนเลเยอร์บน (เช่นการสลับ ASP.NET สำหรับ WPF) หากสิ่งนี้แตกต่างอย่างมากและสถาปัตยกรรมของคุณไม่ซับซ้อนคุณอาจจะดีกว่าที่จะเปิดเผยเอนทิตีของโดเมนให้มากที่สุดเท่าที่จะทำได้

ฉันเกรงว่ามันเป็นหัวข้อที่ค่อนข้างกว้างและได้รับการลงลึกถึงความซับซ้อนของระบบและความต้องการของคุณ


ในกรณีของเราชั้นบนจะไม่เปลี่ยนแน่นอน ในบางกรณีบริการส่งคืนออบเจกต์ POCO ที่ไม่เหมือนใคร (สร้างจากโดเมนอื่น ๆ เช่นผู้ใช้และไฟล์ที่เขาเป็นเจ้าของ) ในบางกรณีบริการจะส่งคืนโมเดลโดเมนเพียงอย่างเดียว - เช่นผลลัพธ์ของ "FindUserByEmail () ควรส่งคืนโมเดลโดเมนผู้ใช้ - และ นี่คือความกังวลของฉันบางครั้งบริการของเราส่งคืนโมเดลโดเมนบางครั้ง DTO ใหม่ - และฉันไม่ชอบความไม่สอดคล้องนี้ฉันอ่านบทความมากที่สุดเท่าที่จะทำได้และคนส่วนใหญ่ดูเหมือนจะยอมรับว่าแม้ว่าแมป Domain Model <-> DTO คือ 1: 1 โมเดลโดเมนไม่ควรปล่อยให้เลเยอร์บริการ - ดังนั้นฉันจึงขาด
Robert Goldwein

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

1

จากประสบการณ์ของฉันเว้นแต่ว่าคุณกำลังใช้รูปแบบ OO UI (เช่นวัตถุเปล่า) การเปิดเผยวัตถุโดเมนไปยัง UI นั้นเป็นแนวคิดที่ไม่ดี เนื่องจากแอปพลิเคชันเติบโตขึ้นความต้องการจาก UI จะเปลี่ยนและบังคับให้ออบเจ็กต์ของคุณรองรับการเปลี่ยนแปลงเหล่านั้น คุณจบการให้บริการ 2 ปริญญาโท: UI และ DOMAIN ซึ่งเป็นประสบการณ์ที่เจ็บปวดมาก เชื่อฉันคุณไม่ต้องการที่จะอยู่ที่นั่น โมเดล UI มีฟังก์ชั่นในการสื่อสารกับผู้ใช้รุ่น DOMAIN เพื่อเก็บกฎเกณฑ์ทางธุรกิจและตัวแบบคงอยู่ที่เกี่ยวข้องกับการจัดเก็บข้อมูลได้อย่างมีประสิทธิภาพ พวกเขาทั้งหมดตอบสนองความต้องการที่แตกต่างกันของแอปพลิเคชัน ฉันกำลังเขียนโพสต์บล็อกเกี่ยวกับเรื่องนี้ฉันจะเพิ่มเมื่อดำเนินการเสร็จแล้ว

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