ฉันต้องประนีประนอม: DRY หรือ Command-Query-Separation


10

ฉันเพิ่ง refactoring วิธีที่ทั้งคำสั่งและวิธีการสืบค้น

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

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


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

มันถูกเรียกโดยทั่วไปว่า CQRS google.com.au/…
Daniel Little

@DanielLittle - ไม่ไม่ใช่ CQS และ CQRS เป็นวิชาที่แตกต่างกันอย่างชัดเจน CQRS เป็นรูปแบบสถาปัตยกรรมที่เกี่ยวข้องมากขึ้นในขณะที่ CQS เป็นรูปแบบการออกแบบมากขึ้นและง่ายต่อการเข้าใจและนำไปใช้ ดูcodebetter.com/gregyoung/2009/08/13/command-query-separation
Erik Funkenbusch

@Erik Funkenbusch คุณถูกต้อง
Daniel Little

คำตอบ:


11

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

QueryResult command()
{
   // do command stuff
   return query();
}

4

ฉันไม่เคยได้ยินเกี่ยวกับ Command-Query-Separation (CQS) มาก่อน แต่ดูเหมือนว่ามันจะเกี่ยวข้องกับ Single Responsibility Principle (SRP) ซึ่งระบุว่าหน้าที่ / คลาสควรมีหน้าที่รับผิดชอบในการทำสิ่งหนึ่งและสิ่งเดียวเท่านั้น .

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

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

ฉันคิดว่าวิธีการห่อหุ้มเป็นทางออกที่ยอมรับอย่างสมบูรณ์และเพื่อแสดงให้เห็นว่าลองยกตัวอย่างของคุณไปอีกขั้นหนึ่ง ถ้าคุณต้องเรียกใช้แบบสอบถาม 2 รายการแทนที่จะเป็น 1 แล้วดำเนินการคำสั่งตามนั้น ดังนั้นโค้ด 2 บรรทัดของคุณจะเป็น 6 หรือ 8 จะเกิดอะไรขึ้นถ้ามีการตรวจสอบ / ตรวจสอบข้อมูลระหว่างหนึ่งกับอีกอันดังนั้นตอนนี้คุณมีรหัส 15 บรรทัด คุณจะคิดสองครั้งเกี่ยวกับการสร้าง wrapper ที่ทำทุกอย่างแทนที่จะโรย 15 บรรทัดในหลายไฟล์หรือไม่?


ฉันคิดว่า wrapper ของ "หลักการเดียว" ควรจะเก็บวิธีอื่น ๆ ที่ต้องการคำสั่งและแบบสอบถามร่วมกันแห้ง
Droogans


ในขณะที่วิธีการแก้ปัญหาของ Karl ในเรื่องนี้ดีกว่าฉันจะหารายละเอียดเพิ่มเติมเกี่ยวกับฟังก์ชั่น wrapper ที่ยาวขึ้นเพื่อเป็นจุดที่ดีมาก
กริชเวลช์

-3

DRY มีความสำคัญมากกว่าเนื่องจากสามารถแก้ไขความต้องการขั้นพื้นฐานได้มากขึ้น - หลีกเลี่ยงความพยายามซ้ำซ้อนและสิ้นเปลืองอย่างมีประสิทธิภาพ นี่คือสิ่งพื้นฐาน - หนึ่งไม่จำเป็นต้องเป็นโปรแกรมเมอร์ที่จะเข้าใจมัน

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

  1. ความจำเป็นในการเรียกใช้โค้ดสำหรับผลลัพธ์นั้นไม่สามารถหลีกเลี่ยงได้เพราะนี่เป็นพื้นฐานสำหรับการเขียนโปรแกรมขนาดใหญ่จากหน่วยเล็ก ๆ

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

  3. ความจำเป็นในการทำให้เกิดผลกระทบและสร้างผลลัพธ์ในรหัสเดียวกันนั้นไม่สามารถหลีกเลี่ยงได้เพราะในทางปฏิบัติเราต้องการทั้งเอฟเฟกต์และการประกอบกันไม่ใช่เพียงอย่างเดียวหรืออย่างอื่น

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

สรุปแล้ว "การแก้ปัญหา" เช่นเดียวกับ CQS เพียงเข้ามาออกแบบโปรแกรมตามหลักการที่ดีบนพื้นฐานของความเป็นจริง ไปหา DRY


บางครั้งคุณต้องหลีกเลี่ยงการแต่งงานกันเพื่อลดความซับซ้อน คุณควรดูที่ CQRS
Daniel Little

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

@Lavinski: ด้วยความเคารพต่อ CQRS โดยเฉพาะวิธีแก้ปัญหาทางเลือกที่ถูกต้องคือ 1. เข้าใจรูปแบบข้อมูล (ไม่มีจำนวนชั้นวัตถุสามารถกำจัดความจำเป็นสำหรับสิ่งนี้), 2. เข้ารหัสคุณสมบัติความถูกต้องมากเท่าที่คุณสามารถทำได้ในสคีมาฐานข้อมูล (น่าเศร้าที่นิยมที่สุด RDBMSes ให้การสนับสนุนค่อนข้าง จำกัด สำหรับหลังไม่ต้องพูดถึง NoSQL คนซึ่งได้รับสิ่งนี้ยิ่งผิดการวิจัยปัจจุบันของฉันคือการให้ทางออกที่ดีกว่าสำหรับเรื่องนี้.)
pyon

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

1
@ EduardoLeón: หากคุณต้องการพิสูจน์การออกแบบของคุณถูกต้องให้ลองเขียนแบบทดสอบสำหรับโปรแกรมของคุณ ฉันรับประกันได้ว่าการทิ้ง CQS จะขัดขวางความพยายามของคุณเท่านั้น
Stefan Billiet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.