Có phải mọi số trong mã đều được coi là số ma thuật của người Viking không?


21

Vì vậy, mỗi số trong mã mà chúng tôi đang gửi đến một phương thức làm đối số có được coi là Số ma thuật không? Đối với tôi, nó không nên. Tôi nghĩ rằng nếu một số nào đó giả sử nó là độ dài tối thiểu của tên người dùng và chúng tôi bắt đầu sử dụng "6" trong mã ... thì vâng, chúng tôi có vấn đề về bảo trì và ở đây "6" là một con số kỳ diệu .... nhưng nếu chúng ta đang gọi một phương thức mà một trong các đối số của nó chấp nhận một số nguyên, ví dụ như là thành viên thứ i của một bộ sưu tập và sau đó chúng ta chuyển "0" cho lệnh gọi phương thức đó, trong trường hợp này tôi không thấy "0" là một phép thuật con số. Bạn nghĩ sao?


4
Trong ví dụ của bạn, số 0 thể hiện điều gì?
Aaron Kurtzhals

2
Trong trường hợp bạn minh họa, "0" không có thuộc tính phép thuật nào.
Tulains Córdova

4
Mọi thứ trừ 0,1 và 42 đều là ma thuật
Mawg

Câu trả lời:


43

Nếu ý nghĩa của con số rất rõ ràng trong ngữ cảnh, tôi không nghĩ đó là vấn đề "số ma thuật".

Ví dụ: Giả sử bạn đang cố gắng lấy chuỗi con của chuỗi, từ đầu đến một số mã thông báo và mã trông như thế này (ngôn ngữ và thư viện tưởng tượng):

s := substring(big_string, 0, findFirstOccurence(SOME_TOKEN, big_string));

Trong bối cảnh này, ý nghĩa của số 0 là đủ rõ ràng. Tôi cho rằng bạn có thể xác định START_OF_SUBSTRINGvà đặt nó thành 0, nhưng trong trường hợp này tôi nghĩ rằng nó sẽ là quá mức cần thiết (mặc dù đó sẽ là cách tiếp cận chính xác nếu bạn biết rằng bắt đầu chuỗi con của bạn có thể không phải là 0, nhưng điều đó phụ thuộc vào chi tiết cụ thể của hoàn cảnh của bạn).

Một ví dụ khác có thể là nếu bạn đang cố xác định xem một số chẵn hay lẻ. Viết:

isEven := x % 2;

không lạ lùng như:

TWO := 2;
isEven := x % TWO;

Kiểm tra số âm như

MINUS_ONE := -1;
isNegativeInt := i <= MINUS_ONE;

cũng cảm thấy kỳ lạ với tôi, tôi muốn nhìn thấy nhiều hơn

isNegativeInt := i <= -1;

6
Để đưa ra một ví dụ khác ở đó, trong mã mà bạn rõ ràng làm việc với độ trên một vòng tròn, sẽ công bằng khi sử dụng một số như 360để đánh dấu một vòng quay đầy đủ với sự hiểu rằng hầu hết mọi người sẽ biết điều đó có nghĩa là gì (mặc dù điều này là một trường hợp nó sẽ không bị tổn thương để cung cấp một hằng số)
KChaloux

11
KChaloux: Nếu tôi có thể, tôi sẽ -1 bình luận của bạn. 360 là một con số kỳ diệu. Nếu 360 xảy ra là một giá trị cho hằng số khác, thì bạn có 2 bộ cho 360 không liên quan và không thể phân biệt. Junior đi cùng, đi "Đó là một con số kỳ diệu", tìm kiếm toàn cầu và thay thế 360 bằng "Degrees_in_Circle", chạy tất cả các bài kiểm tra đơn vị và hồi quy, tất cả đều vượt qua - cung cấp sửa lỗi mã. Mã bây giờ là một bữa sáng cho chó, và tất cả chúng ta đều biết điều gì xảy ra sau một thời gian ngắn .......
mattnz

