ควรมีวิธีการให้อภัยเมื่อมีข้อโต้แย้งที่ผ่านเข้ามาหรือไม่? [ปิด]


21

สมมติว่าเรามีวิธีการfoo(String bar)ที่ทำงานบนสตริงที่ตรงกับเกณฑ์บางอย่างเท่านั้น [a-z0-9-_./@]+ตัวอย่างเช่นมันจะต้องเป็นตัวพิมพ์เล็กต้องไม่ว่างเปล่าหรือมีเพียงช่องว่างและต้องตรงกับรูปแบบ เอกสารประกอบสำหรับวิธีการระบุเกณฑ์เหล่านี้

วิธีการที่ควรปฏิเสธการเบี่ยงเบนใด ๆ และทั้งหมดจากเกณฑ์นี้หรือวิธีการควรให้อภัยมากขึ้นเกี่ยวกับเกณฑ์บางอย่าง? ตัวอย่างเช่นถ้าวิธีการเริ่มต้นคือ

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
    }
    this.bar = bar;
}

และวิธีการให้อภัยครั้งที่สองคือ

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        bar = bar.toLowerCase().trim().replaceAll(" ", "_");
        if (!bar.matches(BAR_PATTERN_STRING) {
            throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
        }
    }
    this.bar = bar;
}

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

กรณีการใช้งานหลักสำหรับกรณีนี้คือผู้ใช้ที่เข้าถึงวัตถุจากที่เก็บโดยตัวระบุสตริงที่ระบุ แต่ละอ็อบเจ็กต์ในที่เก็บควรมีสตริงที่ไม่ซ้ำกันเพื่อระบุ ที่เก็บเหล่านี้สามารถเก็บวัตถุได้หลายวิธี (sql server, json, xml, binary, ฯลฯ ) และดังนั้นฉันจึงพยายามระบุตัวหารร่วมที่ต่ำที่สุดที่จะตรงกับหลักการตั้งชื่อส่วนใหญ่


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

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

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

1
นี่เหมือนกับถามว่า "มีคนทำผิดฉันฉันควรยกโทษให้พวกเขาเหรอ?" เห็นได้ชัดว่ามีสถานการณ์ที่หนึ่งหรืออื่น ๆ มีความเหมาะสม การเขียนโปรแกรมอาจไม่ซับซ้อนเท่ากับความสัมพันธ์ของมนุษย์ แต่มันซับซ้อนพอที่การสั่งยาแบบนี้จะไม่ทำงาน
Kilian Foth

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

คำตอบ:


47

วิธีการของคุณควรทำในสิ่งที่มันบอกว่ามันทำ

สิ่งนี้จะช่วยป้องกันบั๊กทั้งจากการใช้งานและจากผู้ดูแลที่เปลี่ยนพฤติกรรมในภายหลัง มันช่วยประหยัดเวลาเพราะผู้ดูแลไม่จำเป็นต้องใช้เวลาในการหาว่าเกิดอะไรขึ้น

ที่กล่าวว่าหากตรรกะที่กำหนดไม่เป็นมิตรกับผู้ใช้ก็ควรได้รับการปรับปรุง


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

ฉันต้องการเพิ่มความคิดเห็นของ @ Nelson ว่าวิธีการไม่ควรออกแบบในสุญญากาศ หากผู้เขียนบอกว่าพวกเขาจะใช้มัน แต่จะชดเชยและการชดเชยของพวกเขามีค่าวัตถุประสงค์ทั่วไปพิจารณาทำให้พวกเขาเป็นส่วนหนึ่งของชั้นเรียน (เช่นมีfooและfooForUncleanStringวิธีการที่ฝ่ายหลังทำการแก้ไขก่อนส่งให้อดีต)
Blrfl

20

มีบางจุด:

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

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


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


อีกส่วนที่สำคัญโดยผู้เขียน sendmail: การพิจารณาหลักการ Robustness

15

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

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

  • ฟังก์ชั่นดิบโดยไม่ต้องประมวลผลล่วงหน้า
  • ขั้นตอน preprocessing ด้วยตัวเอง
  • การรวมกันของฟังก์ชั่นดิบและการประมวลผลล่วงหน้า

สุดท้ายเป็นทางเลือก คุณควรจะให้มันก็ต่อเมื่อมีการโทรจำนวนมากใช้

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


2
+1 สำหรับคาดการณ์ได้ และอีก +1 (ฉันต้องการ) สำหรับง่าย ฉันอยากให้คุณช่วยชี้ให้เห็นและแก้ไขข้อผิดพลาดของฉันมากกว่าที่จะซ่อนไว้
John M Gant

4

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

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

ในทางตรงกันข้ามถ้าข้อมูลมาจากพูดไฟล์คุณสมบัติที่ประกอบขึ้นโดยคนทางเทคนิคที่ควรเข้าใจว่า"Fred Mertz" != "FredMertz"ฉันจะมีแนวโน้มที่จะทำให้การจับคู่ที่เข้มงวดและประหยัดค่าใช้จ่ายในการพัฒนามากขึ้น

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


3

คุณพูดถึงบริบทที่มาของคำถามนี้

ระบุว่าฉันจะมีวิธีการทำเพียงสิ่งเดียวมันยืนยันความต้องการในสตริงให้มันดำเนินการตามที่ - ฉันจะไม่พยายามที่จะแปลงมันที่นี่ ทำให้มันง่ายและทำให้ชัดเจน; จัดทำเอกสารและพยายามรักษาเอกสารและรหัสให้ตรงกัน

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

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

เน้นใหญ่ที่นี่เป็นความชัดเจนและเอกสารสิ่งที่รหัสไม่


-1
  1. คุณสามารถตั้งชื่อวิธีการตามการกระทำเช่น doSomething (), takeBackUp ()
  2. เพื่อให้ง่ายต่อการบำรุงรักษาคุณสามารถรักษาสัญญาทั่วไปและการตรวจสอบความถูกต้องในขั้นตอนต่างๆ เรียกพวกเขาตามกรณีการใช้งาน
  3. การตั้งโปรแกรมป้องกัน: ขั้นตอนของคุณจัดการกับการป้อนข้อมูลที่หลากหลายรวมถึง (สิ่งขั้นต่ำที่ต้องใช้เคสต้องได้รับการคุ้มครอง)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.