แนวทางปฏิบัติที่ดีที่สุดในการเขียนโปรแกรมป้องกัน (โปรดปิด)


148

หากคุณต้องเลือกเทคนิคที่คุณโปรดปราน (ฉลาด) เพื่อป้องกันการเข้ารหัสพวกเขาจะเป็นอย่างไร? แม้ว่าภาษาปัจจุบันของฉันคือ Java และ Objective-C (มีพื้นหลังเป็น C ++) แต่สามารถตอบได้ทุกภาษา เน้นที่นี่จะเป็นเทคนิคการป้องกันที่ฉลาดกว่าที่ 70% + ของเราที่นี่รู้อยู่แล้ว ดังนั้นถึงเวลาขุดลึกลงไปในกระเป๋าของคุณ

กล่าวอีกนัยหนึ่งลองนึกถึงตัวอย่างที่ไม่น่าสนใจ :

  • if(5 == x) แทน if(x == 5) : เพื่อหลีกเลี่ยงการมอบหมายที่ไม่ได้ตั้งใจ

นี่คือตัวอย่างของวิธีปฏิบัติในการตั้งโปรแกรมการป้องกันที่น่าสนใจ (ตัวอย่างเฉพาะภาษามีอยู่ใน Java):

- ล็อคตัวแปรของคุณจนกว่าคุณจะรู้ว่าคุณต้องเปลี่ยนพวกเขา

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

public void foo(final int arg) { /* Stuff Here */ }

- เมื่อมีสิ่งเลวร้ายเกิดขึ้นให้ทิ้งหลักฐานไว้ข้างหลัง

มีหลายสิ่งที่คุณสามารถทำได้เมื่อคุณมีข้อยกเว้น: การเข้าสู่ระบบอย่างเห็นได้ชัดและทำการล้างข้อมูลบางอย่างอาจเป็นเพียงเล็กน้อย แต่คุณสามารถทิ้งหลักฐานไว้ได้ (เช่นการตั้งค่าตัวแปรให้กับค่าของ Sentinel เช่น "UNABLE TO LOAD FILE" หรือ 99999 จะมีประโยชน์ในตัวดีบักในกรณีที่คุณเกิดข้อcatchผิดพลาดผ่านบล็อก -block)

- เมื่อพูดถึงเรื่องความมั่นคง: มารอยู่ในรายละเอียด

สอดคล้องกับไลบรารีอื่น ๆ ที่คุณใช้อยู่ ตัวอย่างเช่นใน Java หากคุณกำลังสร้างวิธีที่แยกช่วงของค่าจะทำให้ขอบเขตที่รวมต่ำกว่าและขอบเขตพิเศษด้านบนพิเศษสิ่งนี้จะทำให้สอดคล้องกับวิธีการต่าง ๆString.substring(start, end)ซึ่งทำงานในลักษณะเดียวกัน คุณจะพบกับวิธีการเหล่านี้ทั้งหมดใน Sun JDK ที่จะทำงานในลักษณะนี้เนื่องจากมันทำให้การดำเนินการต่างๆรวมถึงการวนซ้ำขององค์ประกอบที่สอดคล้องกับอาร์เรย์โดยที่ดัชนีมาจากศูนย์ ( รวม ) ถึงความยาวของอาร์เรย์ ( พิเศษ )

ดังนั้นอะไรคือแนวปฎิบัติการป้องกันที่คุณโปรดปราน

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


ฉันต้องการที่จะเป็นตัวแทนของคนโง่เขลา 30% ของเราที่นี่ซึ่งอาจไม่ทราบเทคนิคง่ายๆ ใครมีลิงค์ไปสู่เทคนิค "ชัดเจน" ทุกคนควรรู้ว่าเป็นรากฐานหรือไม่?
elliot42

ที่เกี่ยวข้อง: stackoverflow.com/questions/163026/…
Bill the Lizard

ทำไมคุณถึงเลือกคำตอบอย่างเป็นทางการ นั่นฟังดูไม่ชัดเจนทั้งหมด
bzlm

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

คำตอบ:


103

ใน c ++ ฉันเคยชอบนิยามใหม่เพื่อให้หน่วยความจำพิเศษบางอย่างเพื่อตรวจจับข้อผิดพลาดโพสต์รั้ว

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

