2009-04-11 27 views
7

Brian Kernighan được hỏi câu hỏi này trong một số recent interview. Tôi sẽ trích dẫn câu trả lời của anh ấy:Ví dụ có nên - ngay cả các ví dụ mới bắt đầu - bao gồm mã xử lý lỗi?

Brian: Tôi bị rách. Mã xử lý lỗi có xu hướng cồng kềnh và rất không thú vị và không mang tính cấu trúc, vì vậy nó thường theo cách học và hiểu các cấu trúc ngôn ngữ cơ bản. Đồng thời, điều quan trọng là nhắc nhở các lập trình viên rằng các lỗi xảy ra và mã của họ phải có khả năng đối phó với các lỗi.

Sở thích cá nhân của tôi là bỏ qua khá nhiều lỗi trong các phần trước của hướng dẫn, ngoài việc đề cập đến lỗi có thể xảy ra và tương tự như bỏ qua lỗi trong hầu hết các ví dụ trong sách hướng dẫn tham khảo trừ khi điểm của một số phần là lỗi . Nhưng điều này có thể củng cố niềm tin vô thức rằng nó là an toàn để bỏ qua lỗi, mà luôn luôn là một ý tưởng tồi.

Tôi thường để lại xử lý lỗi trong các ví dụ mã tại đây và trên blog của riêng tôi và tôi đã nhận thấy rằng đây là xu hướng chung trên Stack Overflow. Chúng ta có đang củng cố thói quen xấu không? Chúng ta có nên dành nhiều thời gian hơn để đánh bóng các ví dụ với xử lý lỗi, hay nó chỉ nhận được trong cách minh họa điểm?

Trả lời

2

Không thường xuyên tôi không đồng ý với BWK, nhưng tôi nghĩ các ví dụ mới bắt đầu đặc biệt là sẽ hiển thị mã xử lý lỗi, vì đây là điều mà người mới bắt đầu gặp khó khăn. Nhiều lập trình viên có kinh nghiệm hơn có thể xử lý lỗi khi đọc.

+1

Nó phải là manditory. Xử lý lỗi là một phần cơ bản của mã. – EvilTeach

6

Bất kỳ mã ví dụ được cung cấp nào sẽ được sao chép thành mã sản xuất ít nhất một lần, vì vậy hãy cố gắng hết sức khi viết mã.

+0

Bất cứ ai thực hiện điều này chỉ có thể xứng đáng với những gì họ nhận được. :-) – tvanfosson

+0

... không phải là tôi cố ý viết crap, nhưng bạn nên hiểu bất kỳ mã nào mà bạn đang đưa vào sản xuất không chỉ sao chép/dán mã từ một số người lạ ngẫu nhiên. – tvanfosson

+0

Mã ví dụ +1 cần phải là chất lượng sản xuất. Làm thế nào người khác phải học cách pratices tốt. –

1

Xử lý lỗi là một mô hình của chính nó; nó thường không được bao gồm trong các ví dụ vì nó nghiêm trọng làm hỏng điểm mà tác giả cố gắng đi qua.

Nếu tác giả muốn truyền đạt kiến ​​thức về xử lý lỗi trong một miền hoặc ngôn ngữ cụ thể thì tôi thích người đọc có một chương khác phác thảo tất cả các mô hình chi phối về xử lý lỗi và cách điều này ảnh hưởng đến phần còn lại của chương .

+0

Đây là cảm giác của tôi, cả khi đọc và viết. Tôi cảm thấy rằng mã xử lý lỗi bị cản đường, nhưng một giọng nói nhỏ ở phía sau tâm trí của tôi tự hỏi liệu tôi có làm người đọc một sự bất bình khi không bao gồm nó. –

11

Tôi nghĩ rằng nó có thể là một sự cải tiến nếu khi đăng mã ví dụ, chúng tôi ít nhất đưa ra nhận xét trong đó nói rằng bạn nên đặt mã xử lý lỗi tại một số điểm nhất định. Điều này ít nhất có thể giúp ai đó sử dụng mã đó để nhớ rằng họ cần phải xử lý lỗi. Điều này sẽ giữ mã phụ để xử lý lỗi nhưng sẽ vẫn củng cố ý tưởng rằng cần phải có mã xử lý lỗi.

