Điều gì định nghĩa mã mạnh mẽ?


42

Giáo sư của tôi tiếp tục đề cập đến ví dụ Java này khi ông nói về mã "mạnh mẽ":

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Ông tuyên bố rằng "mã mạnh" có nghĩa là chương trình của bạn tính đến tất cả các khả năng và không có lỗi nào xảy ra - tất cả các tình huống đều được xử lý bởi mã và dẫn đến trạng thái hợp lệ, do đó là "khác".

Tôi nghi ngờ, tuy nhiên. Nếu biến là một boolean, điểm kiểm tra trạng thái thứ ba là gì khi trạng thái thứ ba là không thể?

"Không có gì gọi là lỗi" cũng có vẻ vô lý; thậm chí các ứng dụng của Google hiển thị lỗi trực tiếp cho người dùng thay vì nuốt chúng một cách im lặng hoặc bằng cách nào đó coi chúng là trạng thái hợp lệ. Và nó tốt - tôi thích biết khi có sự cố. Và có vẻ như tuyên bố rằng một ứng dụng sẽ không bao giờ có bất kỳ lỗi nào.

Vậy định nghĩa thực sự của "mã mạnh" là gì?



4
Điều này sẽ chỉ giữ trong một ngôn ngữ không gõ mạnh. Trong một ngôn ngữ được gõ mạnh, một biến kiểu boolean (không phải là một số nguyên đặt ra là boolean), chỉ có thể đúng hoặc sai, không có tùy chọn thứ ba ...
Marjan Venema

23
hãy hỏi anh ấy làm thế nào bạn sẽ kiểm tra phạm vi bảo hiểm trong trường hợp thứ 3, bởi vì mã mạnh mẽ chắc chắn sẽ yêu cầu kiểm tra và nếu bạn không quản lý để kiểm tra trường hợp thứ 3, bạn sẽ không thể tìm thấy bất kỳ lỗi nào có thể ẩn trong đó.
gbjbaanb

2
@Marjan - trong một ngôn ngữ không được gõ mạnh, người ta rất có thể chỉ cần viết: if (var) {} other {}
kevin cline

2
Tôi không biết bất kỳ ngôn ngữ nào mà cả x và! X đều có thể đúng. Lưu ý rằng tôi đã không đề xuất "if (x == true) ..."; Tôi ghê tởm những so sánh như vậy.
kevin cline

Câu trả lời:


33

điểm kiểm tra trạng thái thứ ba là gì khi trạng thái thứ ba là không thể logic?

Điều gì về một trạng thái Boolean?cho phép một NULLtrạng thái không đúng cũng không sai. Bây giờ phần mềm nên làm gì? Một số phần mềm phải có khả năng chống sự cố cao như máy tạo nhịp tim. Bạn đã bao giờ thấy ai đó thêm một cột vào cơ sở dữ liệu là một Booleanvà khởi tạo dữ liệu hiện tại NULLban đầu chưa? Tôi biết tôi đã nhìn thấy nó.

Dưới đây là một vài liên kết thảo luận về ý nghĩa của việc mạnh mẽ về phần mềm:

Nếu bạn nghĩ rằng có một định nghĩa phổ biến về "mạnh mẽ" ở đây, thì chúc may mắn. Có thể có một số từ đồng nghĩa như chống bom hoặc chống ngốc. Lập trình viên băng keo sẽ là một ví dụ về một người thường viết mã mạnh ít nhất là theo cách hiểu của tôi về các thuật ngữ.


13
Nếu đây là một boolean nullable cả Java và c # sẽ ném vì vậy null nên được kiểm tra trước.
Esben Skov Pedersen

Dường như không có bất kỳ định nghĩa nào được thống nhất trên toàn cầu về con mèo hay con chó là gì.
Tulains Córdova

11

Vì lợi ích của cuộc thảo luận của tôi, Bool có thể có 2 trạng thái, Đúng hoặc Sai. Bất cứ điều gì khác là không phù hợp với đặc điểm kỹ thuật langugae lập trình. Nếu chuỗi công cụ của bạn không phù hợp với đặc điểm kỹ thuật của nó, bạn sẽ không có vấn đề gì. Nếu một nhà phát triển tạo ra một loại Bool có nhiều hơn 2 trạng thái, thì đó là điều cuối cùng anh ta sẽ làm trên cơ sở mã của tôi.

