Cách tốt nhất để chuẩn bị thiết kế và mã của bạn cho những con bọ không biết đến đó là gì từ ngày đầu tiên?


8

Tôi chỉ tự hỏi, có phương pháp hay kỹ thuật thực tế nào hay thậm chí là các thủ thuật để tránh những lỗi "không xác định" đó, đặc biệt là những lỗi khó chịu và ngẫu nhiên thường xuất hiện vào phút cuối hoặc ít nhất là giữ những thứ này ở mức tối thiểu. Tôi hỏi điều này bởi vì khi bạn làm việc trên một nền tảng mới hoặc lần đầu tiên sử dụng một công nghệ mới nhất định, làm thế nào để bạn biện minh cho thiết kế và mã của bạn đủ mạnh? Hoặc những điều này chỉ có thể được học bởi thời gian và sai lầm?

(Tôi sử dụng C ++ trong phần lớn thời gian làm việc của mình)

Cảm ơn!

Câu trả lời:


5

Gần hai mươi năm trước, tôi đã hiểu rất nhiều về điều này từ cuốn sách tuyệt vời "Không có lỗi: Cung cấp mã không có lỗi trong C và C ++" của David Thielen, hiện đang có sẵn dưới dạng PDF miễn phí .

Anh ấy dạy tôi hai ý tưởng tuyệt vời ...

Lỗi không đến từ đâu. Tất cả các lập trình viên của chúng tôi ngồi xuống và viết chúng vào mã của chúng tôi bằng ngón tay của chúng tôi.

"Lỗi" hàm ý rằng một số cơ quan bên ngoài đã quyết định phá hoại chương trình của bạn với lỗi và nếu bạn sống một cuộc sống sạch sẽ và hy sinh những con thú lông nhỏ dưới chân máy tính của bạn, chúng sẽ biến mất ... Khái niệm này rất quan trọng vì nó có màu sắc cách tiếp cận của bạn để gỡ lỗi mã của bạn. Nếu bạn xem lỗi là "lỗi", bạn hy vọng không tìm thấy lỗi nào. (Bạn hy vọng bà tiên tốt bụng đến, rắc bụi pixie và những con bọ còn sót lại.)

Lỗi không nên được gọi là lỗi, chúng nên được gọi là lỗi lớn [MFU] ... MFU tồn tại bởi vì các chương trình được viết bởi mọi người và mọi người mắc lỗi ... Bạn sẽ viết MFU. Bạn sẽ ngồi xuống và với ác ý hoàn toàn về việc suy nghĩ, hãy đặt MFU vào mã của bạn. Hãy suy nghĩ về nó - bạn biết rằng bạn là người đưa các lỗi vào đó. Vì vậy, nếu bạn ngồi xuống mã, bạn sẽ chèn một số lỗi.

Vì đó là định mệnh không thể tránh khỏi của các lập trình viên để viết lỗi, tôi cần mã hóa phòng thủ, bao gồm cả những thứ sẽ nhảy lên, hét lên và vẫy cờ đỏ khi họ phát hiện ra lỗi.

Được viết vào đầu những năm 90, những chi tiết cụ thể về điều này trong cuốn sách của Thielen khá là cũ. Chẳng hạn, trên Linux và Mac OS X, bạn không còn cần phải viết trình bao bọc của riêng mình cho toán tử mới C ++; bạn có thể sử dụng valgrind cho điều đó.

