ต้นกำเนิดของ“ วิธีการหนึ่งควรส่งคืนค่าหรือมีผลข้างเคียง แต่ไม่ใช่ทั้งสองวิธี”


12

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

ต้นกำเนิดของคำแนะนำนี้คืออะไร? มันเกิดขึ้นจากบุคคลหรือชุมชนใด?

เครดิตเพิ่มเติม: ประโยชน์ที่ได้รับจากการทำตามคำแนะนำนี้คืออะไร?


1
@gnat ใช่มันเกี่ยวกับประวัติศาสตร์เป็นหลัก ฉันกลัวว่าส่วนเครดิตพิเศษนั้นเป็นอัตนัยเกินกว่าที่จะยืนอยู่ได้ด้วยตัวเองและประวัติศาสตร์นั้นมีโอกาสที่ดีกว่าในการหลบหนีจากการถูกปิด ฉันจะเพิ่มแท็ก
Wayne Conrad

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

@gnat ฉันถามเกี่ยวกับผลประโยชน์ที่ผู้อ้างสิทธิ์ (อีกครั้งกลัวการปิด) แต่ฉันแน่ใจว่าไม่รังเกียจเหตุผลกอง - พวกเขาตอบคำถามที่ฉันอยากถาม ถ้าฉันจะลบ "อ้างสิทธิ์" ออกจากคำถามของฉันการทำคำตอบแบบกองบนหัวข้อนั้นจะผลักคำถามไปไกลเกินไปหรือไม่?
Wayne Conrad

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

ข้อดีอย่างหนึ่งคือถ้าคุณจ่ายตามปริมาณของรหัสสิ่งนี้จะเพิ่มพิเศษ "doSomething; GetResultOfSomething; HandleErrorsFromSomething;"

คำตอบ:


13

ตามที่เกร็กหนุ่มความคิดนี้มาจากเบอร์แทรนด์เมเยอร์ : แยกคำสั่ง Query

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

1: Eiffel: ภาษาสำหรับสไลด์วิศวกรรมซอฟต์แวร์ 43-48

ในการออกแบบการขับเคลื่อนด้วยโดเมนสิ่งนี้คล้ายกับการแยก / การแยกคำสั่ง - การสืบค้น - การแยก (CQRS) ตามที่เกร็กยัง

Greg Young นำแนวคิดของ CQS จาก Bertrand มาตั้งชื่อ CQRS ตามที่ Martin Fowler กล่าวถึงในบทความ CQRS นี้

ประโยชน์ที่ได้รับ

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

อ่านบทความในลิงค์ Martin Fowlerสำหรับข้อมูลเพิ่มเติม


1
โดยธรรมชาติแล้วในหลาย ๆ สถานการณ์การสร้างผลลัพธ์ที่เป็นประโยชน์และการปรับเปลี่ยนบางอย่างในเวลาเดียวกันนั้นไม่ได้แพงไปกว่าการแยกจากกัน
Deduplicator

1
@Dupuplicator ตัวอย่างถ้อยคำที่เบื่อหูเป็น InterlockedCompareExchange?

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

4

ฉันไม่รู้ว่ามันมาจากไหน แต่มันเป็นคำแนะนำที่ดีและค่อนข้างตรงไปตรงมาที่จะเข้าใจ

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

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

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


สิ่งนี้ไม่แม้แต่จะพยายามตอบคำถามที่ถามดูวิธีตอบ
gnat

@gnat คำถามของฉันเข้ามาในสองส่วนคำถามหลัก ( "ใคร") และสินเชื่อพิเศษ ( "ทำไม) ไม่ได้อยู่ที่นี้ส่วนหนึ่งเป็นพิเศษเครดิต.
เวย์นคอนราด

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

2
@gnat ฉันเข้าใจคำถามเป็นความพยายามที่จะเข้าใจคำแนะนำนี้ทั้งเหตุผลที่อยู่เบื้องหลังและบริบทที่ได้รับ ฉันไม่เชื่อว่ามันไม่เหมาะสมที่จะตอบคำถามเพียงบางส่วน
Morgen

1

เครดิตเพิ่มเติม: ประโยชน์เดิมของการทำตามคำแนะนำนี้คืออะไร

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

bool FooWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

bool BarWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

void BadShortCircuitEvaluation()
{
    // the programmer's intent is to have side effects of both functions
    if (FooWithSideEffect() && BarWithSideEffect() ) {
        // do something
    }

    // in case FooWithSideEffect() returns true, 
    // then BarWithSideEffect() is not called at all
    // because of short-circuit evaluation
}

นี่คือประโยชน์ที่อ้างสิทธิ์โดยผู้เขียนคำแนะนำ ?
ริ้น

@gnat ฉันมีความสับสนในเรื่องประวัติศาสตร์และการปฏิบัติฉันกลัว
Nick Alexeev

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