Đây có phải là sử dụng của một quá mức cần thiết tượng trưng?


34

Tôi còn khá mới đối với công nghệ phần mềm và vì vậy, như một bài tập học tập, tôi đã viết một ván cờ. Bạn tôi đã xem nó và chỉ ra rằng mã của tôi trông giống như

for (int i = 0; i < 8; i++){
    for (int j = 0; j < 8; j++){

trong khi anh ta khăng khăng rằng nó nên

for (int i = 0; i < CHESS_CONST; i++){
    for (int j = 0; j < CHESS_CONST; j++){

với một số tên biểu tượng tốt hơn mà tôi không thể bận tâm để nghĩ ngay bây giờ.

Bây giờ tất nhiên tôi biết là thường tránh sử dụng số ma thuật, nhưng tôi cảm thấy như từ

  1. con số này sẽ không bao giờ thay đổi;
  2. cái tên không thể được mô tả bằng mọi cách vì số này được sử dụng ở rất nhiều nơi trong suốt mã; và
  3. Bất cứ ai đi qua mã nguồn cho một chương trình cờ vua đều phải biết đủ về cờ vua để biết 8 là để làm gì,

thực sự không cần một hằng số tượng trưng.

Vậy các bạn nghĩ sao? Đây có phải là quá mức cần thiết, hay tôi chỉ nên đi theo quy ước và sử dụng một biểu tượng?


46
CHESS_CONST tệ hơn nhiều so với việc chỉ sử dụng số 8, nhưng một hằng số có tên mô tả sẽ là một sự cải tiến. Bạn nói rằng bất cứ ai cũng nên biết 8 là viết tắt của mã, nhưng điều này không đúng. Một số nguyên không có ngữ cảnh có thể có nghĩa là bất kỳ số lượng của sự vật, như một số di chuyển, số lượng các mảnh trên bảng và như vậy. Một tên mô tả cho hằng số sẽ làm cho ý định rõ ràng và do đó mã dễ hiểu hơn.
JacquesB

43
Cá nhân, những gì tôi thấy chói tai hơn nhiều so với số ma thuật là tên ijcho các biến vòng lặp. Cả đời tôi không thể tìm ra cái nào được cho là đại diện cho thứ hạng và cái nào được cho là đại diện cho tập tin. Xếp hạng phạm vi từ 1..8 và các phạm vi từ a..h, nhưng trong trường hợp của bạn, cả hai ijphạm vi từ 0..7, vì vậy điều đó không giúp tôi biết đó là cái nào. Có một số cuộc khủng hoảng thiếu thư quốc tế mà tôi không biết, hoặc có gì sai khi đổi tên chúng thành rankfile?
Jörg W Mittag

4
Chơi người ủng hộ của quỷ trong một giây; Hãy tưởng tượng đọc mã cờ của ai đó nơi họ đã sử dụng số ma thuật 8. Bạn có thể cho rằng bạn biết nó dùng để làm gì không? Làm thế nào bạn có thể chắc chắn 100%? Có khả năng nào nó có thể có nghĩa gì khác không? Nó sẽ không đẹp hơn một chút nếu bạn thậm chí không phải đưa ra một giả định? Bạn có thể dành bao nhiêu thời gian để theo dõi mã để tìm hiểu xem giả định của bạn có đúng không? Thay vào đó, bạn sẽ mất ít thời gian hơn nếu mã đã được ghi lại nhiều hơn bằng cách sử dụng một cái tên sâu sắc, có ý nghĩa?
Ben Cottrell

16
@JacquesB: Thật vậy. Có 8 cấp bậc, 8 tập tin, 8 con tốt. Một số động cơ cờ vua sử dụng hệ thống điểm trong đó một số quân cờ, một số trường nhất định và một số nước đi nhất định có các điểm gắn liền với chúng và động cơ chọn nước đi có số điểm cao nhất. 8 có thể là một số điểm như vậy. 8 có thể là độ sâu tìm kiếm mặc định. Nó có thể là khá nhiều bất cứ điều gì.
Jörg W Mittag

9
Tôi sẽ xem xét sử dụng một vòng lặp foreach, ví dụ foreach(var rank in Ranks). Tôi cũng sẽ xem xét việc hợp nhất cả hai vòng lặp thành một trong đó mỗi phần tử là một tuple (xếp hạng, tệp).
CodeInChaos

Câu trả lời:


101

IMHO bạn của bạn đã đúng khi sử dụng một cái tên tượng trưng, ​​mặc dù tôi nghĩ rằng cái tên này chắc chắn nên được mô tả nhiều hơn (như BOARD_WIDTHthay vì CHESS_CONST).

Ngay cả khi số sẽ không bao giờ thay đổi trong suốt thời gian của chương trình, có thể có những nơi khác trong chương trình của bạn, nơi số 8 sẽ xảy ra với một ý nghĩa khác. Thay thế "8" bằng BOARD_WIDTHbất cứ nơi nào có nghĩa là chiều rộng của bảng và sử dụng một tên tượng trưng khác khi một điều khác có nghĩa là làm cho những ý nghĩa khác nhau này rõ ràng, rõ ràng và chương trình tổng thể của bạn dễ đọc và dễ bảo trì hơn. Nó cũng cho phép bạn thực hiện tìm kiếm toàn cầu trên chương trình của bạn (hoặc tìm kiếm ký hiệu ngược, nếu môi trường của bạn cung cấp) trong trường hợp bạn cần nhanh chóng xác định tất cả các vị trí trong mã phụ thuộc vào độ rộng của bảng.

Xem thêm bài đăng trước đây của SE.SE này để biết thảo luận về cách (hoặc cách không) chọn tên cho các số.

Như một lưu ý phụ, vì nó đã được thảo luận ở đây trong các bình luận : nếu, trong mã chương trình thực của bạn, vấn đề là nếu biến itham chiếu đến các hàng và jcác cột của bảng, hoặc ngược lại, thì nên chọn tên biến làm cho sự phân biệt rõ ràng, giống như rowcol. Lợi ích của tên như vậy là, họ làm cho mã sai nhìn sai.


22
Tôi muốn nói thêm, nếu OP đã viết một cỗ máy cờ vua thực sự tuyệt vời thì muốn mở rộng nó để bao gồm cờ vua 3D hoặc các biến thể khác, thì 8 số cần thay đổi sẽ là một thách thức.
Steve Barnes

32
@SteveBarnes: Tôi cố gắng tránh những tranh luận như vậy, vì nó quá dễ dẫn đến một cuộc tranh luận được hoàn nguyên như "Tôi nghĩ rằng nó cực kỳ không giống với việc biến chương trình này thành một loại trò chơi khác, vì vậy tôi có thể để lại số 8 kỳ diệu. "
Doc Brown

4
@IllusiveBrian Đó là một đối số "người rơm" cổ điển vì hai lý do: (1) chỉ cần xác định một hằng số không có nghĩa là lập trình viên vẫn không thể gõ "8" (dù là do vô tình, thiết kế hay ác ý!) Và (2) chỉ vì có hằng số BOARD_WIDTH = 8 không biến BOARD_WIDTH thành hằng số chính xác để sử dụng tại một vị trí cụ thể trong chương trình.
alephzero

3
@Blrfl ... hoặc sẽ dẫn đến việc áp đảo mã. Trách nhiệm của nhà phát triển là nhận ra những gì có thể thay đổi trong tương lai và mã phù hợp. Mã hóa như các yêu cầu sẽ không thay đổi gây ra vấn đề, nhưng cực đoan khác thì không tốt hơn.
Malcolm

4
@corsiKa Khi các biến vòng lặp tương ứng với các trục vật lý, chúng nên được đặt tên là x, y hoặc hàng, col hoặc, cho cờ vua, tệp, xếp hạng.
user949300

11

Ok, đây là một vài ý kiến ​​tôi có:

Loại bỏ các con số ma thuật là một ý tưởng tuyệt vời. Có một khái niệm được gọi là DRY, thường được trình bày sai, nhưng ý tưởng là bạn không sao chép kiến ​​thức về các khái niệm trong dự án của bạn. Vì vậy, nếu bạn có một lớp được gọi là ChessBoard, bạn có thể giữ một hằng số được gọi là BOARD_SIZE hoặc ChessBoard.SIZE kèm theo nó. Cách này có một nguồn duy nhất cho thông tin này. Ngoài ra, điều này giúp dễ đọc sau này:

for (int i = 0; i < ChessBoard.SIZE; i++){
  for (int j = 0; j < ChessBoard.SIZE; j++){

Ngay cả khi số lượng không bao giờ thay đổi, chương trình của bạn vẫn tốt hơn. Bất kỳ ai đọc nó đều biết thêm thông tin về những gì mã đang làm.

Một tên xấu tệ hơn là không có tên, nhưng điều đó không có nghĩa là một cái gì đó không nên được đặt tên. Chỉ cần thay đổi tên. Đừng vứt em bé bằng nước tắm. : p Tên có thể được mô tả miễn là bạn hiểu rõ những gì nó được mô tả. Sau đó, khái niệm đó có thể được sử dụng cho nhiều thứ khác nhau.


8
điều này dường như chỉ lặp lại các điểm đã được thực hiện và giải thích trong câu trả lời hàng đầu
gnat

-7

Những gì bạn thực sự muốn là loại bỏ các tham chiếu quảng cáo đến các hằng số, cho dù chúng được đặt tên hay để trần:

for_each_chess_square (row, col) {
  /*...*/
}

Nếu bạn thực sự sẽ sinh sôi nảy nở hằng số bằng cách lặp lại các vòng lặp như vậy và không có gì, tốt nhất là nên gắn bó 8.

8là tự mô tả; nó không phải là một macro đại diện cho một cái gì đó khác.

Bạn không bao giờ Gonna (TM) biến nó thành một chương trình cờ vua 9x9 và nếu bạn từng làm thế, sự phổ biến của 8 sẽ không phải là khó khăn lớn.

Chúng tôi có thể tìm kiếm cơ sở mã 150.000 dòng cho mã thông báo 8 và phân loại các lần xuất hiện có nghĩa là gì trong vài giây.

Quan trọng hơn nhiều là mô đun hóa mã để kiến ​​thức cờ vua được tập trung ở càng ít nơi càng tốt. Tốt hơn là nên có một, hai, có thể ba mô-đun dành riêng cho cờ vua, trong đó có 8 mô-đun theo nghĩa đen xảy ra, hơn ba mươi bảy mô-đun có trách nhiệm dành riêng cho cờ vua, đề cập đến 8 thông qua một tên tượng trưng.

Khi hoặc nếu 8 hằng số này trở thành một nguồn căng thẳng trong chương trình của bạn, bạn có thể dễ dàng khắc phục nó tại thời điểm đó. Khắc phục sự cố thực sự đang xảy ra bây giờ. Nếu bạn không cảm thấy rằng mình bị cản trở bởi 8 điều đặc biệt đó, hãy đi theo bản năng đó.

Giả sử rằng trong tương lai bạn muốn hỗ trợ kích thước bảng thay thế. Trong trường hợp đó, các vòng lặp đó sẽ phải thay đổi cho dù chúng sử dụng hằng số được đặt tên hay 8, bởi vì kích thước sẽ được truy xuất bởi một số biểu thức như board.widthboard.height. Nếu bạn có BOARD_SIZEthay vì 8, những nơi này sẽ dễ dàng tìm thấy hơn. Vì vậy, đó là ít nỗ lực. Tuy nhiên, bạn không được quên về nỗ lực thay thế 8bằng BOARD_SIZEở nơi đầu tiên. Nỗ lực chung không thấp. Đã có một đường chuyền so với mã để thay đổi 8để BOARD_SIZE, và sau đó khác để hỗ trợ kích thước thay thế, không phải là rẻ hơn so với chỉ đi từ 8để hỗ trợ chiều thay thế.

Chúng ta cũng có thể xem xét điều này từ một phân tích rủi ro / lợi ích khách quan hoàn toàn lạnh lùng. Chương trình có hằng số trần trong đó bây giờ. Nếu những cái này được thay thế bởi một hằng số, không có lợi ích; chương trình này giống hệt nhau. Với bất kỳ thay đổi, có một rủi ro khác không. Trong trường hợp này, nó là nhỏ. Tuy nhiên, không có rủi ro nên được thực hiện mà không có lợi ích. Để "bán" sự thay đổi khi đối mặt với lý do này, chúng ta phải đưa ra giả thuyết về một lợi ích: một lợi ích trong tương lai sẽ giúp với một chương trình khác: một phiên bản tương lai của chương trình hiện không tồn tại. Nếu một chương trình như vậy đang được lên kế hoạch, giả thuyết này và lý do liên quan của nó là đúng đắn và cần được thực hiện nghiêm túc.

Chẳng hạn, nếu bạn không muốn thêm nhiều mã sẽ sinh sôi nảy nở thêm các hằng số này, bạn có thể muốn loại bỏ chúng. Nếu các thể hiện của hằng số xấp xỉ tất cả các thể hiện sẽ tồn tại thì tại sao phải bận tâm.

Nếu bạn từng làm việc trên phần mềm thương mại, các đối số ROI cũng sẽ được áp dụng. Nếu một chương trình không bán được và việc thay đổi một số số được mã hóa cứng thành hằng số sẽ không cải thiện doanh số, bạn sẽ không được đền bù cho nỗ lực này. Sự thay đổi có lợi tức bằng không đối với đầu tư của thời gian. Đối số ROI khái quát hóa ngoài tiền. Bạn đã viết một chương trình, đầu tư thời gian và công sức và nhận được một cái gì đó từ đó: đó là tiền lãi của bạn, "R" của bạn. Nếu bằng cách thực hiện thay đổi đó một mình, bạn sẽ nhận được nhiều hơn "R", bất kể đó là gì, bằng mọi cách. Nếu bạn có một số kế hoạch để phát triển hơn nữa và sự thay đổi đó sẽ cải thiện "R" của bạn, ditto. Nếu thay đổi không có "R" ngay lập tức hoặc có thể thấy được cho bạn, hãy quên nó đi.


13
8KHÔNG phải là tự mô tả, đó là một con số có thể có nghĩa gì. Và có lẽ họ muốn làm một ván cờ 9x9, tại sao không? Nếu bạn có 150.000 dòng mã, sẽ không có cách nào bạn có thể ghi nhớ từng 8phương tiện trong mã và ngay cả khi bạn có thể, tại sao bạn lại như vậy? Đó chỉ là rất nhiều rắc rối. Theo như mô-đun hóa, việc thay thế 8bằng một cái gì đó như NUM_RANKSkhông làm tổn hại đến tính mô-đun, trên thực tế, nó giúp ích vì nó làm cho mã dễ dàng hơn để sửa đổi.
Jerfov2

4
@Kaz tôi cũng vậy. Và sau đó tôi giới thiệu những lỗi kỳ lạ đáng kể bởi vì một số ít sử dụng không như tôi nghĩ, bởi vì thật khó để chú ý nhiều đến một số lượng lớn thay thế và cũng luôn luôn chính xác. Vì lý do đó, tôi tránh tham gia vào kịch bản này ngay từ đầu, vì vậy tôi không thể hỗ trợ lời khuyên mà bỏ qua việc này.
doppelgreener

1
"Tuy nhiên, bạn không quên đi những nỗ lực thay thế 8với BOARD_SIZEở nơi đầu tiên" - Thời gian bạn đã dành rà soát trên mã của bạn cố gắng để con số những gì từng 8làm trong tháng chương trình của bạn từ bây giờ sẽ rất có thể vượt quá mức thời gian dành thay thế 8với một hằng số cấp mô-đun có ý nghĩa.
Christian Dean

1
@doppelganger Kịch bản đó đã ở đây. Tôi không nói, hãy tham gia một chương trình cờ vua sử dụng các hằng số và thay thế chúng bằng 8. Tôi cũng không nói, "kế hoạch không sử dụng các hằng số trong một chương trình cờ chưa được viết"
Kaz

1
@Kaz Tại sao bạn muốn làm cho mình phải đọc tất cả các mã trong khoảng 8 và đôi khi có thể hiểu sai ngữ cảnh khi bạn chỉ cần dành thêm 3 giây để đặt tên có ý nghĩa? Để biết giá trị thực của hằng số, việc tìm kiếm giá trị chính xác cho một biến sẽ dễ dàng hơn nhiều so với việc cố gắng thiết kế ngược một số nguyên ma thuật trong mã có nghĩa là gì
Jerfov2
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.