+0

nó cũng hiển thị những lỗi nào cần nắm bắt đôi khi, ví dụ mã trả về 0 thành công sẽ hiển thị "if (code()! = 0) rồi handle_error_here" – gbjbaanb

5

Ngoài câu hỏi làm lộn xộn mã khi bạn đang chứng minh một điểm mã hóa, tôi nghĩ câu hỏi sẽ trở thành, cách bạn có chọn xử lý lỗi trong mã ví dụ của mình không?

Đó là để nói, bạn sẽ làm gì? Những gì gây tử vong cho một ứng dụng là không gây tử vong cho người khác. ví dụ. nếu tôi không thể lấy một số thông tin từ máy chủ web (có thể là lỗi 404 hoặc máy chủ không đáp ứng) có thể gây tử vong nếu bạn không thể làm bất cứ điều gì nếu không có dữ liệu đó. Nhưng nếu dữ liệu đó bổ sung cho những gì bạn đang làm, thì có lẽ bạn có thể sống mà không có nó.

Vì vậy, ở trên có thể chỉ đơn giản là ghi nhật ký lỗi. Đó là tốt hơn so với bỏ qua các lỗi hoàn toàn. Nhưng tôi nghĩ thường khó khăn là trong việc biết làm thế nào/khi nào (và khi nào không) để phục hồi từ một lỗi. Có lẽ đó là một hướng dẫn hoàn toàn mới trong chính nó.

2

Tôi nghĩ giải pháp là ở đâu đó ở giữa.Nếu bạn đang định nghĩa một hàm để tìm yếu tố 'x' trong danh sách 'y', bạn làm điều gì đó như thế này:

function a(x,y) 
{ 
    assert(isvalid(x)) 
    assert(isvalid(y)) 
    logic() 
} 

Không cần phải rõ ràng về những gì làm cho một đầu vào hợp lệ, chỉ là người đọc nên biết logic giả định đầu vào hợp lệ.

+0

+1 để thỏa hiệp. Tôi thích giải pháp này để xác nhận đầu vào, nhưng tôi tự hỏi làm thế nào nó sẽ mở rộng cho một cái gì đó giống như xử lý lỗi cần thiết cho một khách hàng TCP đơn giản. –

1

Một ý tưởng tôi đã sẽ được bao gồm một dòng như sau trong mã ví dụ của bạn ở đâu đó:

DONT_FORGET_TO_ADD_ERROR_CHECKING(); // You have been warned! 

Tất cả điều này là ngăn chặn các mã biên dịch "off the bat" cho bất cứ ai chỉ cách mù quáng bản và dán nó (vì rõ ràng là DONT_FORGET_TO_ADD_ERROR_CHECKING() không được định nghĩa ở bất kỳ đâu). Nhưng nó cũng là một rắc rối, và có thể được coi là thô lỗ.

+0

Tôi thích ý tưởng chung đằng sau điều này. Tôi nghi ngờ rằng nhiều người sẽ chỉ bình luận dòng, nhưng ít nhất bạn đã buộc họ phải tạm dừng và suy nghĩ. –

+0

@Bill: Vâng, nó thực sự chỉ là một cách để giảm tải trách nhiệm đối với bất kỳ mã nào có thể gây ra;) Một chút giống như phải nhấp vào "Có, tôi đã đọc điều khoản EULA và tôi đồng ý" trước khi cài đặt. –

+0

Tôi hy vọng nó sẽ có nhiều hiệu ứng hơn là nhấp vào có cho EULA, nếu không thì hầu hết sẽ không hữu ích: p – Davy8

1

Tôi sẽ nói rằng điều đó phụ thuộc vào ngữ cảnh. Trong một mục nhập blog hoặc sách giáo khoa, tôi sẽ tập trung vào mã để thực hiện hoặc thể hiện chức năng mong muốn. Tôi có lẽ sẽ cung cấp cho các gật đầu bắt buộc để xử lý lỗi, có lẽ, thậm chí đặt trong một kiểm tra nhưng stub mã với một dấu ba chấm. Trong giảng dạy, bạn có thể giới thiệu rất nhiều sự nhầm lẫn bằng cách bao gồm quá nhiều mã không tập trung trực tiếp vào chủ đề trong tầm tay. Trong SO, đặc biệt, các câu trả lời ngắn hơn (nhưng hoàn chỉnh) dường như được ưa thích hơn để xử lý các lỗi với "một làn sóng của bàn tay" có thể phù hợp hơn trong ngữ cảnh này.

