Bài tập boolean thực hành tốt nhất [đã đóng]


10

Tôi đã xem qua các điều kiện sau đây trong một chương trình mà tôi đã tiếp quản từ một nhà phát triển khác:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Tôi tin rằng mã này là dư thừa và xấu, vì vậy tôi đã thay đổi nó thành cái mà tôi nghĩ là một phép gán boolean đơn giản dựa trên so sánh:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

Khi thấy điều này, một người nào đó đang xem lại mã của tôi đã nhận xét rằng mặc dù thay đổi của tôi là đúng về mặt chức năng, nhưng nó có thể khiến người khác nhầm lẫn khi nhìn vào nó. Ông tin rằng việc sử dụng một toán tử ternary làm cho nhiệm vụ này rõ ràng hơn, trong khi tôi không thích việc thêm mã dự phòng:

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE) ? true : false;

Lý luận của ông là làm một việc gì đó theo cách ngắn gọn nhất là không đáng, nếu điều đó khiến một nhà phát triển khác phải dừng lại và giải đố chính xác những gì bạn đã làm.

Câu hỏi thực sự ở đây là phương pháp nào trong ba phương pháp gán giá trị này cho boolean obj.NeedsChangelà rõ ràng nhất và dễ bảo trì nhất?


25
Hình thức thứ ba là vô lý; nó chỉ nêu rõ những gì đáng lẽ phải rõ ràng ở dạng thứ hai.
Robert Harvey

6
Điều này hoàn toàn tùy thuộc vào sở thích cá nhân. Chúng ta có thể giả vờ khác, nhưng vì tất cả đều tương đương về mặt chức năng nên nó sôi sục theo phong cách . Chắc chắn, có một sự khác biệt về khả năng đọc, nhưng "dễ đọc và minh bạch" của tôi có thể là "sự khó hiểu và mờ đục" của bạn
MetaFight

3
@scriptin 5-8 dòng v 1 dòng nhiều hơn ưu tiên, lớp lót 5-8 thường rõ ràng hơn và tốt hơn cho nó. Trong ví dụ đơn giản này, tôi thích dòng 1 hơn, nhưng nói chung tôi đã thấy quá nhiều 10 lớp được xáo trộn thành 1 lớp cho thoải mái. Cho rằng, tôi không bao giờ phàn nàn về biến thể 1, nó có thể không đẹp nhưng nó thực hiện công việc một cách rõ ràng và rõ ràng.
gbjbaanb

4
Tùy chọn 1 và 3 nói với tôi "Tác giả không thực sự hiểu logic boolean".
17 trên 26

2
Biến thể 1 có thể hữu ích nếu bạn cần thường xuyên đặt điểm dừng phụ thuộc vào giá trị.
Ian

Câu trả lời:


39

Tôi thích 2, nhưng tôi có thể điều chỉnh nhỏ cho nó:

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

Đối với tôi, dấu ngoặc đơn làm cho dòng dễ phân tích hơn và làm cho nó rõ ràng rằng bạn đang gán kết quả của một so sánh, và không thực hiện một phép gán kép. Tôi không chắc tại sao lại như vậy (vì tôi không thể nghĩ ra một ngôn ngữ mà dấu ngoặc đơn thực sự ngăn cản việc gán kép), nhưng nếu bạn phải làm hài lòng người đánh giá thì có lẽ đây sẽ là một sự thỏa hiệp chấp nhận được.


4
đây là câu trả lời đúng - mặc dù mã trong câu hỏi là chính xác, việc thêm dấu ngoặc cho người đọc biết rằng nó không phải là bài tập. Nếu bạn đã nhanh chóng xem qua mã, các dấu ngoặc sẽ cung cấp cho bạn thông tin bổ sung tức thời đó ngăn bạn nhìn gần hơn để xem mã có nghĩa như thế không, và đó không phải là một lỗi vô tình. Ví dụ, hãy tưởng tượng dòng là a = b == c, bạn có nghĩa là gán một bool hoặc bạn có nghĩa là gán c cho cả b và a.
gbjbaanb

Dấu ngoặc đơn sẽ ngăn một phép gán kép trong Python. Ngay cả trong các ngôn ngữ mà chúng không ngăn chặn chuyển nhượng kép, dấu ngoặc đơn chắc chắn giúp chỉ ra rằng bạn đang xử lý hai loại hoạt động.
user2357112 hỗ trợ Monica

23

Biến thể 1 dễ hiểu, nhưng đó là lợi thế duy nhất của nó. Tôi tự động cho rằng bất cứ ai viết như thế này đều không thực sự hiểu về booleans là gì và sẽ viết mã trẻ sơ sinh tương tự ở nhiều khía cạnh khác.

Biến thể 2 là những gì tôi sẽ luôn luôn viết, và mong đợi để đọc. Tôi nghĩ rằng bất cứ ai bị nhầm lẫn bởi thành ngữ đó không nên là một nhà văn phần mềm chuyên nghiệp.