Nhưng có một vài điều tôi thường làm cho C / C ++ / ObjC:

  1. Khi tôi có thể hợp lý, hãy bật tùy chọn "Cảnh báo là lỗi" của trình biên dịch và sửa tất cả. (Tôi duy trì một dự án cũ mà việc sửa tất cả các dự án đó sẽ mất vài tuần, vì vậy tôi chỉ sửa một tệp mỗi vài tuần - và trong vài năm, tôi có thể bật tùy chọn đó lên.)
  2. Sử dụng một công cụ phân tích mã tĩnh, như PC-Lint của Gimpel hoặc công cụ rất tiện lợi hiện được tích hợp trong Xcode của Apple. Coverity thậm chí còn tốt hơn, nhưng chi phí dành cho các tập đoàn lớn, không chỉ là người phàm trần.
  3. Sử dụng các công cụ phân tích động, như valgrind, để kiểm tra các vấn đề về bộ nhớ, rò rỉ, v.v.
  4. Như Thielen nói (và chương này vẫn đáng đọc): Khẳng định thế giới . Tất nhiên, không ai ngoài một thằng ngốc sẽ gọi hàm của bạn bằng một con trỏ không - và điều đó có nghĩa là ai đó, ở đâu đó, là một thằng ngốc sẽ làm việc đó. Nó thậm chí có thể là bạn trong ba năm khi những gì bạn đang làm hôm nay trở nên mờ mịt. Vì vậy, chỉ cần thêm một xác nhận ở đầu hàm để xác thực đối số con trỏ đó - phải mất ba giây để nhập và biến mất trong bản thực thi phát hành.
  5. Trong C ++, RTTI là bạn của bạn. Một lần nữa, không ai khác ngoài một tên ngốc sẽ gọi hàm của bạn bằng một con trỏ đến loại đối tượng sai - điều đó có nghĩa là, chắc chắn, một số kẻ ngốc sẽ - và chi phí để chống lại điều đó là không đáng kể. Trong mã dựa trên C có nguồn gốc từ GObject, bạn có thể làm điều tương tự với các macro đúc động phòng thủ.
  6. Các bài kiểm tra đơn vị và hồi quy tự động hiện là một phần quan trọng trong tiết mục của tôi. Trong một dự án, chúng là một phần không thể thiếu của hệ thống xây dựng phát hành và bản dựng sẽ không hoàn thành trừ khi tất cả chúng đều vượt qua.
  7. Một phần quan trọng khác là ghi nhật ký mã trong cả hai tệp thực thi gỡ lỗi và phát hành có thể được kích hoạt trong thời gian chạy bằng một cái gì đó giống như một biến môi trường.
  8. Viết các bài kiểm tra phòng thủ để các lập trình viên chạy các chương trình thực thi gỡ lỗi không thể bỏ qua chúng nếu chúng thất bại. Tin nhắn thời gian chạy đến bàn điều khiển có thể được bỏ qua. Chương trình bị sập với một xác nhận không thể bỏ qua.
  9. Khi thiết kế, cung cấp API công khai và các triển khai riêng tư mà mã bên ngoài không thể có được. Theo cách đó, nếu bạn phải cấu trúc lại, không ai dựa vào một số biến trạng thái nội tâm kỳ diệu hay thứ gì đó. Trong các lớp C ++, tôi là một fan hâm mộ lớn của sự bảo vệ và riêng tư cho việc này. Tôi cũng nghĩ rằng các lớp proxy là tuyệt vời, nhưng bản thân tôi không thực sự sử dụng chúng.

Tất nhiên, những gì bạn sẽ làm cho một ngôn ngữ hoặc công nghệ mới sẽ thay đổi trong các chi tiết. Nhưng một khi bạn nghĩ đến những khái niệm rằng bọ là những con quái vật khổng lồ bạn viết bằng ngón tay của chính mình, và mã của bạn bị tấn công liên tục từ một đội quân ngu ngốc, với bạn là người đứng đầu, tôi chắc chắn bạn Sẽ tìm ra các kỹ thuật phòng thủ phù hợp.


14

Chà, nếu bạn biết điều đó, thì chúng sẽ rơi vào thảm họa "lỗi chưa biết" (IE bạn biết điều gì đó có tính chất "này" sẽ xảy ra). Bất kỳ số lượng bài kiểm tra đơn vị nào sẽ không bắt được chúng, chúng chỉ thực sự hữu ích cho các trường hợp đã biết.