ในฐานะ WikiKnowledge Wrote :

หลีกเลี่ยงการเขียนโปรแกรมการป้องกันล้มเหลวอย่างรวดเร็วแทน

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


8
การตั้งโปรแกรมการป้องกันกำลังพยายามที่จะจัดการกับเงื่อนไขที่ผิดกฎหมายที่แนะนำโดยส่วนอื่น ๆ ของโปรแกรม การจัดการอินพุตของผู้ใช้ที่ไม่เหมาะสมนั้นเป็นสิ่งที่แตกต่างอย่างสิ้นเชิง
Joe Soul-bringer

5
ข้อผิดพลาด ... โปรดทราบว่าคำจำกัดความของการเขียนโปรแกรมป้องกันนี้ไม่ได้ใกล้เคียงกับคำจำกัดความที่ใช้โดยนัยในคำถาม
30719 Sol

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

6
ฉันจะยืนยันว่ากระบวนการ "ล้มเหลวเร็ว" เป็นรูปแบบของการเขียนโปรแกรมป้องกัน
Ryan Delucchi

6
@ryan ถูกต้องล้มเหลวเร็วเป็นแนวคิดการป้องกันที่ดี หากไม่สามารถอยู่ในสถานะที่เป็นไปได้อย่าพยายามที่จะเดินกะเผลกไปมาล้มเหลวอย่างรวดเร็วและดัง! สำคัญอย่างยิ่งถ้าคุณถูกขับเคลื่อนด้วย meta-data การเขียนโปรแกรมการป้องกันไม่ได้เป็นเพียงการตรวจสอบพารามิเตอร์ของคุณ ...
บิล K

75

SQL

เมื่อฉันต้องลบข้อมูลฉันเขียน

select *    
--delete    
From mytable    
Where ...

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

แก้ไข: หากฉันลบข้อมูลจำนวนมากฉันจะใช้จำนวน (*) แทนที่จะเป็น *


ฉันเขียนสิ่งนี้ลงบน iPhone ที่ฉันเลือกข้อความไม่ได้ หากใครบางคนสามารถทำเครื่องหมายรหัสของฉันเป็นรหัสมันจะได้รับการชื่นชมจริงๆ ขอบคุณ
John MacIntyre

6
ฉันเพียงแค่ห่อไว้ในการทำธุรกรรมเพื่อให้ฉันสามารถย้อนกลับไปถ้าผมพลาด ...
rmeador

36
การทำธุรกรรมเริ่มต้น ธุรกรรมย้อนกลับ
ดาลิ

3
+1 ใช่ฉันคิดว่านี่อาจถูกแทนที่ด้วยธุรกรรม แต่ฉันชอบความเรียบง่ายของการทำเช่นนี้
Ryan Delucchi

3
การใช้ธุรกรรมจะดีกว่า หมายความว่าคุณสามารถวิ่งได้หลายสิบครั้งและดูเอฟเฟกต์จริงจนกว่าคุณจะแน่ใจว่าคุณได้รับสิทธิ์และสามารถกระทำได้แล้ว
Ryan Lundy

48

จัดสรรหน่วยความจำที่เหมาะสมเมื่อแอปพลิเคชันเริ่มต้น - ฉันคิดว่า Steve McConnell เรียกสิ่งนี้ว่าเป็นร่มชูชีพหน่วยความจำใน Code Complete

สามารถใช้ในกรณีที่มีข้อผิดพลาดร้ายแรงและคุณจำเป็นต้องยกเลิก

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

  • บันทึกข้อมูลถาวรทั้งหมด
  • ปิดไฟล์ที่เหมาะสมทั้งหมด
  • เขียนข้อความผิดพลาดไปยังไฟล์บันทึก
  • นำเสนอข้อผิดพลาดที่มีความหมายกับผู้ใช้

ฉันเคยเห็นสิ่งนี้เรียกว่ากองทุนวันฝนตก
แท่นที่

42

ในทุกคำสั่งสวิตช์ที่ไม่มีตัวพิมพ์เริ่มต้นฉันเพิ่มเคสที่ยกเลิกโปรแกรมด้วยข้อความแสดงข้อผิดพลาด

