Sử dụng chuỗi / số ma thuật [đóng]


31

Đây là một chủ đề gây tranh cãi, và tôi đoán có nhiều ý kiến ​​như có các lập trình viên. Nhưng vì lợi ích của nó, tôi muốn biết những thông lệ phổ biến trong kinh doanh (hoặc tại nơi làm việc của bạn) là gì.

Ở nơi làm việc của tôi, chúng tôi có một hướng dẫn mã hóa nghiêm ngặt. Một phần trong đó dành riêng cho chuỗi / số ma thuật. Nó tuyên bố (cho C #):

Không sử dụng các giá trị bằng chữ, số hoặc chuỗi, trong mã của bạn ngoài việc xác định các hằng số ký hiệu. Sử dụng mẫu sau để xác định hằng số:

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

Có các trường hợp ngoại lệ: các giá trị 0, 1 và null gần như luôn có thể được sử dụng một cách an toàn. Rất thường các giá trị 2 và -1 cũng ổn. Chuỗi dành cho đăng nhập hoặc theo dõi được miễn quy tắc này. Nghĩa đen được cho phép khi ý nghĩa của chúng rõ ràng từ bối cảnh, và không chịu sự thay đổi trong tương lai.

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

Một tình huống lý tưởng sẽ là một số tài liệu nghiên cứu chính thức cho thấy hiệu ứng về khả năng đọc / duy trì mã khi:

  • Số / chuỗi ma thuật ở khắp mọi nơi
  • Các chuỗi / số ma thuật được thay thế bằng các khai báo liên tục một cách hợp lý (hoặc ở các mức độ bao phủ khác nhau) - và xin đừng hét vào tôi vì đã sử dụng "hợp lý", tôi biết mọi người đều có ý tưởng khác nhau "hợp lý" là gì
  • Các chuỗi / số ma thuật được xếp chồng lên nhau và ở những nơi không cần phải có (xem ví dụ của tôi dưới đây)

Tôi muốn làm điều này để có một số lập luận dựa trên cơ sở khoa học khi tranh luận với một trong những đồng nghiệp của tôi, người sẽ đi đến điểm tuyên bố các hằng số như:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Một ví dụ khác sẽ là (và ví dụ này là trong JavaScript):

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

Bạn có dán ID DOM trên đầu tệp javascript của mình không nếu ID đó chỉ được sử dụng ở 1 vị trí?

Tôi đã đọc các chủ đề sau:
StackExchange
StackOverflow
Bytes Cộng đồng CNTT
Có nhiều bài viết khác, và sau khi đọc một số mẫu này xuất hiện.

Vì vậy, câu hỏi của tôi là có nên sử dụng chuỗi và số ma thuật trong mã của chúng tôi? Tôi đặc biệt tìm kiếm các câu trả lời chuyên gia được hỗ trợ bởi các tài liệu tham khảo nếu có thể.


2
Một biến ma thuật là một biến chứa một ý nghĩa không được phản ánh bởi nội dung của nó. Giá trị nguyên '10' phản ánh ý nghĩa của số 10, do đó không cần phải biến nó thành hằng số. Cùng đi cho không gian và dấu chấm phẩy. Mặt khác, nếu bạn có giá trị '%% ?? %%' và đây là một số dấu phân cách tùy chỉnh, thì đó phải được đặt là một hằng số vì nội dung của nó không phản ánh thực tế rằng đó là một dấu phân cách.
Jeroen Vannevel

23
NumberTen = 10Điều đó là vô nghĩa vì số 10 sẽ không được xác định lại. MaxRetryCount = 10Điều đó có một điểm chúng ta có thể muốn thay đổi số lần thử lại tối đa. private const char SemiColon = ';'; Câm. private const char LineTerminator = ';'; Thông minh.
Mike

1
Câu hỏi thực tế không rõ ràng.
Tulains Córdova

Câu trả lời:


89

... Khi tranh cãi với một trong những đồng nghiệp của tôi, người sẽ đi đến điểm tuyên bố các hằng số như:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Cuộc tranh luận mà bạn cần đưa ra với đồng nghiệp không phải là về việc đặt tên cho một không gian theo nghĩa đen Spacemà là sự lựa chọn tên kém cho các hằng số của anh ta.

Giả sử công việc của mã của bạn là phân tích một luồng các bản ghi có chứa các trường được phân tách bằng dấu chấm phẩy ( a;b;c) và chúng được phân tách bằng dấu cách ( a;b;c d;e;f). Nếu bất cứ ai viết thông số kỹ thuật của bạn gọi cho bạn một tháng kể từ bây giờ và nói, "chúng tôi đã nhầm, các trường trong hồ sơ được phân tách bằng ký hiệu ống ( a|b|c d|e|f)," bạn sẽ làm gì?

Theo sơ đồ giá trị như tên đồng nghiệp của bạn, bạn sẽ phải thay đổi giá trị của chữ ( SemiColon = '|') và sống với mã tiếp tục sử dụng SemiColoncho thứ gì đó không thực sự là dấu chấm phẩy nữa. Điều đó sẽ dẫn đến những bình luận tiêu cực trong đánh giá mã . Để giảm bớt điều đó, bạn có thể thay đổi tên của nghĩa đen thành PipeSymbolvà đi qua và thay đổi mọi lần xuất hiện SemiColonthành PipeSymbol. Với tốc độ đó, bạn có thể vừa mới sử dụng dấu chấm phẩy ( ';') ở vị trí đầu tiên, bởi vì bạn sẽ phải đánh giá từng lần sử dụng riêng lẻ và bạn sẽ thực hiện cùng một số thay đổi.

Các định danh cho hằng số cần được mô tả về giá trị làm gì, không phải giá trị là gì và đó là nơi đồng nghiệp của bạn đã rẽ trái vào cỏ dại. Trong ứng dụng phân tách trường được mô tả ở trên, mục đích của dấu chấm phẩy là một dấu tách trường và các hằng số phải được đặt tên tương ứng:

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

Bằng cách này, khi dấu tách trường thay đổi, bạn thay đổi chính xác một dòng mã, khai báo hằng. Ai đó nhìn vào sự thay đổi sẽ chỉ thấy một dòng đó và sẽ ngay lập tức hiểu rằng dấu tách trường đã thay đổi từ dấu chấm phẩy thành biểu tượng đường ống. Phần còn lại của mã, không cần thay đổi vì nó sử dụng hằng số, vẫn giữ nguyên và người đọc không phải tìm hiểu kỹ về nó để xem những gì khác đã được thực hiện với nó.


Tôi hoàn toàn đồng ý. Vài thập kỷ trước tôi đã làm việc trong một dự án nơi các tin nhắn được gửi trong các phân đoạn, mỗi tin nhắn sử dụng 8 thanh ghi chung. Ai đó đã tuyên bố #define one 1 #define two 2 vv (hoặc bất cứ điều gì tương đương là ở Bưu điện Anh Coral, ngôn ngữ được lựa chọn sau đó). Word xuất phát từ trên cao rằng trong tương lai, trường độ dài sẽ là số byte, không phải phân đoạn, vì vậy rõ ràng mã được đổi thành #define one 8 #define two 16 vv
Mawg

3
Như ngớ ngẩn như những cái tên như chấm phẩy hoặc PipeSymbol vẻ, thay đổi một đến khác sử dụng một kịch bản sẽ dễ dàng hơn rất nhiều so với việc thay đổi mỗi ảnh hưởng ;đến |.
Brandin

Thế còn trường hợp một chuỗi ký tự đã cho được sử dụng nhiều lần trong một tệp, nhưng nó không có ý nghĩa gì ngoài giá trị của nó? Ví dụ: nếu bạn đang kiểm tra rằng bạn có thể nhận được một khóa nhất định trong bản đồ theo 20 kịch bản khác nhau, tôi có nên xác định một hằng số như vậy không?: public static final String MY_KEY_NAME = "MyKeyName"
Jordan McQueen

1
@JordanMcQueen Có một trường hợp được tạo ra để sử dụng chữ trần nếu (và chỉ khi) mỗi cái được sử dụng chính xác một lần và không cần ở bất kỳ nơi nào khác. Nếu nó giống như mỗi kịch bản mã đang được mà xử lý một định dạng tập tin khác nhau, mỗi định dạng cần xác định hằng số riêng của nó (ví dụ, CSV_RECORD_SEPARATOR, TSV_RECORD_SEPARATOR, vv).
Blrfl

8

Xác định dấu chấm phẩy là một hằng số là dư thừa, bởi vì dấu chấm phẩy đã tự nó không đổi . Nó sẽ không bao giờ thay đổi.

Không giống như một ngày nào đó ai đó sẽ thông báo "thay đổi thuật ngữ, + là dấu chấm phẩy mới bây giờ" và đồng nghiệp của bạn sẽ vui vẻ vội vàng chỉ để cập nhật hằng số (họ cười tôi - nhìn họ ngay bây giờ).

Cũng có một vấn đề về tính nhất quán. Tôi đảm bảo rằng anh ấyNumberTen hằng số sẽ KHÔNG được mọi người sử dụng (hầu hết các lập trình viên không nằm ngoài suy nghĩ của họ), vì vậy dù sao nó cũng không phục vụ cho bất kỳ mục đích nào mà nó dự kiến. Khi ngày tận thế đến và "mười" được thay đổi kích thước toàn cầu thành 9, việc cập nhật hằng số sẽ KHÔNG thực hiện thủ thuật, bởi vì nó sẽ vẫn để lại cho bạn một đống chữ 10trong mã của bạn, vì vậy bây giờ hệ thống trở nên hoàn toàn không thể đoán trước ngay cả trong phạm vi của một giả định mang tính cách mạng rằng "mười" có nghĩa là "9".

Lưu trữ tất cả các cài đặt dưới dạng consts cũng là điều tôi có suy nghĩ thứ hai. Người ta không nên làm điều này nhẹ nhàng.

Những ví dụ về loại sử dụng này chúng ta đã thu thập được cho đến nay? Kẻ kết thúc dòng ... số lần thử lại tối đa ... số lượng bánh xe tối đa ... chúng ta có tích cực không?

Chi phí là việc thay đổi cài đặt mặc định đòi hỏi phải biên dịch lại một ứng dụng và trong một số trường hợp, ngay cả các phụ thuộc của nó (vì các giá trị const số có thể được mã hóa cứng trong quá trình biên dịch).

Ngoài ra còn có khía cạnh thử nghiệm và chế giễu. Bạn đã xác định chuỗi kết nối là một hằng, nhưng bây giờ rất tiếc bạn không thể giả định quyền truy cập cơ sở dữ liệu (thiết lập kết nối giả) trong bài kiểm tra đơn vị của bạn.


4
"Nó sẽ không bao giờ thay đổi." Tôi đã từng nghĩ rằng về dấu nháy đơn (mãi mãi gắn liền với giá trị ASCII 39). Một số ứng dụng cũ được sử dụng để cuộn tròn dấu nháy đơn. Nhưng hiện nay, các ứng dụng hiện đại coi giá trị ASCII là dấu nháy đơn tương thích với các ứng dụng cũ và thay vào đó mọi người thường sử dụng (trích dẫn đơn, Unicode 8217 ) cho các ứng dụng tương thích với hiển thị glyph khác nhau cho dấu cong. Do châu Âu sử dụng dấu phẩy theo cách người Mỹ sử dụng dấu chấm như một dấu thập phân, tôi thấy mình hơi do dự khi tuyên bố "không ... bao giờ".
TUYỆT VỜI

@TOOGAM tốt, ví dụ của bạn biện minh cho việc có DecimalPointhằng số - nhưng không Commahoặc Periodhằng. Đó là một sự khác biệt hoàn toàn: trước đây biểu thị một chức năng , vai trò hoặc mục đích của giá trị. "Dấu chấm phẩy" hoặc "dấu phẩy" không thuộc danh mục đó.
Konrad Morawski

Điều đó đúng với ví dụ về Số thập phân. Tuy nhiên, ví dụ dấu nháy đơn dường như là một thể loại tương tự (hoặc giống hệt nhau) dưới dạng dấu phẩy (hoặc dấu chấm phẩy).
TUYỆT VỜI

@KonradMorawski Dấu chấm phẩy có thể được sử dụng cho nhiều mục đích, chẳng hạn như tách chuỗi hoặc kết thúc dòng. Đó là ý nghĩa của nó (không phải giá trị) nên được sử dụng để đặt tên constance. Hãy xem xét sự thay đổi trong tương lai, tức là ngày mai chúng tôi cho phép xử lý 20 bản ghi, do đó, hiến pháp có tên NumberTen nằm ngoài ngữ cảnh, trong khi maxRecord vẫn ổn.
MaxZoom

5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Vì vậy, đồng nghiệp của bạn đang nhắm đến một mục WTF hàng ngày. Những định nghĩa đó là ngớ ngẩn và dư thừa. Tuy nhiên, như đã được chỉ ra bởi những người khác, các định nghĩa sau đây sẽ không ngớ ngẩn hoặc dư thừa:

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

Các số và chuỗi "ma thuật" là các hằng số có ý nghĩa vượt quá giá trị nghĩa đen tức thời của chúng. Nếu hằng số10 có ý nghĩa vượt quá "mười điều" (nói như một mã cho một hoạt động cụ thể hoặc điều kiện lỗi), thì đó là khi nó trở thành "ma thuật" và nên được thay thế bằng một hằng số biểu tượng mô tả ý nghĩa trừu tượng đó.

Ngoài việc mô tả rõ ràng ý định, hằng số biểu tượng cũng giúp bạn tiết kiệm một số vấn đề đau đầu khi bạn viết sai chính tả. Một chuyển đổi đơn giản từ "CVS" sang "CSV" trong một dòng mã đã hoàn toàn thông qua thử nghiệm đơn vị và QA và đưa nó vào sản xuất, trong đó nó đã khiến một hoạt động cụ thể thất bại. Đúng, rõ ràng các bài kiểm tra đơn vị và QA chưa hoàn chỉnh và đó là vấn đề của riêng họ, nhưng sử dụng hằng số tượng trưng sẽ tránh được tình trạng ợ nóng đó hoàn toàn.


3

Không nên có bất cứ điều gì gây tranh cãi về nó. Vấn đề không phải là về việc có sử dụng số ma thuật hay không, vấn đề là phải có mã có thể đọc được.
Hãy xem xét sự khác biệt giữa: if(request.StatusCode == 1)if(request.HasSucceeded). Trong trường hợp này, tôi sẽ cho rằng cái sau dễ đọc hơn nhiều, nhưng điều đó không có nghĩa là bạn không bao giờ có mã như thế nào int MaxNumberOfWheels = 18.

PS: Đây là lý do tại sao tôi hoàn toàn ghét hướng dẫn mã hóa. Các nhà phát triển nên đủ trưởng thành để có khả năng thực hiện các cuộc gọi phán xét như thế này; họ không nên để nó thành một đoạn văn bản được hình thành bởi chúa biết ai.


13
Người lái xe phải đủ chín chắn để có khả năng phán đoán về phía bên nào của con đường họ lái;)
Konrad Morawski