Cách chúng tôi xử lý vấn đề này là đưa dịch vụ ghi nhật ký lỗi vào ứng dụng đang chạy, báo cáo lại cho cơ sở khi xảy ra và xử lý khi xuất hiện. Nếu không, bạn có thể dành nhiều năm mà vẫn không bao gồm bất cứ điều gì ... đến một lúc nào đó, bạn chỉ cần chờ đợi để xem những gì xảy ra trong thế giới thực và phát triển nhanh chóng.

Bên thiết kế, bạn thiết kế để duy trì là một trong những yếu tố quan trọng.

  • Học các mẫu mà làm việc và các mẫu để tránh. Các mô hình nhất quán và đồng thời hơn bạn có thể thoải mái hơn có thể là một loại vấn đề cụ thể sẽ hoặc sẽ không xảy ra.
  • Làm cho mọi thứ rõ ràng. Quan sát dẫn đến nhầm lẫn, dẫn đến lỗi.
  • Quy ước đặt tên mạnh mẽ tất cả các cách thông qua. Nếu bạn đặt tên cho mọi thứ tốt và nhất quán, sẽ có một lượng lợi ích rất lớn khi bạn cố gắng thay đổi mọi thứ hoặc giải thích nó với mọi thứ ... mọi thứ được gọi là Factory sẽ làm X.
  • Đánh vần mọi thứ hoàn toàn. Chúng tôi đã tự động hoàn tất những ngày này không sử dụng các từ viết tắt khi từ đầy đủ loại bỏ nhầm lẫn.
  • Phân chia thành các lớp hoặc trừu tượng ... vì vậy các kiểu vấn đề cụ thể sẽ xảy ra trong một lớp cụ thể thay vì "ở đâu đó"
  • Cô lập các lớp vấn đề thành các lớp và các khía cạnh. Càng ít phần phải làm với phần khác của mã thì nói chung càng tốt. Ngay cả khi phải mất một chút thời gian để viết những thứ tương tự ra hai lần.

Và chìa khóa ... Tìm một người cố vấn đã mắc tất cả các lỗi trước đây HOẶC tạo ra một mớ hỗn độn cho đến khi bạn tìm ra những gì không và không hoạt động.


1
Tôi thích "thiết kế để bảo trì". Đặc biệt tốt là biến nhanh chóng xung quanh khi có vấn đề cuối cùng nảy sinh. Điều đó có nghĩa là các bài kiểm tra đơn vị tốt, toàn diện, chiến lược triển khai tốt và quy trình theo dõi lỗi / QA tốt.
Dean Harding

4

Tất cả những điều trên là những điểm tốt. Nhưng có một cái gì đó không được đề cập. Bạn cần phải làm cho các mô-đun và chức năng của bạn hoang tưởng. Phạm vi kiểm tra tất cả các tham số chức năng. Coi chừng các chuỗi có bắt đầu hoặc kết thúc trống hoặc quá ngắn hoặc quá dài. Coi chừng các booleans đúng hơn không sai. Trong các ngôn ngữ chưa được gõ như PHP, coi chừng các loại biến không mong muốn. Coi chừng NULL.

Mã hoang tưởng này thường được mã hóa dưới dạng các xác nhận có thể bị vô hiệu hóa trên bản dựng sản xuất để tăng tốc mọi thứ. Nhưng nó chắc chắn sẽ ngăn chặn lỗi hoảng loạn vào phút cuối.


Làm thế nào một boolean có thể không đúng cũng không sai?
Zhehao Mao

@Zhehao Mao: Nếu Boolean là một cột trong cơ sở dữ liệu, nó có thể là Đúng, Sai hoặc NULL.
Mike Sherrill 'Nhớ lại mèo'

Khi tôi là một GI, chúng tôi đã có một câu nói. "Khi tất cả mọi người thực sự ra để có được bạn, hoang tưởng chỉ là tốt, tư duy âm thanh." Một số nhà chức trách gọi đây là chương trình phòng thủ .
Mike Sherrill 'Nhớ lại mèo'

Ồ, tôi hiểu rồi. Sự kỳ lạ của SQL.
Zhehao Mao

3