#define INVALID_SWITCH_VALUE 0

switch (x) {
case 1:
  // ...
  break;
case 2:
  // ...
  break;
case 3:
  // ...
  break;
default:
  assert(INVALID_SWITCH_VALUE);
}

2
หรือการขว้างด้วยภาษาที่ทันสมัย
Tom Hawtin - tackline

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

2
Assert มีข้อดีอีกอย่างที่ทำให้มีประโยชน์สำหรับรหัสการผลิต: เมื่อมีบางอย่างผิดพลาดมันจะบอกคุณว่าอะไรที่ล้มเหลวและบรรทัดของโปรแกรมที่เกิดข้อผิดพลาด รายงานข้อผิดพลาดเช่นนั้นวิเศษมาก!
Mason Wheeler

2
@Diomidis: อีกมุมหนึ่งคือ: Assert มีข้อเสียที่เอฟเฟกต์สามารถปิดการใช้งานได้ทั่วโลกในเวลารวบรวม
ไม่แยแส

1
โยนดีกว่าแน่นอน และจากนั้นคุณต้องแน่ใจว่าขอบเขตการทดสอบของคุณนั้นเพียงพอ
โดมินิคโครนิน

41

เมื่อคุณจัดการสถานะต่าง ๆ ของ enum (C #):

enum AccountType
{
    Savings,
    Checking,
    MoneyMarket
}

จากนั้นภายในกิจวัตรประจำวัน ...

switch (accountType)
{
    case AccountType.Checking:
        // do something

    case AccountType.Savings:
        // do something else

    case AccountType.MoneyMarket:
        // do some other thing

    default:
-->     Debug.Fail("Invalid account type.");
}

ในบางจุดฉันจะเพิ่มประเภทบัญชีอื่นให้กับ enum นี้ และเมื่อฉันทำฉันจะลืมแก้ไขคำสั่งเปลี่ยนนี้ ดังนั้นการDebug.Failล่มจึงน่ากลัว (ในโหมด Debug) เพื่อดึงดูดความสนใจของฉันกับความจริงนี้ เมื่อฉันเพิ่มcase AccountType.MyNewAccountType:ความล้มเหลวที่น่ากลัวจะหยุด ... จนกว่าฉันจะเพิ่มประเภทบัญชีอื่นและลืมอัปเดตเคสที่นี่

(ใช่แตกต่างกันน่าจะดีกว่าที่นี่ แต่นี่เป็นเพียงตัวอย่างจากส่วนบนของหัวของฉัน)


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

ใน c ฉันใช้เพื่อเพิ่ม invalidAccountType ในตอนท้าย บางครั้งมันมีประโยชน์
Ray Tayek

1
@Adam - คอมไพเลอร์จะออกคำเตือนถ้าคุณ recompile ทุกอย่าง หากคุณเพิ่มคลาสใหม่และคอมไพล์เพียงบางส่วนคุณอาจไม่สังเกตเห็นบางสิ่งเช่นด้านบนและกรณีเริ่มต้นจะบันทึก มันจะไม่ล้มเหลวอย่างเงียบ ๆ
Eddie

4
ตัวแบ่งจะบอกเป็นนัยในความคิดเห็น Slashene : P
Ryan Lundy

2
หลังจากการดีบักควรเป็น 'โยนใหม่ NotSupportedException ()' สำหรับรหัสการผลิต
user7116

35

เมื่อพิมพ์ข้อความผิดพลาดกับสตริง (โดยเฉพาะอย่างใดอย่างหนึ่งซึ่งขึ้นอยู่กับการป้อนข้อมูลของผู้ใช้) ''ผมมักจะใช้ราคาเดียว ตัวอย่างเช่น:

FILE *fp = fopen(filename, "r");
if(fp == NULL) {
    fprintf(stderr, "ERROR: Could not open file %s\n", filename);
    return false;
}

การขาดเครื่องหมายอัญประกาศรอบ ๆ%sนี้ไม่ดีนักเนื่องจากการพูดชื่อไฟล์เป็นสตริงว่างหรือเพียงแค่ช่องว่างหรืออะไรบางอย่าง แน่นอนข้อความที่พิมพ์ออกมาจะเป็น:

ERROR: Could not open file

ดังนั้นดีกว่าที่จะทำ:

fprintf(stderr, "ERROR: Could not open file '%s'\n", filename);

อย่างน้อยผู้ใช้จะเห็นสิ่งนี้:

ERROR: Could not open file ''

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


4
ดีอย่างหนึ่งที่ผมเคยเห็นปัญหานี้เช่นกัน
อเล็กซ์ Baranosky

28

ความปลอดภัยของ SQL

ก่อนที่จะเขียน SQL ใด ๆ ที่จะแก้ไขข้อมูลฉันจะสรุปสิ่งทั้งหมดในธุรกรรมย้อนกลับ:

BEGIN TRANSACTION
-- LOTS OF SCARY SQL HERE LIKE
-- DELETE FROM ORDER INNER JOIN SUBSCRIBER ON ORDER.SUBSCRIBER_ID = SUBSCRIBER.ID
ROLLBACK TRANSACTION

สิ่งนี้จะป้องกันไม่ให้คุณดำเนินการลบ / อัปเดตที่ไม่ดีอย่างถาวร และคุณสามารถดำเนินการทั้งหมดและตรวจสอบการบันทึกที่เหมาะสมนับหรือเพิ่มSELECTคำสั่งระหว่าง SQL ของคุณและROLLBACK TRANSACTIONเพื่อให้แน่ใจว่าทุกอย่างดูถูกต้อง

เมื่อคุณสมบูรณ์แน่ใจว่ามันไม่สิ่งที่คุณคาดว่าจะเปลี่ยนROLLBACKไปCOMMITและเรียกใช้จริง


คุณชนะฉันไปชกต่อยหนึ่งนี้! :-)
Howard Pinsley