2
Kết quả của một cuộc gọi phán xét có thể khác nhau ngay cả giữa các nhà phát triển trưởng thành, do đó, ngay cả các hướng dẫn mã hóa tùy ý cũng nhằm cải thiện khả năng đọc thông qua tính nhất quán. Điều này không liên quan đến thực tế là việc tạo ra NumberTen không có ý nghĩa.
Mike Partridge

1
Tôi sẽ không khăng khăng rằng họ phải chính thức, đóng dấu, v.v., họ có thể không chính thức nhưng họ nên được thỏa thuận, và điều này đã vượt ra ngoài việc sử dụng sự trưởng thành của bản thân. Nhưng bạn đã xóa bình luận của mình ngay bây giờ Stefan :)
Konrad Morawski

1
@StefanBilliet - hoàn toàn không. Quan điểm của tôi là khả năng đọc được cải thiện thông qua tính nhất quán. Vấn đề ở đây không phải là bản thân hướng dẫn mã hóa, mà là một hướng dẫn được đưa ra đến mức cực đoan thông qua sự hiểu lầm.
Mike Partridge

@MikePartridge Có lẽ tôi nên xây dựng; các hướng dẫn mã hóa mà tôi đã thấy nhiều hơn trong xu hướng của một quy tắc chung về cách một người nào đó nghĩ rằng phần mềm nên được viết, thay vì các thỏa thuận như bạn và Konrad có lẽ đang nghĩ đến :-)
Stefan Billiet
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.