ฉันจะปรับปรุงการตรวจสอบและจัดการข้อผิดพลาดได้อย่างไร


13

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

ฉันมีคำถามสองสามข้อเกี่ยวกับเรื่องนี้:

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

ส่วนใหญ่พูดว่า 'ใช้ข้อความยืนยันเพื่อตรวจสอบข้อผิดพลาดเชิงตรรกะและใช้การตรวจสอบอย่างชัดเจนเพื่อตรวจสอบความผิดพลาดอื่น ๆ ' ดูเหมือนว่าจะไม่ได้รับเราไปไกลมาก เราจะพูดว่าเป็นไปได้หรือไม่:

Malloc returning null, check explictly
API user inserting odd input for functions, use asserts

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


3
เป็นคำถามที่ดี แต่ฉันคิดว่ามันอาจจะเหมาะกว่าสำหรับเว็บไซต์น้องสาวแห่งหนึ่ง (โปรแกรมเมอร์)

ขอบคุณฉันไม่แน่ใจ ฉันคิดว่าเนื่องจากมันเป็นเรื่องที่เกี่ยวข้องกับรหัส SO ค่อนข้างเป็นไร
Anon

3
คำตอบง่ายๆคือ "นี่คือเหตุผลว่าทำไมจึงคิดค้นข้อยกเว้นรับภาษาที่ดีกว่า"
DeadMG

1
@DeadMG: setjmp/ longjmpมีให้บริการใน C ดังนั้นคุณไม่จำเป็นต้องใช้ภาษาใหม่
user786653

3
@DeadMG: คนที่ไม่สามารถรับข้อผิดพลาด C การตรวจสอบที่ถูกต้องมีโอกาสที่ก้อนหิมะในนรกได้รับ c ++ ข้อยกเว้นการจัดการที่เหมาะสม ...
Coder

คำตอบ:


4

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


2

ตรวจสอบสิ่งใด ๆ ได้ตลอดเวลา (อาจมีการเปลี่ยนแปลงหลังจากการตรวจสอบครั้งล่าสุดของคุณ) ที่ไม่ได้ 100% ภายใต้คำสั่งของคุณ และยัง: ในระหว่างการพัฒนาแม้ไม่เชื่อใจตัวเอง! ;-)

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

หากจะจริงจังส่วนสุดท้ายของประโยคสุดท้ายนั้นมีความสำคัญเพราะมันชี้ไปที่ประเด็นหลัก:

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


1
+1 สำหรับ 'ตรวจสอบทุกอย่าง' ฉันไม่ได้ซื้ออาร์กิวเมนต์ของรหัสถ่วง: โปรแกรมเมอร์ใด ๆ ควรจะสามารถแยกแยะระหว่างการตรวจสอบข้อผิดพลาดและตรรกะที่แท้จริงอยู่แล้ว
stijn

2

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

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

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

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

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

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

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

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

  5. บางครั้งเราจำเป็นต้องตรวจสอบข้อยกเว้นก่อนที่จะเกิดขึ้น ตัวอย่างที่พบบ่อยที่สุดคือการหารด้วยศูนย์ข้อผิดพลาด ในอุดมคติแล้วเราจะต้องทดสอบก่อนที่จะมีการยกเว้น - และถ้าเป็นเช่นนั้น - ลองใส่ค่าที่ไม่เป็นศูนย์และเดินหน้าต่อไปแทนที่จะฆ่าตัวตาย!

  6. ทำความสะอาด. อย่างน้อยนี่คือสิ่งที่คุณต้องทำ! หากฟังก์ชั่นเกิดขึ้นเมื่อเปิดไฟล์ 3 ไฟล์และไฟล์ที่สี่ไม่สามารถเปิดได้ - ไม่จำเป็นต้องบอกว่า 3 ไฟล์แรกควรถูกปิด การมอบหมายงานนี้ให้กับเลเยอร์ด้านบนเป็นความคิดที่ไม่ดี หากคุณตัดสินใจที่จะไม่ออกโดยไม่ทำความสะอาดหน่วยความจำ และที่สำคัญที่สุด - แม้ว่าคุณจะรอดชีวิตจากข้อยกเว้นได้แจ้งให้ทราบว่าสิ่งต่าง ๆ ไม่ได้เป็นไปตามปกติ

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

การอ้างอิงที่ดีที่สุด: Code Craft ตอนที่ 6 - สามารถดาวน์โหลดได้


1

การตรวจสอบข้อผิดพลาดระหว่างการสร้าง debug เท่านั้นคือ BAD IDEA (tm), การคอมไพล์ภายใต้การวางซ้อนของตัวแปรที่นำมาใช้ซ้ำได้ใน stack, ลบเพจการป้องกัน, ใช้กลวิธี iffy กับการคำนวณ, แทนที่ arthritics หนักด้วย

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

if(somethinghitthefan)
     abort();

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

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


exit / abort == ประสบการณ์การใช้งานที่แย่ที่สุด: แอปพลิเคชันจะหายไปโดยไม่บอกว่าทำไม ..
stijn

@stijn: abortแบ่งเป็นดีบักเกอร์ / สร้างการถ่ายโอนข้อมูล exitไม่ดีใช่ แม้ว่าฉันจะชอบ__asm int 3มากที่สุด
Coder

ที่เป็นจริงและใน C / C ++ ฉันมักจะเขียน asserts โดยใช้ __asm ​​int 3 เช่นกัน แต่ไม่เคยแสดงคำอธิบายสาเหตุอย่างน้อยและอย่างน้อยก็ควรที่จะมีบรรทัดและไฟล์ อย่างน้อยลูกค้าก็สามารถให้ข้อมูลเกี่ยวกับสิ่งที่เกิดขึ้นได้อย่างแน่นอน
stijn

0

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

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