2
ฉันเคยทำเช่นนี้ตลอดเวลา แต่มันทำให้เกิดค่าใช้จ่ายเพิ่มเติมมากในกลุ่ม DB ที่ฉันต้องหยุด
Zan Lynx

25

สำหรับทุกภาษา:

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


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

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

1
ฉันยอมรับว่ามีกรณีพิเศษที่ฉันประกาศตัวแปรเพื่อความชัดเจน (และบางครั้งเพื่อสร้างเป้าหมายสำหรับการแก้ไขข้อบกพร่อง) ประสบการณ์ของฉันคือการปฏิบัติทั่วไปคือการทำผิดในทิศทางตรงกันข้าม
dkretz

ฉันเห็นด้วยกับมุมมองทั้งสอง; แม้ว่าเมื่อฉันแบ่งนิพจน์เป็นตัวแปรชั่วคราวฉันพยายามทำภายในขอบเขตที่แยกต่างหาก แลมบ์ดาเป็นสิ่งที่ยอดเยี่ยมสำหรับเรื่องนี้เช่นเดียวกับวิธีการช่วยเหลือ
Erik Forbes

19

เมื่อมีข้อสงสัยให้ทิ้งระเบิดแอปพลิเคชัน!

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

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


และแน่นอน: ใช้รหัสทั่วไป (ไลบรารีขนาดเล็กวิธีการขยายใน C # อะไรก็ตาม) เพื่อให้ง่าย ดังนั้นคุณสามารถเขียน somethin glike param.NotNull("param")แทนได้if ( param == null ) throw new ArgumentNullException("param");
peSHIr

2
หรือใช้การเขียนโปรแกรมตามสัญญาเช่น Spec #!
bzlm

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

6
@ MarkJ: คุณไม่เข้าใจใช่มั้ย ถ้ามันระเบิดเร็ว (= ระหว่างการพัฒนาและทดสอบ) มันจะไม่ระเบิดเมื่ออยู่ในการผลิต ดังนั้นฉันหวังว่าพวกเขาจะทำรายการเช่นนี้!
peSHIr

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

18

ใน Java โดยเฉพาะอย่างยิ่งกับคอลเลกชันให้ใช้ API ดังนั้นหากวิธีการของคุณส่งคืนรายการประเภท (ตัวอย่าง) ให้ลองทำดังต่อไปนี้:

public List<T> getList() {
    return Collections.unmodifiableList(list);
}

อย่าปล่อยให้สิ่งใดหลบหนีชั้นเรียนของคุณที่คุณไม่ต้องการ!


+1 ใน C # มีคอลเล็กชันแบบอ่านอย่างเดียวสำหรับสิ่งนี้
tobsen

1
+1 สำหรับ Java ฉันใช้สิ่งนี้ตลอดเวลา
Fortyrunner

+1 ... ฉันทำสิ่งนี้มาก (แม้ว่าฉันต้องการให้คนจำได้มากกว่านี้)
Ryan Delucchi

เพียงให้แน่ใจว่าไม่มีอะไรอื่นมีอินสแตนซ์ของตัวแปรรายการพื้นฐานหรือนี้จะไม่ทำคุณดีมาก ...
GreenieMeanie

5
FYI, Collections.unmodifiableList กลับไม่เปลี่ยนรูปมุมมองของรายการที่ไม่เปลี่ยนรูปสำเนา ดังนั้นหากรายการเดิมได้รับการแก้ไขมุมมองจะ!
Zarkonnen

17

ใน Perl ทุกคนทำ

use warnings;

ฉันชอบ

use warnings FATAL => 'all';

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

use warnings FATAL => 'all';
...
my $string = getStringVal(); # something bad happens;  returns 'undef'
print $string . "\n";        # code dies here

หวังว่านี่จะเป็นการโฆษณาที่มากขึ้น ...
DJG

16

ค#:

string myString = null;

if (myString.Equals("someValue")) // NullReferenceException...
{

}

if ("someValue".Equals(myString)) // Just false...
{

}

เหมือนกันใน Java และภาษา OO ส่วนใหญ่
MiniQuark

นี่เป็นสิ่งที่ดีใน Objective-C ซึ่งเป็นไปได้ที่จะส่งข้อความไปยังศูนย์ การเรียก [nil isEqualToString: @ "Moo"] ส่งคืนค่าเท็จ
zoul

ฉันไม่เห็นด้วยกับตัวอย่าง C # โซลูชันที่ดีกว่าคือการใช้ "if (myString ==" someValue ")" ยังไม่มีข้อยกเว้นอ้างอิง null และสามารถอ่านได้มากขึ้นอย่างแน่นอน
Dan C.

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

2
ใน C # ฉันมักจะใช้ string เสมอ Equal (<string1>, <string2>) ไม่สำคัญว่าหากหนึ่งในนั้นเป็นโมฆะ
Darcy Casselman

15

ในการตรวจสอบ c # ของสตริง IsNullOrEmpty ก่อนทำการดำเนินการใด ๆ กับสตริงเช่นความยาว, indexOf, mid ฯลฯ

public void SomeMethod(string myString)
{
   if(!string.IsNullOrEmpty(myString)) // same as myString != null && myString != string.Empty
   {                                   // Also implies that myString.Length == 0
     //Do something with string
   }
}

[แก้ไข]
ตอนนี้ฉันยังสามารถทำสิ่งต่อไปนี้ใน. NET 4.0 ซึ่งจะตรวจสอบเพิ่มเติมว่าค่านั้นเป็นเพียงช่องว่างหรือไม่

string.IsNullOrWhiteSpace(myString)

7
นั่นไม่ใช่การป้องกัน แต่ก็ไม่สนใจปัญหา if (!string.IsNullOrEmpty(myString)) throw new ArgumentException("<something>", "myString"); /* do something with string */ควรจะเป็น
enashnash

14

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


และ - บน Windows - สำหรับ C ++ ด้วย! (เปิดใช้งานด้วยการโยนข้อยกเว้น SEH พิเศษและการติดตามต่อไปนี้)
Brian Haak

12

ด้วย VB.NET ให้ Option Explicit และ Option Strict เปิดเป็นค่าเริ่มต้นสำหรับ Visual Studio ทั้งหมด


แม้ว่าฉันจะทำงานกับรหัสที่เก่ากว่าดังนั้นฉันจึงไม่ได้เปิดใช้งานตัวเลือกที่เข้มงวด (ทำให้เกิดข้อผิดพลาดในการรวบรวมคอมไพเลอร์มากเกินไป) การเปิดใช้งานตัวเลือกทั้งสองนี้ (และในกรณีของฉัน) บันทึกใจ ปวด.
Kibbee

1
สำหรับทุกคนที่แปลงรหัสเก่าที่ไม่ได้ใช้ตัวเลือกที่เข้มงวดเพื่อใช้งานโปรดทราบว่าในกรณีของรายการที่ถูกเปลี่ยนเป็นสตริงโดยอัตโนมัติพวกเขาไม่ได้ใช้ ToString () พวกเขากำลังใช้ cast to string ในช่วงต้นวัน. NET ของฉันฉันจะเปลี่ยนสิ่งเหล่านี้เพื่อใช้ ToString () และมันจะทำลายสิ่งต่าง ๆ โดยเฉพาะอย่างยิ่งกับ enums
Ryan Lundy

10

C ++

#define SAFE_DELETE(pPtr)   { delete pPtr; pPtr = NULL; }
#define SAFE_DELETE_ARRAY(pPtr) { delete [] pPtr; pPtr = NULL }

จากนั้นแทนที่การเรียก ' ลบ pPtr ' และ ' ลบ [] pPtr ' ของคุณด้วยSAFE_DELETE (pPtr)และSAFE_DELETE_ARRAY (pPtr)

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


1
ควรใช้เทมเพลต มันเป็นขอบเขตและมากเกินไป

ฉันกำลังจะบอกว่า ใช้เทมเพลตแทนแมโคร ด้วยวิธีนี้หากคุณต้องการก้าวผ่านโค้ดคุณสามารถทำได้
Steve Rowe

ฉันเรียนรู้วิธีที่ง่ายต่อการแก้ไขจุดบกพร่องในโรงเรียน นั่นเป็นความผิดพลาดที่ฉันไม่ได้ทำ :)
Greg D