Biến thể 3 kết hợp những nhược điểm của cả 1 và 2. 'nuff nói.


Chà, biến thể 1 chia sẻ lợi thế của nó với biến thể 2 ...
Ded repeatator

1
+1 cho mã trẻ sơ sinh. Tôi đã xem mã như vậy trong nhiều năm, tôi chỉ thiếu từ đúng để xác định nó.
Lilienthal

1
Giả định đầu tiên của tôi với mã như Biến thể 1 là hai nhánh tại một thời điểm trong quá khứ phức tạp hơn và ai đó đã không chú ý khi tái cấu trúc. Tuy nhiên, nếu đó là như thế nào khi được viết lần đầu tiên, thì tôi đồng ý với "không hiểu về
booleans

13

Bất cứ lúc nào mã phức tạp hơn nó cần phải được kích hoạt một "điều này được cho là đang làm gì?" ngửi trong người đọc.

Ví dụ, ví dụ đầu tiên khiến tôi tự hỏi, "có chức năng nào khác trong câu lệnh if / other tại một thời điểm nào đó đã bị xóa không?"

Ví dụ (2) đơn giản, rõ ràng và thực hiện chính xác những gì cần thiết. Tôi đọc nó và ngay lập tức hiểu những gì mã làm.

Việc thêm lông tơ trong (3) sẽ khiến tôi tự hỏi tại sao tác giả lại viết nó theo cách đó thay vì (2). Cần phải có một lý do, nhưng trong trường hợp này dường như không có, vì vậy nó không hữu ích chút nào và khó đọc hơn vì cú pháp gợi ý một cái gì đó không có ở đó. Cố gắng học những gì hiện tại (khi không có gì) làm cho mã khó đọc hơn.


2

Dễ dàng thấy rằng Biến 2 và Biến 1 có liên quan thông qua một loạt các phép tái cấu trúc rõ ràng và đơn giản:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Ở đây, chúng ta có sự sao chép mã không cần thiết, chúng ta có thể tính ra phép gán:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE)
{
    true
}
else
{
    false
}

hoặc viết chính xác hơn:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE) true else false

Bây giờ, cần phải rõ ràng ngay lập tức rằng điều này sẽ gán đúng nếu điều kiện là đúng và gán sai nếu điều kiện là sai, IOW nó sẽ chỉ gán giá trị của điều kiện, tức là nó tương đương với

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE

Các biến số 1 và 3 là mã tân binh điển hình được viết bởi một người không hiểu giá trị trả về của phép so sánh là gì.


Tôi sẽ thêm phần if (...) ... của bạn dưới dạng một nhận xét ngay trước phần đẹp, sau đó bạn có thể quét đơn giản thông qua mã rõ ràng và mã tốt hơn.
DaveM

2

Mặc dù chương trình của bạn nên có xu hướng rõ ràng hơn là "nếu anh chàng cuối cùng duy trì mã của bạn sẽ là một kẻ tâm thần bạo lực, biết bạn sống ở đâu", bạn có thể giả định một vài điều cơ bản mà người kế thừa tâm lý của bạn sẽ thành thạo.

Một trong số đó là cú pháp của ngôn ngữ anh ta đang sử dụng.

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

là rất rõ ràng cho bất cứ ai biết cú pháp C / C ++ / C # / Java / Javascript.

Nó cũng dễ đọc hơn 8 dòng.

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

và ít mắc lỗi

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.Needschange = false;
}

Và tốt hơn là thêm các ký tự không cần thiết, như thể bạn đã quên một nửa cú pháp của ngôn ngữ:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE ? true : false;

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE);

Tôi nghĩ có nhiều sai lầm về cú pháp giống như C của nhiều ngôn ngữ: thứ tự hoạt động không nhất quán, sự kết hợp trái / phải không nhất quán, sử dụng quá mức các ký hiệu, sao chép dấu ngoặc / thụt, toán tử ternary, ký hiệu infix, v.v.

Nhưng giải pháp không phải là phát minh ra phiên bản độc quyền của riêng bạn. Đó là cách nói dối điên rồ, như mọi người tạo ra của riêng mình.


Nói chung, điều số 1 làm cho mã Real World TM không thể đọc được là số lượng của nó.

Giữa chương trình 200 dòng không bệnh lý và chương trình 1.600 dòng giống hệt nhau, chương trình ngắn hơn hầu như sẽ luôn dễ dàng phân tích và hiểu hơn. Tôi sẽ chào đón sự thay đổi của bạn bất cứ ngày nào.


1

Hầu hết các nhà phát triển sẽ có thể hiểu được hình thức thứ 2 trong nháy mắt. Theo ý kiến ​​của tôi về việc đơn giản hóa như ở dạng thứ 1 đơn giản là không cần thiết.

Bạn có thể cải thiện khả năng đọc bằng cách thêm khoảng trắng và dấu ngoặc nhọn như:

obj.NeedsChange =    obj.Performance <= LOW_PERFORMANCE;

hoặc là

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

như Jacob Raihle đã đề cập.

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.