Điều đó nói rằng, nếu tôi làm mẫu mã có sẵn để tải xuống, tôi thường làm cho nó hoàn chỉnh nhất có thể và bao gồm xử lý lỗi hợp lý. Ý tưởng ở đây là để tìm hiểu người đó luôn có thể quay lại hướng dẫn/blog và sử dụng điều đó để giúp hiểu mã như được triển khai thực sự. Trong kinh nghiệm cá nhân của tôi, đây là một trong những vấn đề mà tôi có với TDD thường được trình bày như thế nào - thường bạn chỉ thấy các bài kiểm tra được phát triển để kiểm tra xem mã có thành công trong đường dẫn chính thực hiện hay không. Tôi muốn xem thêm hướng dẫn TDD bao gồm phát triển các bài kiểm tra cho các đường dẫn thay thế (lỗi). Khía cạnh này của thử nghiệm, tôi nghĩ, là khó khăn nhất để có được một xử lý trên vì nó đòi hỏi bạn phải suy nghĩ, không phải những gì sẽ xảy ra, nhưng của tất cả những điều có thể đi sai.

1

Một cách tiếp cận mà tôi đã thấy, đặc biệt là trong Advanced Programming in the UNIX EnvironmentUNIX Network Programming là để bao bọc các cuộc gọi với mã kiểm tra lỗi và sau đó sử dụng trình bao bọc trong mã ví dụ. Ví dụ:

ssiz_t Recv(...) 
{ 
    ssize_t result; 
    result = recv(...); 
    /* error checking in full */ 
} 

sau đó, trong mã gọi:

Recv(...); 

Bằng cách đó bạn có thể hiển thị xử lý lỗi trong khi cho phép dòng chảy của gọi mã để được rõ ràng và súc tích.

+0

Lúc đầu, tôi đã bực mình bởi tất cả những thư viện không bao gồm và các cuộc gọi hàm trong UNP , nhưng chúng phục vụ một mục đích có giá trị. :) –

+0

... erm. đây không phải là xử lý lỗi thích hợp, nó không thể phản ứng đầy đủ với các điều kiện đặc biệt. tất cả những gì nó có thể làm là đăng nhập và hủy bỏ ... –

+0

"Đúng" phụ thuộc quá nhiều vào ngữ cảnh cho bất kỳ chương trình như vậy để làm việc. Đủ rồi. Tuy nhiên, nó hoàn toàn thích hợp cho mã ví dụ như được tìm thấy trong APUE và UNP. Đầu tiên, nó cho thấy cách kiểm tra và phản ứng với trạng thái trả về. Thứ hai, nó cho thấy dòng chảy của mã ví dụ mà không có số lượng lớn kiểm tra lỗi. – dwc

4

Ví dụ phải minh họa. Họ nên luôn luôn cho thấy điểm được thực hiện rõ ràng với sự phân tâm ít nhất có thể. Dưới đây là một ví dụ meta:

Giả sử chúng tôi muốn đọc một số từ tệp, thêm 3 và in số đó vào bảng điều khiển. Chúng ta sẽ cần chứng minh một vài điều.

infile = file("example.txt") 
content = infile.read() 
infile.close() 
num = int(content) 
print (3 + num) 

dài dòng, nhưng chính xác, ngoại trừ một số điều có thể xảy ra sai. Đầu tiên, nếu tệp không tồn tại thì sao? Điều gì xảy ra nếu nó tồn tại nhưng không chứa một số?

Vì vậy, chúng tôi cho biết cách xử lý lỗi.

try: 
    infile = file("example.txt") 
    content = infile.read() 
    infile.close() 
    num = int(content) 
    print (3 + num) 
except ValueError: 
    print "Oops, the file didn't have a number." 
except IOError: 
    print "Oops, couldn't open the file for some reason." 