3
หรือใช้ Smart Pointers ... หรือ heck หลีกเลี่ยงใหม่ / ลบมากที่สุดเท่าที่จะทำได้
Arafangion

1
@Arafangion: deleteเพียงแค่หลีกเลี่ยง ใช้งานnewได้ดีตราบใดที่วัตถุใหม่ได้รับตัวชี้สมาร์ท
Alexandre C.

10

ด้วย Java คุณสามารถใช้ประโยชน์จากคีย์เวิร์ด assert ได้แม้ว่าคุณจะเรียกใช้โค้ดการผลิตที่ปิดการยืนยันแล้ว:

private Object someHelperFunction(Object param)
{
    assert param != null : "Param must be set by the client";

    return blahBlah(param);
}

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


ใน. NET Debug.Assert ทำสิ่งเดียวกัน เมื่อใดก็ตามที่คุณมีสถานที่ที่คุณคิดว่า "การอ้างอิงนี้ไม่สามารถเป็นโมฆะที่นี่ใช่มั้ย?" คุณสามารถใส่ Debug.Assert ที่นั่นเพื่อที่ว่าถ้ามันสามารถเป็นโมฆะ, คุณสามารถแก้ไขข้อผิดพลาดหรือเปลี่ยนสมมติฐานของคุณ
ไรอันลุน

