อะไรเป็นสาเหตุของข้อบกพร่องใหม่ที่ปรากฏขึ้นที่อื่นเมื่อมีการแก้ไขข้อบกพร่องที่รู้จัก?


14

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

ฉันเริ่มคิดว่ามันจะเกิดขึ้นได้อย่างไร แต่ไม่สามารถเข้าใจได้

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

ดังนั้นสิ่งที่อาจเป็นสาเหตุของปัญหาดังกล่าวใน codebase ขนาดเล็กที่สดใหม่เขียนโดยนักพัฒนาคนเดียวที่ยังคงจดจ่ออยู่กับงานของเขา ?

สิ่งที่อาจช่วยได้?

  • การทดสอบหน่วย (ไม่มี)?
  • สถาปัตยกรรมที่เหมาะสม (ฉันค่อนข้างแน่ใจว่า codebase ไม่มีสถาปัตยกรรมเลยและเขียนโดยไม่ต้องคิดเบื้องต้น) ต้องการการปรับโครงสร้างทั้งหมดหรือไม่
  • เขียนโปรแกรมจับคู่?
  • อื่น ๆ อีก?

14
รูปแบบการออกแบบที่ดีของ ol ที่ดี "คลื่นแห่งความล้มเหลว" :-)
Brian Knoblauch

1
ฉันเปรียบมันเป็นฟองสบู่ในแผ่นสัมผัส กดลงมันจะปรากฏขึ้นที่อื่น ยิ่งรหัสของฉันดีขึ้นเท่าไหร่ฉันก็ยิ่งเห็นน้อยลงเท่านั้น
johnc

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

... และนั่นเป็นฝันร้ายที่จะแก้ไขข้อผิดพลาด
risingDarkness

คำตอบ:


38

มันไม่ได้เกี่ยวอะไรกับโฟกัสขนาดโครงการเอกสารหรือปัญหากระบวนการอื่น ๆ ปัญหาเช่นนี้มักเกิดจากการมีเพศสัมพันธ์มากเกินไปในการออกแบบซึ่งทำให้ยากที่จะแยกการเปลี่ยนแปลง


15
สิ่งนี้รวมกับการทดสอบการถดถอยที่ไม่ดีหรือไม่มีเลย
Ryathal

3
จริง, @Ryathal ถึงแม้ว่าการทดสอบการถดถอยจะไม่ป้องกันข้อผิดพลาดเหล่านั้นเพียงแจ้งให้คุณทราบเกี่ยวกับพวกเขาในไม่ช้า
Karl Bielefeldt

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

14

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

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

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


7

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


5

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

ตัวอย่างเช่นสมมติว่าฟังก์ชั่น A และ B ใช้การประชุมแบบ zero-based สำหรับปริมาณบางส่วนดังนั้นจึงทำงานร่วมกันได้อย่างถูกต้อง แต่ C ใช้หนึ่งคุณอาจ "แก้ไข" A เพื่อทำงานกับ C แล้วค้นพบปัญหากับ B

ปัญหาที่ลึกกว่านั้นคือการขาดการตรวจสอบความถูกต้องของแต่ละส่วนอย่างอิสระ การทดสอบหน่วยถูกออกแบบมาเพื่อแก้ไขปัญหานี้ พวกเขายังทำหน้าที่เป็นข้อมูลจำเพาะของอินพุตที่เหมาะสม เช่นชุดการทดสอบที่ดีจะทำให้ชัดเจนว่าฟังก์ชั่น A และ B คาดหวังอินพุต 0-based และ C 1

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

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

หวังว่านี่จะช่วยได้


5

การมีเพศสัมพันธ์แน่นขาดการทดสอบสิ่งเหล่านี้อาจเป็นสาเหตุของปัญหาที่พบบ่อยที่สุด โดยทั่วไปปัญหาที่พบบ่อยเป็นเพียงมาตรฐานต่ำและขั้นตอน อีกประการหนึ่งคือการจัดการรหัสที่ไม่ถูกต้องเพื่อให้ได้รับโชคในขณะที่มีพฤติกรรมที่ถูกต้อง พิจารณาmemcpyข้อผิดพลาดจาก Linus Torvalds ที่เปลี่ยนการใช้งานข้อบกพร่อง (ไม่เกิด) ในไคลเอนต์ที่ใช้memcpyในสถานที่ที่ควรใช้memmoveกับแหล่งที่มาและปลายทางที่ทับซ้อนกัน


4

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

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


0

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


0

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

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


0

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

ดังนั้นโดยทั่วไปคุณเกือบตอบเอง:

  • คลัปหลวม
  • ขาดการทดสอบ

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

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


0

สมมติว่านักพัฒนา A เขียนโค้ดบางส่วนพร้อมกับบั๊ก รหัสไม่ได้เป็นอย่างที่ควรจะทำ แต่สิ่งที่แตกต่างกันเล็กน้อย นักพัฒนา B เขียนโค้ดที่ใช้รหัสของ A ทำสิ่งที่ spec'ed ทำและรหัสของ B ไม่ทำงาน B ตรวจสอบค้นหาพฤติกรรมที่ไม่ถูกต้องในรหัสของ A และแก้ไข

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

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

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