2010-04-10 10 views
5

Tôi nhớ nhiều năm trước, khi tôi còn đi học, một trong những giáo viên khoa học máy tính của tôi dạy chúng tôi nên kiểm tra 'tính đúng đắn' hoặc 'bình đẳng' của một điều kiện chứ không phải những thứ tiêu cực như 'bất bình đẳng'.Thực hành kiểm tra 'tính đúng đắn' hoặc 'bình đẳng' trong các câu lệnh có điều kiện - có thực sự hợp lý không?

Hãy để tôi giải thích - Nếu một đoạn mã có điều kiện có thể được viết bằng cách kiểm tra xem biểu thức là đúng hay sai, chúng ta nên kiểm tra 'độ đúng'.

Ví dụ: Tìm hiểu xem một số là số lẻ - nó có thể được thực hiện theo hai cách:

if (num % 2 != 0) 
{ 
    // Number is odd 
} 

hoặc

if (num % 2 == 1) 
{ 
    // Number is odd 
} 

(Vui lòng tham khảo câu trả lời rõ rệt cho một ví dụ tốt hơn.)

Khi tôi bắt đầu viết mã, tôi biết rằng num % 2 == 0 ngụ ý số này là ngay cả, vì vậy tôi chỉ cần đặt một ! ở đó để kiểm tra xem nó là lẻ. Nhưng anh ta giống như 'Đừng kiểm tra điều kiện KHÔNG. Thực hành kiểm tra 'tính đúng đắn' hoặc 'bình đẳng' của các điều kiện bất cứ khi nào có thể '. Và anh ấy khuyên tôi nên sử dụng đoạn mã thứ hai.

Tôi không ủng hộ hoặc chống lại một trong hai nhưng tôi chỉ muốn biết - sự khác biệt của nó là gì? Xin đừng trả lời 'Về mặt kỹ thuật đầu ra sẽ giống nhau' - chúng ta TẤT CẢ biết điều đó. Nó là một thực hành lập trình chung hay là thực hành lập trình của riêng mình rằng ông đang rao giảng cho người khác?

LƯU Ý: Tôi đã sử dụng cú pháp kiểu C#/C++ không có lý do gì. Câu hỏi của tôi là áp dụng như nhau khi sử dụng các toán tử IsNot, <> trong VB, v.v. Vì vậy, khả năng đọc của '!' nhà điều hành chỉ là một trong những vấn đề. Không phải vấn đề.

+0

Có thể là câu hỏi wiki? – slugster

Trả lời

6

Vấn đề xảy ra khi, sau này trong dự án, thêm nhiều điều với JSTL ...) - một âm không khó đọc, nhưng 5+ là một cơn ác mộng, đặc biệt khi ai đó quyết định tổ chức lại và phủ nhận toàn bộ điều. Có lẽ trong một dự án mới, bạn sẽ viết:

if (authorityLvl!=Admin){ 
doA(); 
}else{ 
doB(); 
} 

Kiểm tra lại trong một tháng, và nó trở thành này:

if (!(authorityLvl!=Admin && authorityLvl!=Manager)){ 
doB(); 
}else{ 
doA(); 
} 

Tuy khá đơn giản, nhưng phải mất một giây.
Bây giờ, hãy dùng thêm 5 đến 10 năm nữa để thối.
(x% 2! = 0) chắc chắn không phải là vấn đề, nhưng có lẽ cách tốt nhất để tránh kịch bản trên là dạy học sinh không sử dụng điều kiện tiêu cực như quy tắc chung, với hy vọng rằng họ sẽ sử dụng phán xét trước khi họ làm - bởi vì chỉ nói rằng nó có thể trở thành vấn đề bảo trì có lẽ sẽ không đủ động lực.

Là một phụ lục, một cách tốt hơn để viết mã sẽ là:

userHasAuthority = (authorityLvl==Admin); 
if (userHasAuthority){ 
doB(); 
else{ 
doA(); 
} 

Bây giờ lập trình tương lai có nhiều khả năng chỉ cần thêm "|| authorityLvl == Manager", userHasAuthority là dễ dàng hơn để di chuyển vào một và thậm chí nếu điều kiện được tổ chức lại, nó sẽ chỉ có một âm. Hơn nữa, không ai thêm lỗ hổng bảo mật vào ứng dụng bằng cách áp dụng sai lầm khi áp dụng Luật của De Morgan.

+0

giống như tia chớp từ bầu trời trong xanh - giải thích rõ ràng - đặc biệt là đoạn mã thứ hai. Lý do tốt nhất tôi đã đọc. (+1 khi tôi có đủ đại diện: D) – Senthil

0

Tôi nhớ cũng đã nghe điều tương tự trong lớp học của mình. Tôi nghĩ điều quan trọng hơn là luôn sử dụng sự so sánh trực quan hơn, thay vì luôn kiểm tra tình trạng tích cực.

0

Thực sự là một vấn đề rất có hậu quả. Tuy nhiên, một điều tiêu cực để kiểm tra theo nghĩa này là nó chỉ hoạt động đối với các so sánh nhị phân. Ví dụ, nếu bạn kiểm tra một số thuộc tính của hệ thống số ba bậc bạn sẽ bị giới hạn.

1

Tôi đã cho mọi người biết rằng nó liên quan đến cách hiển thị ký tự ping (!) Khi đọc lướt qua.

Nếu ai đó thường xuyên "đọc lướt" mã - có lẽ vì họ cảm thấy tốc độ đọc thường xuyên của họ quá chậm - thì có thể dễ dàng bỏ lỡ !, khiến họ hiểu sai mã.

Mặt khác, nếu một người nào đó thực sự đọc tất cả mã mọi lúc, thì không có vấn đề gì.

Hai nhà phát triển rất giỏi mà tôi đã từng làm việc (và tôn trọng cao) mỗi người sẽ viết == false thay vì sử dụng ! vì những lý do tương tự.

Yếu tố then chốt trong đầu tôi ít liên quan đến những gì phù hợp với bạn (hoặc tôi!) Và hơn thế nữa với những gì hiệu quả đối với người duy trì mã. Nếu mã không bao giờ được nhìn thấy hoặc được duy trì bởi bất kỳ ai khác, hãy làm theo ý thích cá nhân của bạn; nếu mã cần được duy trì bởi những người khác, tốt hơn là nên lái nhiều hơn về phía giữa đường. Một trẻ vị thành niên (tầm thường!) thỏa hiệp về phía bạn ngay bây giờ, có thể tiết kiệm cho người khác một tuần gỡ lỗi sau này.

Cập nhật: On xem xét thêm, tôi sẽ đề nghị thanh toán ra điều kiện như một chức năng ngữ riêng biệt sẽ cung cấp cho vẫn bảo trì hơn:

if (isOdd(num)) 
{ 
    // Number is odd 
} 
+0

Xin chào! Tôi đã bỏ lỡ một vài '!' Bản thân mình khi đọc mã của người khác. Đặc biệt nếu mã giống như 'if (! (Some-condition))'. Nó không xảy ra với tôi! : D – Senthil

+0

Giới thiệu về bản cập nhật của bạn - Tôi không biết chính xác vị từ có nghĩa là gì, nhưng tôi đoán hàm isOdd() sẽ chứa điều kiện, phải không? – Senthil

+0

+1 Đối với chức năng biến vị ngữ ... Tôi làm điều đó liên tục và cải thiện đáng kể khả năng đọc. – helpermethod

2

tôi sẽ không đồng ý với giáo sư cũ của bạn - kiểm tra cho một KHÔNG điều kiện là miễn là bạn đang kiểm tra cho một điều kiện cụ thể không. Nó thực sự đáp ứng tiêu chí của anh ta: bạn sẽ kiểm tra rằng nó là TRUE rằng một giá trị KHÔNG phải là cái gì đó.

Tôi băn khoăn ý của mình là gì - hầu hết các điều kiện thực tế sẽ là đơn đặt hàng có độ lớn nhỏ hơn số lượng điều kiện NOT, do đó dễ kiểm tra hơn khi bạn kiểm tra một nhóm giá trị nhỏ hơn.

+0

Chúng tôi sẽ luôn kiểm tra thứ gì đó là TRUE cuối cùng vì chỉ sau đó mệnh đề 'thực sự' sẽ được thực hiện: D Đó không phải ý của tôi và đó không phải là tiêu chí của anh ta. WOW điều này đang trở nên khó hiểu! – Senthil

1

Bạn vẫn phải cẩn thận về những điều như thế này:

if (num % 2 == 1) 
{ 
    // Number is odd 
} 

Nếu num là tiêu cực và lẻ sau đó tùy thuộc vào ngôn ngữ hoặc thực hiện num% 2 có thể bằng -1. Trên lưu ý đó, không có gì sai khi kiểm tra sự sai lệch nếu nó đơn giản hóa ít nhất cú pháp của séc. Ngoài ra, sử dụng! = Là rõ ràng hơn với tôi hơn chỉ! -Đối với toàn bộ điều như! có thể hòa trộn với dấu ngoặc đơn.

Để chỉ kiểm tra trueness bạn sẽ phải làm:

if (num % 2 == 1 || num % 2 == -1) 
{ 
    // Number is odd 
} 

Đó chỉ là một ví dụ rõ ràng. Vấn đề là nếu sử dụng một phủ định cho phép kiểm tra ít hơn hoặc làm cho cú pháp của các kiểm tra rõ ràng thì đó rõ ràng là con đường để đi (như với ví dụ trên). Khóa mình vào kiểm tra tính đúng đắn không đột nhiên làm cho điều kiện của bạn dễ đọc hơn.

+0

@Evan: Điều số lẻ chỉ là ví dụ đầu tiên xuất hiện trong đầu tôi. Tôi không nghĩ qua tất cả các trường hợp có thể xảy ra. Nhưng tôi hy vọng độc giả hiểu những gì tôi đang cố gắng nói trong câu hỏi. – Senthil

+0

Tôi hiểu. Tôi chỉ nói rằng trong trường hợp như kiểm tra này cho trường hợp sai liên quan đến 1 kiểm tra trong khi kiểm tra cho sự thật có thể liên quan đến 2 kiểm tra. Việc kiểm tra trường hợp giả có vẻ thích hợp hơn. –

0

Trả lời Bevan (không phù hợp với nhận xét):

Bạn nói đúng. !foo không phải lúc nào cũng giống như foo == false. Hãy xem ví dụ này, trong JavaScript:

var foo = true, 
    bar = false, 
    baz = null; 

foo == false; // false 
!foo;   // false 
bar == false; // true 
!bar;   // true 
baz == false; // false (!) 
!baz;   // true 
0

Tôi cũng không đồng ý với giáo viên của bạn trong trường hợp cụ thể này. Có lẽ anh ta rất gắn bó với bài học nói chung tốt để tránh tiêu cực, nơi một người tích cực sẽ làm tốt, rằng anh ta không thấy cây này cho khu rừng.

Đây là vấn đề. Hôm nay, bạn lắng nghe anh ta và chuyển mã của bạn thành:

// Print black stripe on odd numbers 
int zebra(int num) { 
    if (num % 2 == 1) { 
    // Number is odd 
    printf("*****\n"); 
    } 
} 

Tháng tiếp theo, bạn hãy xem lại và quyết định không thích ma thuật hằng số (có thể anh ấy cũng dạy bạn điều này không thích). Vì vậy, bạn thay đổi mã của mình:

#define ZEBRA_PITCH 2 
[snip pages and pages, these might even be in separate files - .h and .c] 
// Print black stripe on non-multiples of ZEBRA_PITCH 
int zebra(int num) { 
    if (num % ZEBRA_PITCH == 1) { 
    // Number is not a multiple of ZEBRA_PITCH 
    printf("*****\n"); 
    } 
} 

và thế giới có vẻ ổn. Đầu ra của bạn đã không thay đổi, và bài kiểm tra hồi quy của bạn đã qua.

Nhưng bạn chưa hoàn tất. Bạn muốn hỗ trợ ngựa vằn đột biến, có sọc đen dày hơn sọc trắng của chúng. Bạn nhớ từ tháng trở lại rằng bạn ban đầu mã hóa nó như vậy mà mã của bạn in một sọc đen bất cứ nơi nào một dải màu trắng không nên được - trên số thậm chí không. Vì vậy, tất cả những gì bạn phải làm là chia cho, giả sử, 3, thay vì 2, và bạn nên làm. Đúng? Vâng:

#define DEFAULT_ZEBRA_PITCH 2 
[snip pages and pages, these might even be in separate files - .h and .c] 
// Print black stripe on non-multiples of pitch 
int zebra(int num, int pitch) { 
    if (num % pitch == 1) { 
    // Number is odd 
    printf("*****\n"); 
    } 
} 

Hey, đây là gì? Hiện tại, bạn có số lượng lớn nhất là trắng ngựa vằn nơi bạn dự kiến ​​chúng chủ yếu là màu đen!

Vấn đề ở đây là cách suy nghĩ về các con số. Là một số "lẻ" bởi vì nó không phải là ngay cả, hoặc bởi vì khi chia cho 2, phần còn lại là 1? Đôi khi miền vấn đề của bạn sẽ gợi ý tùy chọn cho một tên miền và trong những trường hợp đó, tôi khuyên bạn nên viết mã của mình để diễn tả thành ngữ đó, thay vì sửa lỗi trên các quy tắc đơn giản như "không kiểm tra từ chối".