สไตล์โค้ดที่ดีในการแนะนำการตรวจสอบข้อมูลทุกที่?


10

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

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

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

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

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

(FYI: ฉันยังเป็นผู้เริ่มต้นดังนั้นโปรดแก้ตัวหากคำถามนี้ไร้เดียงสาโครงการของฉันอยู่ใน Python)



3
@gnat มันคล้ายกัน แต่แทนที่จะตอบคำถามของฉันมันมีคำแนะนำ ("ป้องกันได้เท่าที่คุณจะเป็นได้") สำหรับอินสแตนซ์เฉพาะนั้นที่ OP กล่าวถึงซึ่งแตกต่างจากแบบสอบถามทั่วไปของฉัน
user7088941

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

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

1
ในภาษาที่พิมพ์อย่างเคร่งครัดโดยมีการกำหนดชนิดข้อมูลที่เหมาะสมคอมไพเลอร์จะทำสิ่งนี้ให้คุณ
SD

คำตอบ:


4

ทางออกที่ดีกว่าคือการใช้ประโยชน์จากคุณลักษณะและเครื่องมือของ Python

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

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

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

คุณยังรู้สึกกังวลเกี่ยวกับฟังก์ชั่นที่ค้างเมื่อความต้องการเปลี่ยนแปลง นี้สามารถจับโดยการทดสอบแบบอัตโนมัติ

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


+1 สำหรับการชี้ให้ฉันnamedtupleและสิ่งดีๆอื่น ๆ ทั้งหมด ฉันไม่ได้เกี่ยวกับnamedtuple- และในขณะที่ฉันรู้เกี่ยวกับการทดสอบอัตโนมัติฉันไม่เคยใช้มันมากนักและไม่ได้ตระหนักว่ามันจะช่วยฉันได้มากแค่ไหนในกรณีนี้ สิ่งเหล่านี้ดูเหมือนจะดีพอ ๆ กับการวิเคราะห์แบบคงที่ (การทดสอบอัตโนมัติอาจจะดีกว่าเพราะฉันสามารถตรวจจับทุกสิ่งที่ไม่สามารถวิเคราะห์ได้แบบสแตติก!) ถ้าคุณรู้เรื่องอื่นโปรดแจ้งให้เราทราบ ฉันจะเปิดคำถามต่อไปอีกสักครู่ แต่ถ้าไม่มีคำตอบอื่น ๆ ฉันจะยอมรับคุณ
user7088941

9

ตกลงปัญหาจริงอธิบายไว้ในความคิดเห็นด้านล่างคำตอบนี้:

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

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

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


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

1
@ user7088941: ปัญหาที่คุณอธิบายสามารถแก้ไขได้อย่างง่ายดายโดยมีคลาสที่มีสองฟิลด์: "title" และ "bibliographical_reference" คุณจะไม่มั่ว ขึ้นอยู่กับการสั่งซื้อในรายการของสตริงดูเหมือนผิดพลาดมาก อาจเป็นปัญหาพื้นฐานหรือไม่
JacquesB

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

3
"ฉันจะหลีกเลี่ยงการปรับโครงสร้างอย่างต่อเนื่อง" - บล็อกนี้เป็นปัญหาของคุณ รหัสที่ดีนั้นเกิดจากการปรับโครงสร้างใหม่ การปรับโครงสร้างใหม่จำนวนมาก สนับสนุนโดยการทดสอบหน่วย โดยเฉพาะอย่างยิ่งเมื่อส่วนประกอบต้องมีการขยายหรือพัฒนา
Doc Brown