Lựa chọn A.

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Lựa chọn B

if (var == true) {
    ...
} else {
    ...
}

Tôi khẳng định lựa chọn B mạnh mẽ hơn .....

Bất kỳ twit có thể nói với bạn để xử lý các lỗi không mong muốn. Chúng thường dễ dàng phát hiện một khi bạn nghĩ về chúng. Ví dụ mà giáo sư của bạn đưa ra không phải là điều có thể xảy ra, vì vậy đó là một ví dụ rất kém.

A là không thể kiểm tra mà không có khai thác thử nghiệm phức tạp. Nếu bạn không thể tạo ra nó, bạn sẽ thử nó như thế nào? Nếu bạn chưa kiểm tra mã, làm sao bạn biết nó hoạt động? Nếu bạn không biết nó hoạt động, thì bạn không viết phần mềm mạnh mẽ. Tôi nghĩ họ vẫn gọi đó là Catch22 (Phim hay, thỉnh thoảng xem nó).

Tùy chọn B là tầm thường để kiểm tra.

Vấn đề tiếp theo, hãy hỏi giáo sư câu hỏi này "Bạn muốn tôi làm gì với nó nếu Boolean không đúng cũng không sai?" Điều đó sẽ dẫn đến một cuộc thảo luận rất thú vị .....

Hầu hết các trường hợp, một bãi chứa cốt lõi là khủng bố, tệ nhất là nó gây khó chịu cho người dùng hoặc tốn rất nhiều tiền. Điều gì sẽ xảy ra nếu, nói, mô-đun là hệ thống tính toán reentry thời gian thực của tàu con thoi? Bất kỳ câu trả lời nào, cho dù không chính xác đến đâu, không thể tệ hơn việc phá thai, điều này sẽ giết chết người dùng. Vì vậy, phải làm gì, nếu bạn biết câu trả lời có thể sai, hãy chọn 50/50 hoặc hủy bỏ và đi đến thất bại 100%. Nếu tôi là thành viên phi hành đoàn, tôi sẽ lấy 50/50.

Lựa chọn A giết chết tôi Lựa chọn B cho tôi cơ hội sống sót.

Nhưng chờ đã - đó là một mô phỏng của cuộc tái ngộ tàu con thoi - thì sao? Hủy bỏ để bạn biết về nó. Có vẻ đó là một ý hay? - KHÔNG - bởi vì bạn cần kiểm tra với mã bạn định gửi.

Tùy chọn A tốt hơn cho mô phỏng, nhưng không thể triển khai. Tùy chọn B vô dụng là mã được triển khai để mô phỏng thực hiện giống như các hệ thống trực tiếp.

Hãy nói rằng đây là một mối quan tâm hợp lệ. Giải pháp tốt hơn là tách biệt xử lý lỗi khỏi logic ứng dụng.

if (var != true || var != false) {
    errorReport("Hell just froze over, var must be true or false")
}
......
if (var == true){
 .... 
} else {
 .... 
}

Đọc xa hơn - Máy Therac-25 Xray, Ariane 5 Rocket thất bại và các thứ khác (Liên kết có nhiều liên kết bị hỏng nhưng đủ thông tin mà Google sẽ giúp)


1
".. những lỗi bất ngờ. Chúng thường rất dễ phát hiện một khi bạn nghĩ về chúng" - nhưng khi bạn nghĩ về chúng, chúng không còn bất ngờ nữa.
gbjbaanb