4
@mattnz: Hy vọng rằng loại thay đổi mã quy mô lớn sẽ nhanh chóng bị bắt (hy vọng trong quá trình xem xét mã, nếu chúng là đàn em đó) từ lâu trước khi nó được đưa vào sản xuất. Tôi nghĩ ai đó sẽ làm điều đó trong bối cảnh đó có lẽ cũng sẽ thay thế 0trong bối cảnh của ví dụ chuỗi con của tôi. Trong trường hợp đó, đây có thể là thiệt hại ít nhất mà họ có thể gây ra. Đã lâu rồi tôi mới thực hiện bất kỳ mã hóa nào thực hiện các phép tính hình học, nhưng nói chung, các giá trị 15, 30, 45, 60, 90, 180, 360 là các hằng số được chấp nhận. Tôi chưa từng thấy ai định nghĩa FIFTEEN_DEGREES, ...
Thất vọngWithFormsDesigner

5
@KChaloux Ví dụ thực sự có thể sụp đổ nếu có sự thay đổi từ Độ sang Radian. Đến 360, bạn đang thể hiện 1 vòng quay hoàn chỉnh. Vì có nhiều biểu diễn cho cùng một giá trị, nên được rút ra. Đặc biệt, xem xét 360PI có thể trông giống như 2PI (180 lần quay nhưng vẫn chỉ cùng hướng ở cuối) hoặc 360 lần quay giống như 1 lần quay, nhưng tác dụng phụ có thể khác.
Chris

14
Một chút của một người đàn ông rơm ở đó, TWO và MINUS_ONE hoàn toàn xấu vì thay thế một số ma thuật bằng kết xuất của nó trong văn bản là KHÓA HỌC ngu ngốc. Tên của hằng phải truyền đạt ý nghĩa của nó. Ngoại trừ các ví dụ của bạn là về các sự kiện cơ bản về các con số, gắn chặt với chỉ những con số cụ thể đó, vì vậy thực sự không có ý nghĩa gì ngoài điều đó.
Michael Borgwardt

17
bool hasApples = apples > 0;

Rõ ràng là không có nghĩa là vắng mặt. Tôi thấy 0 dễ hiểu hơn một biến có tên "absValue".


for(int i=0; i < arr.length; i++)

Rõ ràng 0 là vị trí bắt đầu. Tôi sẽ bị nhầm lẫn bởi một biến có tên là "FirstPocation". Một biến như vậy sẽ khiến tôi tự hỏi nếu vị trí bắt đầu có thể thay đổi.


14

Tôi sẽ đề xuất ba yếu tố chính trong việc quyết định liệu một cái gì đó có nên là một tuyên bố liên tục hay không:

  1. Là số một cái gì đó là chính xác và chính xác đại diện
  2. Có bất kỳ kịch bản hợp lý nào theo đó giá trị sẽ phải thay đổi, nhưng mã sẽ không phải viết lại
  3. Ai đó nhìn thấy số có thể nhận ra nó nhanh hơn hoặc nhanh hơn so với người nhìn thấy hằng số có tên

Một cái gì đó như pi có lẽ nên được viết dưới dạng hằng số được đặt tên, chứ không phải là một chữ số, vì một chữ số có khả năng dài dòng không cần thiết, không cần thiết hoặc cả hai. Một cái gì đó như số lượng vị trí trong bộ đệm có thể là một hằng số được đặt tên (mặc dù xem ghi chú bên dưới) để cho phép khả năng mở rộng bộ đệm mà không phải sửa đổi tất cả mã sử dụng nó. Những thứ như các số "4", "28" và "29" trong câu lệnh if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28;có lẽ không nên được đặt tên là hằng số, vì biểu thức gần như chắc chắn dễ đọc hơn if ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;. Lưu ý rằng những người duy trì tiêu chuẩn đã chỉ ra rằng độ dài của tháng 2 năm 2100 trong năm đó sẽ không phù hợp với công thức trên, cản trở xử lý chính xác những ngày như vậy (tức là mã sẽ không bị vấp bởi tràn số nguyên hoặc các vấn đề khác như vậy).