Rob đã đúng khi nói rằng các bài kiểm tra đơn vị sẽ không cứu bạn khỏi các lỗi không xác định NHƯNG các bài kiểm tra đơn vị sẽ giúp bạn tránh các lỗi giới thiệu khi bạn sửa các lỗi không xác định và sẽ cứu bạn khỏi vô tình giới thiệu lại các lỗi cũ. TDD cũng sẽ buộc bạn phải thiết kế phần mềm của bạn ngay từ đầu để có thể kiểm tra được và điều đó có giá trị tích cực rất lớn.


Khía cạnh của các bài kiểm tra đơn vị này dường như là một bài kiểm tra sai lầm nhất: bạn không chứng minh tính đúng đắn của mã của mình với các lỗi không đáng tin cậy, bạn làm sai lệch tính chính xác của các thay đổi sau với nó. Nhưng mỗi khi tìm thấy một lỗi trong mã không được kiểm tra, ai đó sẽ khóc 'xem, các thử nghiệm của bạn là vô giá trị, họ đã không tìm thấy lỗi này'
keppla

Sau đó, bạn thêm một bài kiểm tra để tái tạo khiếm khuyết. Khắc phục lỗi và bạn sẽ luôn kiểm tra lỗi đó mỗi khi bạn chạy bộ kiểm tra của mình ...
hủy bỏ

đó là những gì tôi sẽ làm, nhưng điều đó thường dẫn đến 'vâng, bây giờ đã quá muộn, lỗi đã xảy ra'. Thực tế là lỗi không được giới thiệu lại thường sẽ được kiểm tra
keppla

Điều này là đúng, nhưng sau đó họ đã di cư đến nơi chưa biết :)
Robin Vessey

2

Tránh tình trạng / "tác dụng phụ" khi có thể. Mặc dù các máy tính có tính xác định và cung cấp cùng một đầu ra cho cùng một đầu vào, nhưng tổng quan về đầu vào luôn không đầy đủ. Đáng buồn thay, hầu hết thời gian chúng tôi không nhận ra nó không đầy đủ như thế nào .

Khi nói về các ứng dụng web, toàn bộ cơ sở dữ liệu, yêu cầu hiện tại, phiên của người dùng, thư viện của bên thứ 3 đã cài đặt và nhiều phần khác của đầu vào. Khi nói về các chủ đề, nó thậm chí còn tệ hơn: toàn bộ hệ điều hành của bạn, với tất cả các quy trình khác được quản lý bởi cùng một bộ lập lịch là 'một phần của đầu vào'.

Lỗi được gây ra bởi đánh giá sai cách xử lý đầu vào hoặc đánh giá sai đầu vào. Theo kinh nghiệm của tôi, sau này là những điều khó khăn: bạn chỉ có thể quan sát chúng 'sống', thông thường, bạn không còn đầu vào nữa.

Khi tìm hiểu Công nghệ mới, Cơ sở hạ tầng, v.v., đó là cách tốt nhất để có cái nhìn tổng quan, thành phần nào đóng góp cho đầu vào và sau đó cố gắng tránh càng nhiều trong số chúng càng tốt .


+1: Các tác dụng phụ thường có thể tránh được bằng cách áp dụng các nguyên tắc RẮN và tạo ra các phương pháp nguyên tử. Ngoài ra, mã phải được bao phủ bởi các khẳng định.
Falcon

0

Khi phần mềm của bạn trở nên phức tạp hơn, không thể tránh khỏi một số lỗi sẽ xảy ra. Cách duy nhất để tránh điều đó hoàn toàn là chỉ phát triển phần mềm tầm thường - và thậm chí sau đó, đôi khi bạn bị ràng buộc mắc lỗi.

Điều thực tế duy nhất bạn có thể làm là tránh sự phức tạp không cần thiết - làm cho phần mềm của bạn đơn giản nhất có thể, nhưng không đơn giản hơn thế.

Về cơ bản đó là tất cả những gì các nguyên tắc và mẫu thiết kế cụ thể hơn đều hướng tới - làm cho mọi thứ đơn giản nhất có thể. Vấn đề là "đơn giản theo cách nào" có thể chủ quan - bạn có nghĩa là thiết kế đơn giản tuyệt đối cho các yêu cầu hiện tại hoặc đơn giản để sửa đổi cho các yêu cầu trong tương lai. Và cũng có những nguyên tắc cho điều đó.