1
+1, วิธีสาธารณะควรทิ้งความล้มเหลวของสัญญา, เอกชนควรยืนยัน
user7116

9

ฉันไม่พบreadonlyคำหลักจนกว่าฉันจะพบ ReSharper แต่ตอนนี้ฉันใช้มันโดยสัญชาตญาณโดยเฉพาะอย่างยิ่งสำหรับชั้นเรียนบริการ

readonly var prodSVC = new ProductService();

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

C # ไม่อนุญาตให้คุณสามารถทำเครื่องหมายตัวแปรท้องถิ่นเป็นอ่านได้อย่างเดียวดังนั้นเราจึงไม่ได้มีทางเลือก ...
Jason Punyon

ฉันไม่แน่ใจว่าที่นี่หมายความว่าอ่านอย่างเดียว แต่สุดท้ายของ Java ไม่เพียงพอสำหรับฉัน หมายความว่าตัวชี้ไปยังวัตถุนั้นไม่มีการเปลี่ยนแปลง แต่ไม่มีวิธีป้องกันการเปลี่ยนแปลงของวัตถุ
Slartibartfast

ใน C # โครงสร้างแบบอ่านอย่างเดียวจะป้องกันไม่ให้มีการเปลี่ยนแปลง
ซามูเอล

9

ใน Java เมื่อมีบางสิ่งเกิดขึ้นและฉันไม่รู้ว่าทำไมบางครั้งฉันจะใช้ Log4J ดังนี้:

