Bài giảng Kỹ thuật lập trình - Chương 5: Defensive Programming - Vũ Đức Vượng

•Xuất phát từ khái niệm defensive driving.

•Khi lái xe bạn luôn phải tâm niệm rằng bạn không bao giờ biết chắc được người lái xe khác sẽ làm gì. Bằng cách đó, bạn có thể chắc chắn rằng khi họ làm điều gì nguy hiểm, thì bạn sẽ không bị ảnh hưởng ( tai nạn).

•Bạn có trách nhiệm bảo vệ bản thân, ngay cả khi người khác có lỗi

•Trong defensive programming, ý tưởng chính là nếu chương trình ( con) được truyền dữ liệu tồi, nó cũng không sao, kể cả khi với CT khác thì sẽ bị fault.

•Một cách tổng quát,  lập trình phòng thủ nghĩa là : làm thế nào để tự bảo vệ mình khỏi thế giới lạnh lùng,tàn nhẫn của dữ liệu không hợp lệ, các sự kiện mà có thể "không bao giờ" xảy ra, và các lập trình viên khác ‘sai lầm’

ppt 42 trang xuanthi 27/12/2022 1540
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 5: Defensive Programming - Vũ Đức Vượng", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pptbai_giang_ky_thuat_lap_trinh_chuong_5_defensive_programming.ppt

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 5: Defensive Programming - Vũ Đức Vượng

  1. Khai niem : DEFENSIVE PROGRAMMING • Xuất phát từ khái niệm defensive driving. • Khi lái xe bạn luôn phải tâm niệm rằng bạn không bao giờ biết chắc được người lái xe khác sẽ làm gì. Bằng cách đó, bạn có thể chắc chắn rằng khi họ làm điều gì nguy hiểm, thì bạn sẽ không bị ảnh hưởng ( tai nạn). • Bạn có trách nhiệm bảo vệ bản thân, ngay cả khi người khác có lỗi • Trong defensive programming, ý tưởng chính là nếu chương trình ( con) được truyền dữ liệu tồi, nó cũng không sao, kể cả khi với CT khác thì sẽ bị fault. • Một cách tổng quát, lập trình phòng thủ nghĩa là : làm thế nào để tự bảo vệ mình khỏi thế giới lạnh lùng,tàn nhẫn của dữ liệu không hợp lệ, các sự kiện mà có thể "không bao giờ" xảy ra, và các lập trình viên khác ‘sai lầm’
  2. 3 cách để xử lý rác vào. • Kiểm tra giá trị của mọi dữ liệu từ nguồn bên ngoài – Khi nhận dữ liệu từ file, bàn phím, mạng, hoặc từ các nguồn ngoài khác, hãy kiểm tra đê đảm bảo rằng dữ liệu nằm trong giới hạn cho phép. – Hãy đảm bảo rằng giá trị số nằm trong dung sai và xâu phải đủ ngẵn để xử lý , Nếu một chuỗi được dự định để đại diện cho một phạm vi giới hạn của các giá trị (như một ID giao dịch tài chính hoặc một cái gì đó tương tự), hãy chắc chắn rằng các chuỗi là hợp lệ cho mục đích của nó; nếu không từ chối . – Nếu bạn làm việc trên 1 ứng dụng bảo mật, hãy đực biệt lưu ý đến những dữ liệu có thể tấn công hệ thống : Cố làm tràn bộ nhớ , injected SQL commands, injected html hay XML code, tràn số
  3. 2 Assertions • 1 macro hay 1 CT con dùng trong quá trình phát triển ứng dụng , cho phép CT tự kiểm tra khi chạy. • Return true >> OK, false >> có 1 lỗi gì đó trong CT. • VD : Nếu hệ thống cho rằng file dữ liệu về khách hàng không bao giờ vượt quá 50 000 bản ghi, CT có thể chứa 1 assertion rằng số bản ghi là <= 50 000. Khi mà số bản ghi <= 50,000, assertion sẽ không có phản ứng gì. Nếu đếm đc hơn 50 000 bản ghi, nó sẽ lớn tiếng “khẳng định” rằng có 1 lỗi trong CT
  4. • End users không cần thấy các thông báo của assertion ; • Assertions chủ yếu đc dùng trong quá trình phát triển hay bảo dưỡng ứng dụng. • Dịch thành code khi phát triển, loại bỏ khỏi code trong sản phẩm >>performance
  5. Guidelines for Using Assertions • Sử dụng code xử lý lỗi với những điều kiện ta chờ đợi sẽ xảy ra; Dùng assertions cho các ĐK không mong đợi ( không bao giờ xảy ra) – Error-handling : checks for bad input data – Assertions : check for bugs in the code. – Error handling hướng tới việc xử lý lỗi, còn assertion thì hướng đến việc hiệu chỉnh chương trình , tạo ra new version of software • Tránh đưa code xử lý vào trong assertions – Điều gì xảy ra khi ta turn off the assertions ?
  6. 3. Kỹ thuật xử lý lỗi Error Handling Techniques • Error handling dùng để xử lý các lỗi mà ta chờ đợi sẽ xảy ra • Tùy theo tình huống cụ thể, ta có thể trả về 1 giá trị trung lập, thay thế đoạn tiếp theo của dữ liệu hợp lệ, trả về cùng giá trị như lần trước, thay thế giá trị hợp lệ gần nhất, Ghi vết 1 cảnh báo vào tệp, trả về 1 mã lỗi, gọi 1 thủ tục hay đối tượng xử lý, hiện 1 tbaos hay tắt máy
  7. 4. Xử lý ngoại lệ - Exceptions • Exception : bắt các tình huống bất thường và phục hồi chúng về trạng thái trước đó. • Dùng Ngoại lệ để thông báo cho các bộ phận khác của chương trình về lỗi không nên bỏ qua – Lợi ích của ngoại lệ là khả năng báo hiệu điều kiện lỗi . Phương pháp tiếp cận khác để xử lý các lỗi tạo ra khả năng mà một điều kiện lỗi có thể truyền bá thông qua một cơ sở mã không bị phát hiện. Ngoại lệ có thể loại trừ khả năng đó. • Chỉ dùng ngoại lệ cho những điều kiện thực sự ngoại lệ – Exceptions đc dùng trong những tình huống giống assertions— cho các sự kiện không thường xuyên, nhưng có thể không bao giờ xảy ra – Exception có thể bị lạm dụng và phá vở các cấu trúc, điều này dễ gây ra lỗi, vì làm sai lệch luồng điều khiển
  8. Dim tran As SqlTransaction Try conn.Open() tran = conn.BeginTransaction() SqlHelper.ExecuteNonQuery(tran, "ThemHDon",_ HDInfo.SoHoaDonTC, HDInfo.TenKhach, _ HDInfo.PhuongThucTT) iMaHD = GetMaHoaDon_Integer(tran) For Each objCT In arrDSCT SqlHelper.ExecuteNonQuery(tran, "ThemChiTietHD", objCT.ChiTiet, _ objCT.SoTienVND, iMaHDP) Next tran.Commit() Catch ex As Exception tran.Rollback() End Try
  9. 5.Gỡ rối - debbuging • Các chương trình đã viết có thể đã có nhiều lỗi ? – tại sao phần mềm lại phức tạp vây ? • Sự phức tạp của Ct liên quan đến cách thức tương tác của các thành phần của ct đó, mà 1 phần mềm lại bao gồm nhiều thành phần và các tương tác giữa chúng • Nhiều kỹ thuật làm giảm số lượng các thành phần tương tác : – Che giấu thông tin – Trừu tượng hóa • Có các kỹ thuật nhàm đảm bảo tính toàn vẹn thiết kế phần mềm – Documentation – Lập mô hình – Phân tích các yêu cầu – Kiểm tra hình thức • Nhưng chưa có 1 kỹ thuật nào làm thay đổi cách thức xây dựng phần mềm => luôn xuất hiện lỗi khi test, phai loại bỏ = gỡ rối !
  10. • Động lực chính cho việc cải tiến các ngôn ngữ LT là cố gắng ngăn chặn các lỗi thông qua các đặc trưng ngôn ngữ như : – Kiểm tra các giới hạn biên của các chỉ số – Hạn chế không dùng con trỏ, bộ dọn dẹp, các kiểu dữ liệu chuỗi – Xác định kiểu nhập/xuất – Kiểm tra dữ liệu chặt chẽ. • Mỗi ngôn ngữ cũng có những đặc tính dễ gây lỗi : lệnh goto, biến toàn cục, con trỏ trỏ tới vùng không xác định, chuyển kiểu tự động • LTV cần biết trước những đặc thù để tránh các lỗi tiềm ẩn, đồng thời cần kích hoạt mọi khả năng kiểm tra của trình biên dịch và quan tâm đến các cảnh báo • Ví dụ : so sánh C,Pascal, VB
  11. Understand Error Messages Gỡ rối khi build-time dễ hơn lúc run-time, khi và chỉ khi ta (1) Hiểu đc các thông báo lỗi!!! • Một số là từ preprocessor Misspelled #include file #include int main(void) /* Print "hello, world" to stdout and return 0. { Missing */ printf("hello, world\n"); return 0; } $ gcc217 hello.c -o hello hello.c:1:20: stdioo.h: No such file or directory hello.c:3:1: unterminated comment hello.c:2: error: syntax error at end of input
  12. Understand Error Messages (tt) (1) Hiểu đc các thông báo lỗi!!! • Một số là từ linker #include Misspelled int main(void) function name /* Print "hello, world" to stdout and return 0. */ { prinf("hello, world\n") return 0; } Compiler warning (not error): Linker error: Cannot find prinf() is called before declared definition of prinf() $ gcc217 hello.c -o hello hello.c: In function `main': hello.c:6: warning: implicit declaration of function `prinf' /tmp/cc43ebjk.o(.text+0x25): In function `main': : undefined reference to `prinf' collect2: ld returned 1 exit status
  13. Các phương pháp gỡ rối • Có đầu mỗi , phát hiện dễ ràng : – Khi có lỗi, ta thường đổ cho trình dịch, thư viện hay bất cứ nguyên nhân nào khác tuy nhiên, cuối cùng thì lỗi vẫn thuộc về CT – Rất may là hầu hết các lỗi thường đơn giản và dễ tìm. Hãy khảo sát các đầu mối của việc xuất ra kq có lỗi và cố gắng suy ra nguyên nhân gây ra nó – Khi có đc 1 số thông tin về lỗi và nơi xảy ra lỗi, hãy tạm dừng để ngẫm nghĩ xem lỗi xảy ra ntn. – Suy luận ngược trở lại trạng thái của CT bị hỏng để xđ nguyên nhân gây ra lỗi – Gỡ rối liên quan đến việc lập luận lùi, giỗng như tìm kiếm các bí mật của 1 vụ án. 1 số vđề không thể xảy ra và chỉ có những thông tin xác thực mới đáng tin cậy. => phải đi ngược từ kết quả để khám phá nguyên nhân, khi có lời giải thích đầy đủ, ta sẽ biết đc vấn đề cần sửa và có thể phát hiện ra 1 số vđề khác
  14. Các phương pháp gỡ rối • Kiểm tra sự thay đổi mới nhất – Lỗi thường xảy ra ở những đoạn CT mới đc bổ xung – Nếu phiên bản cũ OK, phiên bản mới có lỗi => lỗi chắc chắn nằm ở những đoạn CT mới – Lưu ý, khi sửa đổi, nâng cấp : hãy giữ lại phiên bản cũ – đơn giản là comment lại đoạn mã cũ – Đặc biệt, với các hệ thống lớn, làm việc nhóm thì việc sử dụng các hệ thống quản lý phiên bản mã nguồn và các cơ chế lưu lại quá trình sửa đổi là vô cùng hữu ích ( source safe )
  15. Các phương pháp gỡ rối • Gỡ rối ngay khi gặp – Khi phát hiện lỗi, hãy sửa ngay, đừng để sau mới sửa, vì có thể lỗi không xuất hiện lại ( do tình huống) – Cũng đừng quá vội vàng, không suy nghĩ chín chắn, kỹ càng, vì có thể việc sửa chữa này ảnh hưởng tới các tình huống khác
  16. Các phương pháp gỡ rối • Giải thích cho người khác về đoạn code – Tạo đk để ngẫm nghĩ – Thậm chí có thể giải thích cho người không phải LTV – Extrem programming : làm việc theo cặp, pair programming, người này LT, người kia kiểm tra, và ngược lại – Khi gặp vấn đề, khó khăn, chậm tiến độ, lập tức thay đổi công việc => rút ra khỏi luồng quán tính sai lâm
  17. Các phương pháp gỡ rối • Hiển thị kết quả để định vị khu vực gây lỗi – Thêm vào các dòng lệnh in giá trị các biến liên quan, hoặc đơn giản xác định tiến trình thực hiện : “đến đây 1” • Viết mã tự kiểm tra – Viết thêm 1 hàm để kiểm tra, gắn vào trước và sau đoạn có nguy cơ, comment lại sau khi đã xử lý lỗi • Tạo log file • Lưu vết – Giúp ghi nhớ đc các vấn đề đã xảy ra, và giải quyết các vđề tương tự sau này, cũng như khi chuyển giao CT cho người khác
  18. Hiển thị KQ (cont.) In debugging output –Maybe even better: ra stderr; debugging output có thể tách fprintf(stderr, "%d", keyvariable); biệt với các in ân của CT –Maybe better still: Ngoài ra: stderr không dùng buffer FILE *fp = fopen("logfile", "w"); fprintf(fp, "%d", keyvariable); Ghi ra 1 a log file fflush(fp);
  19. • Các lỗi xuất hiện thất thường : – Khó giải quyết – Thường gán cho lỗi của máy tính, hệ điều hành – Thực ra là do thông tin của chính CT : không phải do thuật toán, mà do thông tin bị thay đổi qua mỗi lần chạy – Các biến đã đc khởi tạo hết chưa ? – Lỗi cấp phát bộ nhớ ? Vd : char *vd( char *s) { char m[101]; strncpy(m,s,100) return m; } - Giải phóng bộ nhớ động ? for (p=listp; p!=NULL; p=p->next) free(p) ; ???
  20. Thêm – Những lỗi thường gặp với C, C++ 1. Array as a parameter handled improperly – Tham số mảng đc xử lý không đúng cách 2. Array index out of bounds – Vượt ra ngoài phạm vi chỉ số mảng 3. Call-by-value used instead of call-by reference for function parameters to be modified – Gọi theo giá trị, thay vì gọi theo tham chiếu cho hàm để sửa 4. Comparison operators misused – Các toán tử so sánh bị dùng sai 5. Compound statement not used - Lệnh phức hợp không đc dùng 6. Dangling else - nhánh else khong hợp lệ 7. Division by zero attempted - Chia cho 0 8. Division using integers so quotient gets truncated – Dùng phép chia số nguyên nên phần thập phân bị cắt 9. Files not closed properly (buffer not flushed) - File không đc đóng phù hợp ( buffer không bị dẹp) 10. Infinite loop - lặp vô hạn 11. Global variables used – dùng biến tổng thể
  21. 22. Off-by-one error in a loop – Thoát khỏi bởi 1 lỗi trong vòng lặp 23. Overused (overloaded) local variable names - Trùng tên biến cục bộ 24. Pointers not set properly or overwritten in error – Con trỏ không đc xác định đúng hoặc trỏ vào 1 vị trí không có 25. Return with value attempted in void function – trả về 1 giá trị trong 1 hàm void 26. Undeclared variable name – không khai báo biến 27. Un-initialized variables – Không khởi tạo giá trị 28. Unmatched parentheses – thiếu } 29. Un-terminated strings - xâu không kết thúc , thiếu “ 30. Using "=" when "= =" is intended or vice versa 31. Using "&" when "&&" is intended or vice versa 32. "while" used improperly instead of "if“ – while đc dùng thay vì if