Sau một vài lần lặp lại hiển thị cách xử lý lỗi do, trong trường hợp này, xử lý và phân tích tệp. Tất nhiên, chúng tôi muốn thể hiện một cách sâu sắc hơn để thể hiện mệnh đề try. Bây giờ chúng tôi thả lỗi xử lý, nguyên nhân đó không phải là những gì chúng tôi đang trình diễn.

Lần đầu tiên loại bỏ các biến phụ không cần thiết.

infile = file("example.txt") 
print (3 + int(infile.read())) 
infile.close() 

Vì chúng tôi không viết thư cho nó, cũng không phải là tài nguyên đắt tiền trong một quy trình chạy lâu, thật sự an toàn để mở nó. Nó sẽ đóng khi chương trình kết thúc.

print (3 + int(file("example.txt").read())) 

Tuy nhiên, một số có thể cho rằng đó là thói quen xấu và có cách tốt hơn để xử lý vấn đề đó. Chúng ta có thể sử dụng một ngữ cảnh để làm cho nó rõ ràng hơn một chút. tất nhiên chúng tôi sẽ giải thích rằng một tập tin sẽ tự động đóng vào cuối của một khối.

with file("example.txt") as infile: 
    print (3 + int(infile.read())) 

Và bây giờ, chúng tôi đã trình bày mọi thứ chúng tôi muốn, chúng tôi hiển thị ví dụ hoàn chỉnh ở phần cuối của phần. Ngoài ra, chúng tôi sẽ thêm một số tài liệu.

Đây thực sự là cách tôi thường thấy hướng dẫn được thể hiện và hoạt động rất tốt. Tôi thường cảm thấy thất vọng khi thiếu một phần nào đó.

+2

Đây là những gì tôi muốn thấy trong sách, nơi tác giả có thể dành một chương, hoặc ít nhất một vài trang, đánh bóng một ví dụ. –

0

Không, trừ khi mục đích của ví dụ này là để chứng minh một khía cạnh xử lý ngoại lệ. Đây là một peeve thú cưng của tôi - nhiều ví dụ cố gắng để chứng minh thực hành tốt nhất và kết thúc lên che khuất và làm phức tạp ví dụ. Tôi thấy điều này tất cả các thời gian trong các ví dụ mã bắt đầu bằng cách định nghĩa một loạt các giao diện và các chuỗi kế thừa không cần thiết cho ví dụ. Một ví dụ điển hình về quá phức tạp là một phòng thí nghiệm thực hành tôi đã làm ở TechEd năm ngoái. Phòng thí nghiệm nằm trên Linq, nhưng mã mẫu mà tôi đã hướng dẫn để viết đã tạo ra một ứng dụng nhiều tầng không có mục đích gì.

Ví dụ nên bắt đầu bằng mã đơn giản nhất có thể thể hiện điểm, sau đó tiến vào sử dụng thực tế và thực tiễn tốt nhất.

Là một sang một bên, khi tôi đã yêu cầu mẫu mã từ các ứng viên hầu hết trong số đó là cẩn thận để chứng minh kiến ​​thức về xử lý ngoại lệ:

public void DoSomethingCool() 
{ 
    try 
    { 
     // do something cool 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
} 

Tôi đã nhận được hàng trăm dòng mã với mọi phương pháp như thế này. Tôi đã bắt đầu thưởng điểm thưởng cho những người sử dụng ném; thay vì ném cũ;

1

Tôi không nghĩ rằng việc xử lý lỗi phải nằm trong ví dụ nếu nó che khuất logic. Nhưng một số lỗi xử lý chỉ là thành ngữ của việc làm một số điều, và trong trường hợp này bao gồm nó.

Ngoài ra, nếu chỉ ra rằng việc xử lý lỗi cần được thêm vào. Đối với tình yêu của vị thần cũng chỉ ra lỗi nào cần được xử lý.

Đây là phần khó chịu nhất khi đọc một số ví dụ. Nếu bạn không biết những gì bạn đang làm (mà chúng ta phải giả định của người đọc ví dụ ...) bạn không biết phải tìm lỗi nào. Mà biến "thêm lỗi xử lý" gợi ý vào "ví dụ này là vô dụng".

0

Mã mẫu không cần bao gồm xử lý lỗi nhưng nếu không nó sẽ chứng minh các kỹ thuật mã hóa an toàn thích hợp. Nhiều đoạn mã web vi phạm số OWASP Hàng đầu.