if (some bad condition) {
    log.error("a bad thing happened", new Exception("Let's see how we got here"));
}

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


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

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

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

9

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

ตัวอย่าง:

class Foo
{
   virtual void DoSomething();
}

class Bar: public Foo
{
   void DoSomething() override { /* do something */ }
}

สำหรับ Java นี่คือคลาส Foo {void doSomething () {}} คลาสบาร์ {@Override void doSomething () {}} จะให้คำเตือนหากไม่มีคำอธิบายประกอบ (ดังนั้นคุณจึงไม่สามารถแทนที่วิธีที่คุณไม่ได้ทำ หมายถึง) และเมื่อมีคำอธิบายประกอบอยู่ที่นั่น แต่ไม่ได้แทนที่อะไรเลย
Jorn

ดี ... ฉันไม่รู้เกี่ยวกับอันนี้ ... มันแย่มากที่ดูเหมือนจะเฉพาะเจาะจงกับ Microsoft ... แต่
#defines

8

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

สิ่งนี้ได้ช่วยแยกแยะสภาพการแข่งขันและเงื่อนไขการล๊อคหลอกที่ไม่น่าเชื่อก่อนที่ฉันจะเริ่มทำสิ่งนี้


1
การรอด้วยการหมดเวลาที่ใช้เช่นนี้เป็นสัญญาณของปัญหาอื่น ๆ แย่ลง
dicroce

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

8

ค#

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

8

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

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


1
เมื่อเขียนรหัสเพื่อหาข้อความแสดงข้อผิดพลาดอ่านข้อความและถามสิ่งที่คุณต้องการทราบต่อไปจากนั้นเพิ่ม ทำซ้ำจนกว่าจะไม่มีเหตุผล ตัวอย่างเช่น: "อยู่นอกช่วง" อยู่นอกช่วงอะไร "ฟูนับนอกระยะ" คุณค่าคืออะไร "ฟูนับ (42) อยู่นอกระยะ" ช่วงคืออะไร? "ฟูนับ (42) อยู่นอกระยะ (549 ถึง 666)"
HABO

7

ใน C # ให้ใช้asคำสำคัญเพื่อส่ง

string a = (string)obj

จะโยนข้อยกเว้นถ้า obj ไม่ใช่สตริง

string a = obj as string

จะปล่อยให้เป็นโมฆะถ้า obj ไม่ใช่สตริง

คุณยังคงต้องคำนึงถึง null แต่โดยทั่วไปแล้วจะตรงไปข้างหน้ามากขึ้นแล้วมองหาข้อยกเว้น cast บางครั้งคุณต้องการพฤติกรรมประเภท "cast or blow up" ซึ่งเป็นกรณี(string)objที่ต้องการไวยากรณ์

ในรหัสของฉันฉันพบว่าฉันใช้asไวยากรณ์ประมาณ 75% ของเวลาและ(cast)ไวยากรณ์ประมาณ 25%


ถูกต้อง แต่ตอนนี้คุณต้องตรวจสอบ null ก่อนใช้การอ้างอิง
Brian Rasmussen

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

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

2
เรื่องนี้ดูเหมือนจะเป็นการป้องกันเหมือนหน้าต่างห้องบอลรูมขนาดใหญ่ในป้อมปราการ แต่มันเป็นมุมมองที่น่ารัก!
Pontus Gagge

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

6

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

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

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


6

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

ในข้อผิดพลาดในการเขียนโปรแกรม 25 อันดับแรกที่อันตรายที่สุด "การตรวจสอบอินพุตที่ไม่เหมาะสม" เป็นข้อผิดพลาดที่อันตรายที่สุดในส่วน "การโต้ตอบที่ไม่ปลอดภัยระหว่างส่วนประกอบ"

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

เพื่อที่จะใช้ค่าคงที่ฉันเขียนวิธีการในชั้นเรียนใด ๆ ที่ตรวจสอบ "ความสอดคล้องระดับ" ที่ควรจะเรียกว่าอัตโนมัติโดยเงื่อนไขก่อนและมาโคร postcondition