Một cảnh báo quan trọng với quy tắc số 2 là trong một số trường hợp, mã có thể dựa vào các số được mã hóa cứng theo cách không thể được biểu diễn bằng hằng số có tên. Ví dụ, một phương pháp tính toán một sản phẩm chéo của hai vectơ được truyền dưới dạng các tham số rời rạc sẽ chỉ có ý nghĩa khi được sử dụng trên các vectơ ba chiều. Số lượng kích thước yêu cầu không phải là một giá trị có thể được thay đổi một cách có ý nghĩa mà không cần viết lại hoàn toàn thói quen. Ngay cả khi người ta thấy trước một nhu cầu có thể để tính toán sản phẩm chéo của ba vectơ 4 chiều, sử dụng hằng số có tên cho giá trị "3" sẽ giúp làm thỏa mãn nhu cầu đó dễ dàng hơn.


4

Điều này, như tất cả các nguyên tắc, là một vấn đề mức độ. Nói chung, số chữ trong mã nguồn càng nghi ngờ thì chúng càng lớn. Độ dài tối đa như 10 hoặc địa chỉ bộ nhớ như 0x587FB0 rõ ràng là thực tiễn xấu - gần như chắc chắn rằng sớm muộn bạn sẽ phải lặp lại các giá trị này nhiều lần, tạo ra nguy cơ không tương thích và lỗi tinh vi được đưa ra ở những nơi không có đã thay đổi

0 nằm ở đầu kia của thang đo; nó vẫn còn nghi ngờ nhưng không nhiều lắm Bạn có đang sử dụng 0 làm giá trị sentinel không? Sau đó, có lẽ bạn nên sử dụng hằng số tượng trưng thay vì chỉ vì hằng số có thể giải thích ý nghĩa của nó. Đây có phải là một thỏa thuận văn hóa cực kỳ cố thủ như "0 có nghĩa là hoàn thành thành công" không? Điều đó có thể ổn. Có nghĩa là "mục đầu tiên trong bộ sưu tập"? Điều đó có thể vô hại, nhưng nếu có một phương pháp thay thế như first()tôi có thể thích điều đó hơn.


1
"Bạn có đang sử dụng 0 làm giá trị sentinel không?" <- Bạn có thể giải thích những gì bạn có nghĩa là "sentinel" ở đây? Tôi không thể tìm thấy một định nghĩa có vẻ phù hợp.
rory.ap

3

Mỗi con số không tên không rõ ràng ngay lập tức từ ngữ cảnh là một con số kỳ diệu. Thật là hơi ngớ ngẩn khi định nghĩa những con số có ý nghĩa rõ ràng ngay lập tức từ bối cảnh.

Trong django (khung web python), tôi có thể định nghĩa một số trường cơ sở dữ liệu với một số nguyên như:

firstname = models.CharField(max_length=40)
middlename = models.CharField(max_length=40)
lastname =  models.CharField(max_length=40) 

đó là rõ ràng hơn (và thực hành được đề nghị ) hơn nói

MAX_LENGTH_NAME = 40
...
firstname = models.CharField(max_length=MAX_LENGTH_NAME)
middlename = models.CharField(max_length=MAX_LENGTH_NAME)
lastname =  models.CharField(max_length=MAX_LENGTH_NAME) 