7
một số câu hỏi như nếu mã của bạn if (var != true || var != false) {nên là một &&thay thế.

1
Tôi có thể dễ dàng nghĩ về một bool không đúng hoặc sai, nhưng nó vẫn bất ngờ. Trong trường hợp bạn nói bool không thể là bất cứ điều gì khác, nếu tôi kiểm tra xem một chữ cái có phải là ký tự chữ số không và sau đó chuyển đổi nó thành giá trị nguyên của nó, tôi có thể dễ dàng nghĩ rằng giá trị nguyên đó nhỏ hơn 0 hoặc lớn hơn 9, nhưng nó vẫn bất ngờ.
gnasher729

1
Null Booleans được hỗ trợ trong Java và C # và có ứng dụng trong thế giới thực. Hãy xem xét một cơ sở dữ liệu chứa một danh sách những người. Sau một thời gian, bạn quyết định bạn cần một trường giới tính (isMale). Null có nghĩa là "không bao giờ được hỏi nên không biết"; đúng có nghĩa là nam và sai có nghĩa là nữ. (OK, chuyển đổi giới tính bị bỏ qua vì đơn giản ...).
kiwiron

@kiwiron: Sẽ là một giải pháp tốt hơn không nên sử dụng loại liệt kê, "Nam", "Nữ", "Không hỏi". Việc liệt kê là tốt hơn - có thể được gia hạn khi có nhu cầu (ví dụ như Asexual, Hermaphrodite, "Từ chối trả lời" của bạn xuất hiện trong tâm trí).
mattnz 17/05/2015

9

Trên thực tế mã của bạn không mạnh mẽ hơn nhưng ÍT HƠN. Cuối cùng elsechỉ đơn giản là mã chết mà bạn không thể kiểm tra.

Trong các phần mềm quan trọng như trong tàu vũ trụ, mã chết và mã thông thường chưa được kiểm tra bị cấm: Nếu một tia vũ trụ tạo ra một sự kiện đơn lẻ làm đảo lộn mã chết của bạn, thì mọi thứ đều có thể. Nếu SEU kích hoạt một phần mã mạnh, hành vi (không mong muốn) vẫn nằm trong tầm kiểm soát.


Tôi không nhận được nó trong tàu vũ trụ là mã chết bị cấm? tức là bạn không thể viết cuối cùng? kể từ khi bạn không thể kiểm tra nó, bạn không thể đặt nó vào? nhưng sau đó nó có nghĩa là gì "Nếu SEU kích hoạt một phần mã mạnh, hành vi (không mong muốn) vẫn nằm trong tầm kiểm soát."
tồi tàn

5
Có, phạm vi kiểm tra phần mềm quan trọng trong không gian phải là 100% và do đó, mã không thể truy cập được (còn gọi là mã chết) bị cấm.
mouviciel

7

Tôi nghĩ rằng giáo sư có thể nhầm lẫn giữa "lỗi" và "lỗi". Mã mạnh mẽ chắc chắn nên có ít / không có lỗi. Mã mạnh có thể, và trong một môi trường thù địch, phải có quản lý lỗi tốt (có thể là xử lý ngoại lệ hoặc kiểm tra trạng thái hoàn trả nghiêm ngặt).

Tôi đồng ý rằng ví dụ mã của giáo sư là ngớ ngẩn, nhưng không ngớ ngẩn như của tôi.

// Assign 3 to x
var x = 3;
x = 3;   // again, just for sure
while (x < 3 or x > 3) { x = 3; }  // being robust
if (x != 3) { ... }  // this got to be an error!

1
Việc cuối cùng nếu chắc chắn được kích hoạt, nó sẽ không đòi hỏi nhiều nỗ lực như vậy. Bất kỳ lập trình viên C có kinh nghiệm đã thấy giá trị đột nhiên thay đổi. Tất nhiên, về mặt logic, trong một môi trường đơn luồng có kiểm soát, điều này sẽ không bao giờ xảy ra. Trong cuộc sống thực, mã bên trong nếu cuối cùng sẽ xảy ra. Nếu không có gì hữu ích bạn có thể làm trong đó nếu, thì đừng mã hóa nó! (Tôi đã có một trải nghiệm hài hước trong quá trình phát triển phần mềm cụ thể khi tôi nêu ra một ngoại lệ với những lời chửi rủa trong trường hợp có điều gì đó không thể xảy ra ... đoán xem điều gì đã xảy ra?).
Alex

2
Câu chuyện có thật:boolean x = something(); if (x) { x = True // make sure it's really true, ... }
Andres F.

6

Không có sự đồng ý về định nghĩa của Robust Code , vì đối với nhiều thứ trong lập trình, nó ít nhiều mang tính chủ quan ...

Ví dụ mà giáo sư của bạn đưa ra phụ thuộc vào ngôn ngữ:

  • Trong Haskell, a Booleancó thể là Truehoặc False, không có tùy chọn thứ ba
  • Trong C ++, một, boolcó thể true, falsehoặc (không may) đến từ một số diễn viên đáng ngờ đã đưa nó vào một trường hợp không xác định ... Điều này không nên xảy ra, nhưng có thể, do một lỗi trước đó.

Tuy nhiên, những gì giáo sư của bạn đang khuyên che khuất mã bằng cách đưa ra logic ngoại lai cho các sự kiện không nên xảy ra ở giữa chương trình cốt lõi, vì vậy tôi sẽ chỉ cho bạn, thay vào đó, hướng tới Lập trình phòng thủ .

Trong trường hợp đại học, bạn thậm chí có thể gia tăng nó bằng cách áp dụng chiến lược Design By Contract:

  • Thiết lập bất biến cho các lớp (ví dụ: sizelà số lượng mục trong datadanh sách)
  • Thiết lập các điều kiện trước và sau điều kiện cho từng chức năng (ví dụ: chức năng này chỉ có thể được gọi với amức nhỏ hơn 10)
  • Kiểm tra từng điểm tại các điểm vào và ra của từng chức năng của bạn

Thí dụ:

class List:
  def __init__(self, items):
    self.__size = len(items)
    self.__data = items

  def __invariant(self):
    assert self.__size == len(self.__data)

  def size(self):
    self.__invariant()

    return self.__size

  def at(self, index):
    """index should be in [0,size)"""
    self.__invariant()
    assert index >= 0 and index < self.__size

    return self.__data[index]

  def pushback(self, item):
    """the subsequent list is one item longer
       the item can be retrieved by self.at(self.size()-1)"""
    self.__invariant()

    self.__data.append(item)
    self.__size += 1

    self.__invariant()
    assert self.at(self.size()-1) == item

Nhưng giáo sư đặc biệt nói rằng đó là Java và đặc biệt KHÔNG nói loại var là gì. Nếu là Boolean, nó có thể đúng, sai hoặc null. Nếu một cái gì đó khác, nó có thể không bằng cả đúng và không bằng với sai. Vâng, chồng chéo giữa mạnh mẽ, phòng thủ và hoang tưởng.
Andy Canfield

2
Trong C, C ++ và Objective-C, bool có thể có giá trị không xác định, giống như bất kỳ loại nào khác, nhưng bất kỳ nhiệm vụ nào sẽ đặt nó thành đúng hoặc sai và không có gì khác. Ví dụ: bool b = 0; b ++; b ++; sẽ đặt b thành true.
gnasher729

2

Cách tiếp cận của giáo sư của bạn là hoàn toàn sai lầm.

Một hàm, hoặc chỉ một chút mã, nên có một thông số cho biết nó làm gì, nó sẽ bao gồm mọi đầu vào có thể. Và mã phải được viết để hành vi của nó được đảm bảo khớp với thông số kỹ thuật. Trong ví dụ này, tôi sẽ viết thông số kỹ thuật khá đơn giản như thế này:

Spec: If var is false then the function does "this", otherwise it does "that". 

Sau đó, bạn viết hàm:

if (var == false) dothis; else dothat; 

và mã đáp ứng thông số kỹ thuật. Vì vậy, giáo sư của bạn nói: Điều gì xảy ra nếu var == 42? Nhìn vào thông số kỹ thuật: Nó cho biết chức năng nên làm "điều đó". Nhìn vào mã: Hàm làm "cái đó". Hàm đáp ứng thông số kỹ thuật.

Trường hợp mã của giáo sư của bạn khiến mọi thứ hoàn toàn không ổn định là thực tế là với cách tiếp cận của anh ta, khi var không đúng cũng không sai, nó sẽ thực thi mã chưa từng được gọi trước đó và điều đó hoàn toàn chưa được kiểm chứng, với kết quả hoàn toàn không thể đoán trước.


1

Tôi đồng ý với tuyên bố của @ gnasher729: Cách tiếp cận của giáo sư của bạn hoàn toàn sai lầm.

Mạnh mẽ có nghĩa là nó có khả năng chống vỡ / thất bại bởi vì nó đưa ra một vài giả định và bị tách rời: nó khép kín, tự xác định và di động. Nó cũng bao gồm khả năng thích ứng với các yêu cầu thay đổi. Trong một từ, mã của bạn là bền .

Điều này thường chuyển thành các hàm ngắn lấy dữ liệu của họ từ các tham số được người gọi truyền vào và sử dụng giao diện công cộng cho người tiêu dùng - phương thức trừu tượng, trình bao bọc, giao diện, giao diện kiểu COM, v.v. - chứ không phải là các hàm chứa mã triển khai cụ thể.


0

Mã mạnh mẽ chỉ đơn giản là mã xử lý thất bại tốt. Không nhiều không ít.

Trong số các lỗi, có nhiều loại: mã không chính xác, mã không đầy đủ, giá trị không mong muốn, trạng thái không mong muốn, ngoại lệ, cạn kiệt tài nguyên, .... Mã mạnh mẽ xử lý tốt các mã này.


0

Tôi sẽ xem xét mã bạn đã đưa ra làm ví dụ về lập trình phòng thủ (ít nhất là khi tôi sử dụng thuật ngữ này). Một phần của lập trình phòng thủ là đưa ra các lựa chọn nhằm giảm thiểu các giả định được đưa ra về hành vi của phần còn lại của hệ thống. Ví dụ, cái nào trong số này là tốt hơn:

for (int i = 0; i != sequence.length(); ++i) {
    // do something with sequence[i]
}

Hoặc là:

for (int i = 0; i < sequence.length(); ++i) {
    // do something with sequence[i]
}

(Trong trường hợp bạn gặp khó khăn khi thấy sự khác biệt, hãy kiểm tra kiểm tra vòng lặp: lần sử dụng đầu tiên !=, lần sử dụng thứ hai <).

Bây giờ, trong hầu hết các trường hợp, hai vòng lặp sẽ hành xử theo cùng một cách chính xác. Tuy nhiên, lần đầu tiên (so sánh với !=) đưa ra một giả định isẽ chỉ được tăng lên một lần mỗi lần lặp. Nếu nó bỏ qua giá trị sequence.length()thì vòng lặp có thể tiếp tục vượt ra ngoài giới hạn của chuỗi và gây ra lỗi.

Do đó, bạn có thể đưa ra một lập luận rằng việc triển khai thứ hai mạnh mẽ hơn: nó không phụ thuộc vào các giả định về việc liệu cơ thể vòng lặp có thay đổi hay không i(lưu ý: thực tế nó vẫn đưa ra giả định ikhông bao giờ âm).

Để đưa ra một số động lực cho lý do tại sao bạn có thể không muốn đưa ra giả định đó, hãy tưởng tượng rằng vòng lặp đang quét một chuỗi, thực hiện một số xử lý văn bản. Bạn viết vòng lặp và mọi thứ đều ổn. Bây giờ các yêu cầu của bạn thay đổi và bạn quyết định bạn cần hỗ trợ các ký tự thoát trong chuỗi văn bản, do đó bạn thay đổi thân vòng lặp để nếu nó phát hiện một ký tự thoát (giả sử, dấu gạch chéo ngược), nó sẽ tăng iđể bỏ qua ký tự ngay sau khi thoát. Bây giờ vòng lặp đầu tiên có lỗi vì nếu ký tự cuối cùng của văn bản bị gạch chéo ngược, thân vòng lặp sẽ tăng lên ivà vòng lặp sẽ tiếp tục vượt ra ngoài cuối chuỗi.


-1

Cá nhân tôi mô tả một mã là 'mạnh mẽ' có thuộc tính này, thuộc tính quan trọng:

  1. Nếu mẹ tôi ngồi trước nó và làm việc với nó, bà không thể phá vỡ hệ thống

Bây giờ, khi nghỉ, tôi có nghĩa là đưa hệ thống vào trạng thái không ổn định hoặc gây ra ngoại lệ UNHANDLED . Bạn biết đấy, đôi khi đối với một khái niệm đơn giản, bạn có thể đưa ra một định nghĩa và giải thích phức tạp. Nhưng tôi thích các định nghĩa đơn giản. Người dùng khá giỏi trong việc tìm kiếm các ứng dụng mạnh mẽ. Nếu người dùng ứng dụng của bạn gửi cho bạn nhiều yêu cầu về lỗi, về mất trạng thái, về quy trình làm việc không trực quan, v.v., thì có điều gì đó không ổn với chương trình của bạn.

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.