ผมประเมินห้องสมุดสัญญารหัส


6

ชวา

java api ไม่มีแนวคิดของวัตถุที่ไม่เปลี่ยนรูปซึ่งไม่ดี! รอบชิงชนะเลิศสามารถช่วยคุณได้ในกรณีนี้ แท็กทุกชั้นเรียนที่ไม่เปลี่ยนรูปด้วยรอบชิงชนะเลิศและเตรียมชั้นเรียนตามนั้น

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

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

ไม่เคยใช้โคลนใช้ตัวสร้างสำเนา

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


5

ฉันลืมเขียนechoPHP หลายครั้งเกินไป:

<td><?php $foo->bar->baz(); ?></td>
<!-- should have been -->
<td><?php echo $foo->bar->baz(); ?></td>

มันจะพาฉันไปตลอดกาลเพื่อลองคิดดูว่าทำไม -> baz () ไม่ได้กลับมาอะไรเลยในความเป็นจริงฉันแค่ไม่ได้สะท้อน! : -S ดังนั้นฉันจึงสร้างEchoMeคลาสที่สามารถห่อหุ้มคุณค่าที่ควรสะท้อน:

<?php
class EchoMe {
  private $str;
  private $printed = false;
  function __construct($value) {
    $this->str = strval($value);
  }
  function __toString() {
    $this->printed = true;
    return $this->str;
  }
  function __destruct() {
    if($this->printed !== true)
      throw new Exception("String '$this->str' was never printed");
  }
}

จากนั้นสำหรับสภาพแวดล้อมการพัฒนาฉันใช้ EchoMe เพื่อห่อสิ่งที่ควรพิมพ์:

function baz() {
  $value = [...calculations...]
  if(DEBUG)
    return EchoMe($value);
  return $value;
}

การใช้เทคนิคนั้นตัวอย่างแรกที่ขาดหายไปechoจะทำให้เกิดข้อยกเว้น ...


ไม่ควร destructor ตรวจสอบ $ this-> printed! == จริงหรือ
Karsten

คุณควรพิจารณาใช้ระบบเทมเพลตการฝัง php ใน html นั้นเหมาะสมที่สุดสำหรับเกือบทุกระบบ
Cruachan

บางทีฉันอาจจะหายไปบางอย่าง แต่ดูเหมือนว่าฉันจะพยายามชดเชยการเข้ารหัส: AnObject.ToStringแทนที่จะเป็นWriteln(AnObject.ToString)?
ไม่แยแส

ใช่ แต่ความผิดพลาดง่ายกว่าใน PHP
มากเกินไป php

4

C ++

เมื่อฉันพิมพ์ใหม่ฉันต้องพิมพ์ลบทันที โดยเฉพาะอย่างยิ่งสำหรับอาร์เรย์

ค#

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


ฉันชอบจุดแรกของคุณ ฉันทำสิ่งที่คล้ายกันเช่นเมื่อเขียนวิธีการที่ส่งกลับคอลเลกชันของบางสิ่งบางอย่าง ฉันสร้างคอลเลกชันในบรรทัดแรกและเขียนคำสั่งส่งคืนทันที สิ่งที่เหลืออยู่คือการเติมวิธีการรวบรวมคอลเลกชัน
Outlaw Programmer

5
ใน C ++ เมื่อคุณพิมพ์ใหม่คุณควรกำหนดตัวชี้นั้นให้กับ AutoPtr หรือคอนเทนเนอร์ที่นับโดยอ้างอิงทันที C ++ มี destructors และแม่แบบ ใช้อย่างชาญฉลาดเพื่อจัดการการลบโดยอัตโนมัติ
Anrewdrew

4

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

นอกจากนี้ 'strace -p [pid]' บน linux จะแสดงว่าคุณต้องการให้ระบบเรียกใช้กระบวนการ (หรือเธรด linux) มันอาจดูแปลกในตอนแรก แต่เมื่อคุณคุ้นเคยกับการเรียกของระบบโดยการเรียกใช้ libc คุณจะพบว่าสิ่งนี้มีค่าสำหรับการวินิจฉัยภาคสนาม

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