Các bài kiểm tra đơn vị là một ví dụ về sự không chắc chắn này. Một mặt, chúng là sự phức tạp không cần thiết - mã phải được phát triển và duy trì, nhưng không hoàn thành công việc. Mặt khác, chúng là một cách đơn giản để tự động hóa thử nghiệm, giảm số lượng thử nghiệm thủ công khó khăn hơn nhiều phải thực hiện.

Cho dù bạn học được bao nhiêu lý thuyết thiết kế và bao nhiêu kinh nghiệm bạn có được, nguyên tắc ghi đè (và đôi khi là hướng dẫn duy nhất bạn có) là hướng tới sự đơn giản.


0

Không có gì ngẫu nhiên về lỗi phần mềm, nguyên nhân gốc là hoàn toàn xác định về bản chất, hướng dẫn không chính xác cho máy tính.

Lỗi luồng có thể không xác định trong hành vi thực thi, nhưng không phải là ngẫu nhiên trong nguyên nhân gốc.

Chúng xảy ra với cùng một lý do chính xác vào những thời điểm dường như không thể dự đoán được, nhưng điều đó không làm cho chúng ngẫu nhiên chỉ không thể dự đoán được, một khi bạn biết nguyên nhân gốc rễ bạn có thể dự đoán chắc chắn khi nào chúng sẽ xảy ra.

Tôi nói rõ ràng và phân biệt vì một lý do. Ngẫu nhiên có nghĩa là một điều, Được thực hiện, thực hiện, xảy ra hoặc được chọn mà không có phương pháp hoặc quyết định có ý thức , ngụ ý rằng có một số quyết định độc lập trên một phần của máy tính, không có gì nó đang làm chính xác những gì nó được bảo phải làm, bạn chỉ không nói với nó để làm điều đúng trong một số trường hợp rất xác định.

Các ngữ nghĩa của các từ là có lý do, ngẫu nhiên không có nghĩa là một cái gì đó khác nhau chỉ vì ai đó sử dụng nó - chính xác, nó luôn có nghĩa tương tự. Một thuật ngữ tốt hơn sẽ là lỗi vô ý hoặc không rõ ràng logic.

Xem xét các lỗi như ngẫu nhiên gần giống như chấp nhận rằng có một số lực không thể hiểu được khác trong công việc mà không được hiểu đầy đủ hành động độc lập với đầu vào của bạn vào máy tính, và điều đó không khoa học lắm. Ý tôi là các vị thần tức giận và bôi nhọ ứng dụng của bạn một cách bất chợt?


+1 cho điểm hợp lệ, nhưng -1 cho nitpicking. Vì vậy, +/- 0. Tôi nghĩ rằng hầu hết mọi người đọc câu hỏi mất "ngẫu nhiên" không theo nghĩa hoàn toàn theo nghĩa đen (chính xác những gì không "ngẫu nhiên" thực sự có ý nghĩa, đưa đến cùng cực của nó?), Mà là một cái gì đó có ý nghĩa như "tôi không hiểu làm thế nào hành vi này có thể len ​​lỏi vào hoặc tại sao phần mềm làm điều này sai ".
CVn

@Micheal - đó là lý do tại sao tôi nói rõ ràng và phân biệt. Không có cực đoan đến ngẫu nhiên nó có nghĩa là một chuyện, Made, thực hiện, xảy ra, hoặc lựa chọn mà không cần phương pháp hoặc quyết định có ý thức ngữ nghĩa của từ này là có một lý do, ngẫu nhiên không có nghĩa là một cái gì đó khác nhau chỉ vì ai đó sử dụng nó trong một cách chính xác, nó luôn có nghĩa tương tự Những gì họ có thể có nghĩa là vô ý , vì những lý do tôi nêu trong lời giải thích của tôi trong câu trả lời của tôi.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.