vì tôi không bao giờ cần phải thay đổi độ dài (và luôn có thể so sánh với max_lengthtrường). Nếu tôi cần thay đổi độ dài của trường sau khi triển khai ứng dụng ban đầu, tôi cần thay đổi nó ở chính xác một vị trí trên mỗi trường trong mã django của mình, sau đó viết thêm một di chuyển để thay đổi lược đồ của DB. Nếu tôi cần tham chiếu max_lengthđến một trường được xác định của một loại đối tượng, tôi có thể thực hiện trực tiếp - nếu các trường đó đang xác định một Personlớp, tôi có thể sử dụng Person._meta.get_field('firstname').max_lengthđể có đượcmax_lengthđang được sử dụng (được xác định ở một nơi). Việc 40 cùng được sử dụng cho nhiều lĩnh vực là không liên quan vì tôi có thể muốn thay đổi chúng một cách độc lập. Độ dài của tên đầu tiên không bao giờ nên phụ thuộc vào độ dài của middlename hoặc họ; chúng là những giá trị riêng biệt và có thể thay đổi độc lập.

Thông thường các chỉ số mảng có thể sử dụng các số chưa được đặt tên; giống như nếu tôi có một tệp dữ liệu CSV mà tôi muốn đặt vào một từ điển python, với phần tử đầu tiên trong hàng là từ điển keytôi sẽ viết:

mydict = {}
for row in csv.reader(f):
    mydict[row[0]] = row[1:]

Chắc chắn tôi có thể đặt tên index_column = 0và làm một cái gì đó như:

index_col = 0
mydict = {}
for row in csv.reader(f):
    mydict[row[index_col]] = row[:index_col] + row[index_col+1:]

hoặc tệ hơn là xác định after_index_col = index_col + 1để loại bỏ index_col+1, nhưng điều đó không làm cho mã rõ ràng hơn trong quan điểm của tôi. Ngoài ra, nếu tôi index_colđặt tên, tốt hơn tôi nên làm cho mã hoạt động ngay cả khi cột không bằng 0 (do đó là row[:index_col] +một phần).


7
Trên thực tế, max_lngth=40vs. max_length=MAX_LENGTH_NAMElà một bài kiểm tra kinh điển về một con số ma thuật hét lên là một biểu tượng. Ngày sẽ đến khi bạn muốn hỗ trợ 45 tên nhân vật và bây giờ mọi nghi ngờ sử dụng "40" đều phải được kiểm tra cẩn thận.
Ross Patterson

1
@RossPatterson - Đây không phải là C nơi chúng tôi liên tục so sánh với var toàn cầu MAX_ARRAY_SIZE, mà là một khung web tốt. Nơi duy nhất mà số ma thuật xuất hiện là nơi bạn khai báo mô hình cơ sở dữ liệu; mọi thứ khác được so sánh với giá trị này (ví dụ: 40 không xuất hiện ở nơi nào khác trong mã). Cũng lưu ý, bạn không thể thay đổi biến này một cách dễ dàng mà không cần thực hiện di chuyển lược đồ vì nó được gắn với DB. Nếu tôi muốn thay đổi để nói 1 nhân vật tên đệm ngay lập tức rõ ràng một trong những vị trí của nó để thay đổi mã 40để 1. Bạn phải nghĩ về bối cảnh.
dr jimbob

2
Xin lỗi, bạn đã sai ở hai điểm. Đầu tiên, OP đã hỏi một câu hỏi "thực hành lập trình" không chỉ định bất kỳ ngôn ngữ nào. Họ nói "phương thức", không phải "chức năng", vì vậy chúng ta hãy giả sử một cái gì đó hướng đối tượng, nhưng điều đó không đưa chúng ta ra khỏi vương quốc của dữ liệu được đánh số ma thuật. Thứ hai, nếu số ma thuật được đưa vào cơ sở dữ liệu ( ví dụ: lược đồ), thì việc mã hóa nó còn tệ hơn nữa. Điều đúng đắn cần làm là lấy ma thuật gần như không đổi từ nguồn của nó - chính cơ sở dữ liệu hoặc mô đun lược đồ tập trung tất cả các hằng số đó sẽ thay đổi theo thời gian của mã.
Ross Patterson
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.