Là nguyên tắc kiểu mã hóa - ví dụ: nguyên tắc thoát đơn
Những người vẫn quan tâm đến việc một lối thoát đơn hay nhiều lối thoát vẫn bị mắc kẹt vào cuối những năm 1960. Trước đó, một cuộc thảo luận như vậy rất quan trọng vì chúng ta còn ở giai đoạn sơ khai của lập trình viên có cấu trúc, và có khá nhiều trại tuyên bố rằng những phát hiện đằng sau Chương trình cấu trúc Bohm-Jacopini Định lý không thể áp dụng cho tất cả các cấu trúc lập trình.
Đó là một cái gì đó nên được giải quyết từ lâu. Vâng, nó đã được giải quyết (gần 4 thập kỷ là chính xác, trong cả Học viện và ngành công nghiệp), nhưng mọi người (những người hoàn toàn ủng hộ hoặc chống lại) đã không được chú ý.
Đối với phần còn lại của câu trả lời của tôi, tất cả đều tương đối (những gì không có trong phần mềm?):
Vâng. Hầu hết thời gian cho trường hợp chung, với sự cẩn thận cụ thể cho các trường hợp cạnh và cấu trúc lập trình ngôn ngữ cụ thể.
Luôn luôn, hoặc chỉ đôi khi?
Hầu hết thời gian.
Nó thực sự tạo ra bao nhiêu sự khác biệt?
Phụ thuộc.
Mã có thể đọc và mã không thể đọc được. Độ phức tạp tăng (mà chúng ta nên biết bây giờ làm tăng xác suất đưa ra lỗi) so với độ phức tạp đơn giản hơn (và ergo, xác suất lỗi nhỏ hơn.) Các ngôn ngữ có trình biên dịch không thêm trả về ngầm định (giả sử Pascal, Java hoặc C #) và các ngôn ngữ đó mặc định là int (C và C ++).
Cuối cùng, đó là một kỹ năng được mài giũa với người đàn ông / giờ đằng sau bàn phím. Đôi khi, có thể có nhiều câu lệnh trả về, như ở đây (trong một số mã giả Pascal):
function foo() : someType
begin
if( test1 == true )
then
return x;
end
doSomethignElseThatShouldnHappenIfTest1IsTrue();
return somethingElse();
end;
Mục đích rất rõ ràng và thuật toán đủ nhỏ và không phức tạp đến mức nó không đảm bảo việc tạo ra một biến 'cờ' giữ giá trị trả về cuối cùng được sử dụng trong một điểm trả về duy nhất. Thuật toán có thể bị lỗi, nhưng cấu trúc của nó đủ đơn giản để nỗ lực phát hiện lỗi là (không có khả năng) là không đáng kể.
Đôi khi không phải (ở đây sử dụng mã giả giống như C):
switch(someVal)
{
case v1 : return x1;
case v2 : return x2:
case v3 : doSomething(); // fall-through
case v4: // fall-through
case v5: // fall-through
case v6: return someXthingie;
...
...
default:
doSomething(); // no return statement yet
}
Ở đây, thuật toán không có cấu trúc đơn giản và câu lệnh chuyển đổi (kiểu C) cho phép các bước rơi qua mà có thể hoặc không được thực hiện một cách có chủ ý như một phần của thuật toán.
Có thể thuật toán là chính xác, nhưng viết kém.
Hoặc có thể, bởi các lực lượng bên ngoài vượt quá khả năng của lập trình viên, đây là đại diện thực tế (và chính xác) của một thuật toán cần thiết hợp pháp.
Có lẽ nó sai.
Để khám phá sự thật của bất kỳ điều này đòi hỏi nỗ lực hơn nhiều so với ví dụ trước. Và đây là điều tôi tin tưởng mạnh mẽ (nhớ rằng tôi không có nghiên cứu chính thức nào để sao lưu điều này):
Giả sử một đoạn mã được coi là chính xác:
Nhiều câu lệnh trả về làm tăng tính dễ đọc và đơn giản của đoạn mã như vậy, nếu đoạn mã biểu thị một thuật toán đơn giản với cấu trúc luồng đơn giản vốn có. Nói một cách đơn giản, tôi không có nghĩa là nhỏ bé, nhưng ý tôi là vốn có thể hiểu được hoặc tự chứng minh , điều đó không đòi hỏi nỗ lực đọc không tương xứng (cũng không khiến mọi người nôn mửa, nguyền rủa mẹ ai đó hoặc nuốt một viên đạn khi họ phải đọc nó. )
Một câu lệnh trả về duy nhất làm tăng tính dễ đọc và đơn giản của một đoạn mã như vậy nếu giá trị trả về được tính trong suốt quá trình thực thi thuật toán hoặc nếu các bước trong thuật toán chịu trách nhiệm tính toán nó có thể được nhóm lại với nhau tại một vị trí trong cấu trúc của thuật toán .
Một câu lệnh trả về duy nhất làm giảm tính dễ đọc và đơn giản của một đoạn mã như vậy nếu nó yêu cầu các phép gán cho một hoặc nhiều biến cờ, với các vị trí của các phép gán đó không được định vị thống nhất trong suốt thuật toán.
Nhiều câu lệnh trả về làm giảm tính dễ đọc và đơn giản của một đoạn mã như vậy nếu các câu lệnh trả lại không được phân phối đồng đều trên thuật toán và nếu chúng phân định các khối mã loại trừ lẫn nhau không đồng nhất về kích thước hoặc cấu trúc.
Điều này liên quan chặt chẽ đến sự phức tạp của một đoạn mã được đề cập. Và điều này đến lượt nó có liên quan đến các biện pháp phức tạp chu kỳ và halstead. Từ điều này, người ta có thể quan sát như sau:
Kích thước của chương trình con hoặc hàm càng lớn, cấu trúc luồng điều khiển bên trong của nó càng lớn và phức tạp hơn, và xác suất bạn sẽ phải đối mặt với một câu hỏi về việc nên sử dụng nhiều câu lệnh trả lại hay đơn.
Kết luận của việc này là: giữ cho các chức năng của bạn nhỏ làm một việc và chỉ một việc (và thực hiện tốt). Nếu chúng thể hiện các số liệu độ phức tạp nhỏ và chu kỳ trên danh nghĩa, không chỉ chúng bị ràng buộc là chính xác nhất và được thực hiện các nhiệm vụ có thể hiểu được, cấu trúc bên trong của chúng cũng sẽ tương đối rõ ràng.
Sau đó, và chỉ sau đó bạn có thể khá dễ dàng và không mất nhiều giấc ngủ, bạn có thể quyết định có nên sử dụng một lần trả lại và nhiều lần trả lại mà không gặp nhiều rủi ro khi đưa ra các lỗi với một trong hai lựa chọn hay không.
Người ta cũng có thể xem xét tất cả những điều này và đề nghị rằng khi mọi người đấu tranh với vấn đề trả lại một lần hoặc nhiều lần trả lại, đó là bởi vì - do thiếu kinh nghiệm, ngu ngốc hoặc thiếu đạo đức công việc - họ không viết mã sạch và có xu hướng viết chức năng quái dị với sự coi thường hoàn toàn các biện pháp chu kỳ và halstead.