2
ฉันเข้าใจแล้ว. +1 สำหรับข้อมูลเชิงลึกและความคิดเห็นที่ดีทั้งหมด และขอขอบคุณทุกความคิดเห็นที่เป็นประโยชน์อย่างไม่น่าเชื่อ! (ในขณะที่ฉันกำลังใช้คลาส / วัตถุบางอย่างฉันสลับมันกับรายการที่กล่าวถึงซึ่งตามที่ฉันเห็นตอนนี้ไม่ใช่ความคิดที่ดีคำถามยังคงเป็นวิธีที่ดีที่สุดที่จะใช้สิ่งนี้โดยที่ฉันใช้คำแนะนำที่เป็นรูปธรรมจาก JETMs ซึ่งสร้างความแตกต่างอย่างมากในแง่ของความเร็วในการบรรลุสถานะที่ปราศจากบั๊ก)
7088941

3

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

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

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

(หรือในบางกรณีให้ทำการบันทึกข้อมูลซ้ำหากข้อมูลมีรูปแบบที่ไม่ถูกต้อง)

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

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

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

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


1

ไม่เป็นไร. ฉันเคยใช้รหัสใน FoxPro ที่ฉันมี TRY..CATCH บล็อกเกือบทุกฟังก์ชั่นใหญ่ ตอนนี้ฉันโค้ดใน JavaScript / LiveScript และไม่ค่อยตรวจสอบพารามิเตอร์ในฟังก์ชั่น "ภายใน" หรือ "ส่วนตัว"

"วิธีการตรวจสอบ" ขึ้นอยู่กับโครงการ / ภาษาที่เลือกมากกว่านั้นขึ้นอยู่กับทักษะการใช้โค้ดของคุณ


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

1
@ maaartinus ที่ถูกต้อง โดยทั่วไปภาษาโปรแกรมทำให้เราสร้างสิ่งที่ง่ายต่อการใช้เพื่อป้องกันไม่ให้เกิดการระเบิด - แต่ภาษาการเขียนโปรแกรมสร้างขึ้นเพื่อป้องกันความไม่สอดคล้องกันดูเหมือนจะยากกว่าการใช้งาน: ความรู้ของฉันตลอดเวลา refactor ทุกอย่างและใช้คลาสที่ดีที่สุด การไหลของข้อมูลในใบสมัครของคุณ นี่คือสิ่งที่ฉันขออย่างแน่นอน - มีวิธีที่ง่ายกว่าในการแก้ไขปัญหานี้
user7088941

@ user7088941 นั่นเป็นเหตุผลที่ฉันหลีกเลี่ยงภาษาที่พิมพ์อย่างอ่อน Python ยอดเยี่ยมมาก แต่สำหรับทุกอย่างที่ใหญ่กว่านี้ฉันไม่สามารถติดตามสิ่งที่ฉันทำที่อื่นได้ ดังนั้นฉันชอบ Java ซึ่งค่อนข้าง verbose (ไม่มากกับคุณสมบัติลอมบอกและ Java 8) มีการพิมพ์ที่เข้มงวดและเครื่องมือสำหรับการวิเคราะห์แบบคงที่ ฉันขอแนะนำให้คุณลองใช้ภาษาที่มีความเข้มงวดเพราะไม่รู้วิธีแก้ปัญหาเป็นอย่างอื่น
maaartinus

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

1
@ user7088941 ไม่ใช่ OO แต่มีกฎ "ล้มเหลวเร็ว" ทุกวิธีที่ไม่ใช่ส่วนตัวจะต้องตรวจสอบข้อโต้แย้งและโยนเมื่อมีอะไรผิดปกติ ไม่ต้องพยายามไม่ต้องพยายามแก้ไขเพียงแค่เป่าขึ้นไปบนฟ้า แน่นอนว่าในระดับที่สูงกว่านั้นข้อยกเว้นจะได้รับการบันทึกและจัดการ ในขณะที่การทดสอบของคุณพบปัญหาส่วนใหญ่มาก่อนและไม่มีปัญหาซ่อนอยู่รหัสจะรวมเข้ากับโซลูชันที่ปราศจากข้อผิดพลาดเร็วกว่าเมื่อคุณอดทนต่อข้อผิดพลาด
maaartinus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.