Tại sao các biến không sử dụng là một vấn đề như vậy?


9

Một ngày nọ, tôi đang dọn dẹp các biến không sử dụng và tôi bắt đầu suy ngẫm, vấn đề chính xác là gì?

Trên thực tế, một số trong số chúng thậm chí còn giúp gỡ lỗi (ví dụ: kiểm tra chi tiết ngoại lệ hoặc kiểm tra giá trị trả về trước khi trả về).

Tôi không thể tìm thấy rủi ro thực sự khi có chúng ..

Ví dụ

Tôi không có nghĩa là các dòng mất thời gian chú ý của các lập trình viên khác, chẳng hạn như:

int abc = 7;

Đó là một sự dư thừa rõ ràng và mất tập trung. Ý tôi là những thứ như:

try {
    SomeMethod();
} catch (SomeException e) {
    // here e is unused, but during debug we can inspect exception details
    DoSomethingAboutIt();
}

31
Ý bạn là khác với thực tế là lập trình viên đến sau bạn sẽ phải dành thời gian cố gắng tìm hiểu tại sao họ lại ở đó?
Robert Harvey


1
Ví dụ của bạn là vô hại, nhưng tôi chưa bao giờ thấy các trường hợp như thế được gọi là "các biến không sử dụng". Những cảnh báo của bạn đến từ đâu?
Jacob Raihle

9
Vâng, retkhông phải là không sử dụng.
Robert Harvey

4
Bạn đã viết " Ý tôi là như thế catch (SomeException e) " - bạn đang giả vờ có những trường hợp tương tự khác. Khai sáng cho tôi, cái nào? Tôi hỏi vì trong C # hoặc C ++, tôi gặp khó khăn khi tìm một tình huống khác cho trường hợp của bạn.
Doc Brown

Câu trả lời:


4

Theo khung bạn đã đưa ra, thật khó để tranh luận với các biến đó mỗi lần:

try {
    SomeMethod();
} catch (SomeException e) {
// here e is unused, but during debug we can inspect exception details
DoSomethingAboutIt();
}

Lấy ví dụ này Bạn đang bắt một ngoại lệ và (có lẽ) có mã xử lý ngoại lệ đó một cách thích hợp. Thực tế là bạn không sử dụng ví dụ thực tế của ngoại lệ không có hại, đối với dòng mã cũng như không dễ hiểu.

Nhưng điều khiến tôi suy nghĩ là khi bạn viết về việc hợp pháp hóa »các biến không sử dụng«

Trong thực tế, một số trong số họ thậm chí còn giúp gỡ lỗi

Đó không phải là mục đích của việc viết mã: phải gỡ lỗi sau. Để tránh những hiểu lầm, tôi phải nói rằng, tôi nhận thức rõ rằng, đôi khi bạn phải sửa mã của mình; và đôi khi gỡ lỗi là giải pháp. Nhưng nó không phải là điều đầu tiên, điều bạn nghĩ đến, khi viết mã, bạn để lại "điểm neo", mục đích duy nhất của nó là làm cho việc gỡ lỗi dễ dàng hơn.

SomeClass Func() {
    // ...stuff...
    var ret = FinalComputationResult(thing, foo, bar);
    // ret is unused, but while debugging allows checking return value.
    return ret;
}

Ở đây nó phụ thuộc vào mức độ phức tạp stuffvà mức độ liên quan đến giá trị được trả về.

Là một "Nguyên tắc vàng", tôi sẽ nói như sau:

Nếu nó giúp hiểu được mục đích của mã, bạn có thể không bị thừa trong mã của mình

hoặc nói cách khác:

Viết mã của bạn dưới dạng dự phòng miễn phí là cần thiết để hiểu sau này dễ dàng, mã đang làm gì

Điều đó dẫn đến: Hầu hết thời gian, bạn nên xóa các biến "gỡ lỗi" .


19

Vấn đề lớn nhất là sự rõ ràng . Nếu mã của bạn có một đống rác ngoại lai trong đó và tôi đang duy trì mã của bạn, tôi phải tìm ra mọi thứ làm gì.

Là biến đó bao giờ được sử dụng cho bất cứ điều gì? Có lẽ bạn thực hiện các thao tác trên nó, nhưng không bao giờ sử dụng giá trị của nó cho một cái gì đó. Chỉ cần tăng một biến không có nghĩa là biến đó phục vụ mục đích nếu bạn không bao giờ đọc nó (trả về, nhập vào một biểu thức khác, et al).

Tuy nhiên: nếu một biến có mục đích và được đặt tên một cách thích hợp thì nó không làm mất đi toàn bộ mã.

Đưa ra các ví dụ trong câu hỏi cập nhật của bạn và một số người khác tôi nghĩ:

  • Có một chức năng gọi một chức năng khác, lưu trữ kết quả, ghi lại nó, sau đó trả về nó là khá ngắn và rõ ràng.

  • Việc tách một câu lệnh có nhiều biểu thức thành nhiều câu lệnh (ví dụ: tách một phép tính dài, phức tạp thành nhiều câu lệnh với nhiều biến trung gian) có thể làm cho mã rõ ràng hơn mặc dù dài dòng hơn. Với ít thông tin để xử lý tại một thời điểm, bộ não có thể dễ dàng dò dẫm những gì đang diễn ra.

  • Không sử dụng ngoại lệ là hoàn toàn tốt: hầu hết các ngôn ngữ yêu cầu chỉ định ngoại lệ bị bắt bao gồm cung cấp tên biến được sử dụng trong catchkhối. Không có cách nào xung quanh điều này trong nhiều ngôn ngữ phổ biến và các lập trình viên đã quen với nó.

Nếu tôi cần dành thời gian để tìm ra các yếu tố mã nào có mục đích và điều đó chỉ làm lãng phí thời gian của tôi, năng suất của tôi sẽ giảm. Tuy nhiên, nếu mã khá ngắn gọn và các biến được đặt tên tốt ngay cả khi chúng có vẻ không liên quan lúc đầu, điều này sẽ giảm thiểu rủi ro lãng phí thời gian không cần thiết để xem lại mã để hiểu mã.

Mã xấu với các biến không liên quan, các khối trống và mã chết là một cách mà các nhà phát triển nhận được tiếng xấu xung quanh văn phòng: "Tôi đã sửa một lỗi trong mã của Snowman. Tôi đã dành hai giờ để tìm ra chức năng đó đang làm gì và ba mươi giây để sửa lỗi! Snowman rất tệ trong lập trình! " Nhưng nếu mã phục vụ một mục đích và được viết một cách rõ ràng, nó hoàn toàn ổn.


9
+1 cho "Người tuyết rất tệ trong lập trình." Tôi luôn nghi ngờ. Làm thế nào bạn có thể trở thành một lập trình viên giỏi khi ngón tay của bạn luôn tan chảy?
Robert Harvey

Xem chỉnh sửa của tôi - Tôi không có nghĩa là các biến đơn thuần được tạo ra không có mục đích, chỉ là các biến có thể hỗ trợ ở đây và ở đó trong quá trình gỡ lỗi hoặc chỉ được tạo bởi một trong những công cụ tự động như khối bắt.
Tar

1
@Tar thay đổi toàn bộ câu hỏi - chỉnh sửa đến.

Lưu ý rằng trong danh sách gạch đầu dòng của bạn khi bạn thực hiện việc này, hai lần đầu tiên có xu hướng không thực sự dẫn đến cảnh báo (Tôi chưa bao giờ thấy một ngôn ngữ nào tạo ra cảnh báo trong trường hợp như vậy). Đối với trường hợp thứ ba, bất kỳ ngôn ngữ nào yêu cầu ngoại lệ đều được cung cấp một mã định danh không có cảnh báo cho nó và bất kỳ ngôn ngữ nào tạo ra cảnh báo cho nó đều không yêu cầu nó phải có mã định danh (một lần nữa, tôi quen thuộc với dù sao).
Phục vụ

2
Nhìn vào lịch sử sửa đổi, tôi không thấy bất kỳ dấu hiệu nào của câu hỏi thay đổi căn bản. Theo như mã của OP, hai cái đầu tiên sẽ dẫn đến cảnh báo bằng C # (có vẻ là ngôn ngữ được sử dụng). Ví dụ thứ ba sẽ không dẫn đến một cảnh báo. Các ý kiến ​​về câu hỏi cũng chỉ ra rằng chúng được chỉ định cụ thể trong các cảnh báo của trình biên dịch và khi Robert chỉ ra rằng ví dụ thứ ba không tạo ra cảnh báo, tác giả thừa nhận rằng đó là một ví dụ tồi cho câu hỏi của họ.
Phục vụ

5

Các biến không được sử dụng không phục vụ mục đích rõ ràng là một mùi mã trong quan điểm của tôi. Tốt nhất, chúng có thể là một vật gây xao lãng - chúng thêm vào tiếng ồn chung trong mô-đun.

Trường hợp xấu nhất là các lập trình viên tiếp theo dành thời gian để tìm ra những gì nó phải làm và tự hỏi liệu mã đã hoàn thành. Làm cho mình (và mọi người khác) một ân huệ và thoát khỏi.


1
Một "lỗi" trong quan điểm của bạn là gì? Các biến không được sử dụng không tạo ra kết quả bất ngờ, sai lầm cho mỗi se, đó là điều mà hầu hết mọi người sẽ coi là một lỗi.
Harris

5
Tại sao biến không được sử dụng? Rất có thể bởi vì nó đáng lẽ đã được sử dụng, nhưng một biến khác đã được sử dụng thay vì nhầm lẫn. Bạn nhận được một cảnh báo trình biên dịch, và bạn sửa nó và sửa lỗi cùng một lúc. Vấn đề là nếu bạn có một lập trình viên vô kỷ luật để lại một mớ hỗn độn, bạn không thể tìm thấy nơi cảnh báo đó chỉ ra một lỗi và nơi nó chỉ ra một lập trình viên lộn xộn.
gnasher729

@HarrisWeinstein Cho những người thử nghiệm và nhà phát triển thậm chí không thể đồng ý với lỗi là gì trong hầu hết thời gian, tôi sẽ đến đó ngay bây giờ. Đủ để nói rằng đó là một thiếu sót trong mã - và có thể là thực thi vì nó sẽ chiếm không gian. Phải thừa nhận rằng, không phải là vấn đề lớn nhất trên thế giới mà ở đó với hộp bình luận đánh vần sai chính tả và nhận xét mã. Đó là cruft mà không thêm gì nên được gỡ bỏ. Mã có vẻ tốt truyền cảm hứng cho sự tự tin. Tôi nghĩ rằng báo giá này cũng thích hợp và bao gồm quá trình tái cấu trúc tốt.
Robbie Dee

Nếu bạn đang sử dụng ngôn ngữ động, việc gán giá trị cho some_varkhi phần còn lại của mã sử dụng someVargần như được đảm bảo là một lỗi. Điều này có thể không phải là vấn đề trong Java hoặc C nhưng nó có thể dễ dàng phá vỡ một số Python.
Sean McS Something 18/1/17

1
@ThomasJunk Đó có lẽ là một thuật ngữ tốt hơn cho nó - cảm ơn bạn. Tôi sẽ điều chỉnh câu trả lời của tôi cho phù hợp.
Robbie Dee

5

Các biến không được sử dụng làm cho ý định mã của bạn không rõ ràng. Điều này là xấu bởi vì mặc dù xuất hiện, mã chủ yếu được viết cho mọi người đọc, không phải cho máy tính .

Những người khác đã chỉ ra rằng việc xây dựng một giá trị và không sử dụng nó làm cho những người khác phải đọc và làm việc với mã của bạn nhầm lẫn. Tuy nhiên, theo quan điểm của tôi, mối nguy hiểm lớn hơn là cho chính bạn .

Một biến không được sử dụng có thể là cố ý hoặc nó có thể là một sự giám sát chỉ ra một khiếm khuyết. Chẳng hạn, bạn có thể đã nhập nhầm tên và lưu trữ một giá trị ở một nơi khi bạn nghĩ rằng bạn đã lưu nó ở một nơi khác. Chương trình kết quả có thể chạy tốt nhưng âm thầm đưa ra kết quả sai.

Phân tích luồng dữ liệu có thể giúp bạn tìm ra các lỗi như vậy và nhiều lỗi khác. Do đó, nó trả tiền để viết mã của bạn theo cách mà mọi thứ mà một bộ phân tích luồng dữ liệu chỉ ra là sự bất thường, trên thực tế, là một lỗi. Hỗ trợ tự động trong việc ngăn chặn lỗi là vô giá; nhiều người nghĩ rằng "Ồ, tôi không cần sự giúp đỡ, tôi sẽ không bao giờ bất cẩn như vậy", nhưng cho đến nay mọi người tôi đã gặp đều nghĩ rằng điều đó là sai.


2

Có một kiểu mã hóa liên quan đến việc cố tình gán bất cứ thứ gì đã (hoặc có thể trở thành) quan tâm cho một biến cho mục đích cụ thể là dễ dàng xem xét nó trong trình gỡ lỗi. Điều này đặc biệt hữu ích cho mã trông giống như:

return foo(bar(), baz(wot(12), wombat(&badger)));

Ngay cả với các tên tốt hơn cho các chức năng, có thể dễ dàng tìm ra những gì sai trong cuộc gọi đến foo khi được viết là:

auto awombat = wombat(&badger);
auto awot = wot(12);
auto abaz = baz(awot, abadger);
auto abar = bar();
auto afoo = foo(abar, abaz);
return afoo;

Tôi vẫn chưa làm việc với những người thực hành điều này như cấu hình mặc định, nhưng viết lại một đoạn mã cứng đầu từ chối không có ý nghĩa gì trong hình thức chuyển nhượng đơn lẻ có thể giúp dễ dàng tìm ra những gì đang diễn ra theo trình gỡ lỗi. Chúng tôi luôn hoàn nguyên mã trở lại định dạng nhỏ gọn, "đẹp" sau đó nhưng tôi tự hỏi liệu đó có phải là một lỗi không.

Giải pháp thay thế là đi lên và xuống ngăn xếp và hy vọng bạn không bước quá xa hoặc sử dụng các trình gỡ lỗi có thể đảo ngược (rất hiếm gặp).

Đây không phải là một chiến lược phổ biến, nhưng vì nó đã giúp tôi vượt qua một số lỗi vô lý, tôi không nghĩ rằng nó nên được viết ra vì bản chất là xấu.


Trong khi tôi có lẽ sẽ không đi xa như bạn đã thấy hình thức "đẹp" đầu tiên của bạn quá nhỏ gọn.
Loren Pechtel

Ngoại trừ việc không có một biến không sử dụng nào trong mã của bạn.
Florian F

Về mặt tích cực, nếu bạn nhận được một cảnh báo về các biến không được sử dụng, bạn sẽ biết rằng ở đâu đó trong sự chuyển đổi đó, bạn đã phạm phải một số sai lầm lớn. Mà sẽ dễ dàng để sửa chữa.
gnasher729

1

Đối với những người bao gồm mã kiểm tra đơn vị của họ trong cùng các dự án hoặc mô-đun như mã "thực" của họ, một trường không được sử dụng , như phương thức đối tượng, là một tín hiệu mạnh mẽ rằng đơn vị của bạn kiểm tra không kiểm tra mọi thứ. Điều này làm tăng khả năng nhà phát triển sẽ cố gắng sử dụng trường hoặc phương thức hiện không được sử dụng đó và gặp phải lỗi không được phát hiện cho đến lúc đó.

Một biến không được sử dụng trong chương trình con hoặc phương thức không cần thiết có thể chỉ ra rằng người lập trình có nghĩa là sử dụng nó, nhưng đang sử dụng một biến khác do nhầm lẫn (giả sử, sau khi dọn dẹp sau thao tác sao chép-dán).

Một biến không được sử dụng trong chương trình con tầm thường hơn có lẽ là không cần thiết, như những người khác đã trả lời. Đôi khi, nó được sử dụng trong một tuyên bố về vụn bánh mì hiện đang được bình luận:

SomeObject tmp = someMethod();
// printDebugInfoAbout (tmp);

... rõ ràng với nhãn cầu rằng nó được sử dụng ở đó và chỉ ở đó (nghĩa là someMethodcó tác dụng phụ quan trọng), nhưng IDE không biết điều đó và việc loại bỏ biến đó còn rắc rối hơn giá trị của nó. Tôi tạm thời sử dụng các bộ triệt cảnh báo trong những trường hợp như vậy.


1
Tôi đang tự hỏi trong trường hợp nào bạn muốn có mã nhận xét được cam kết với kho lưu trữ của bạn. Nhưng một tình huống tương tự phát sinh khi sử dụng biên dịch có điều kiện (chẳng hạn như khi sử dụng assertmacro trong C hoặc C ++). Cảnh báo biến không được sử dụng thực sự có thể là một phiền toái ở đó và đàn áp chúng là phản ứng hợp lý nhất, nếu bạn hỏi tôi.
5gon12eder

1
Tôi đã chỉnh sửa câu trả lời của mình, thêm một ví dụ rất sơ bộ về những gì tôi đã thấy trong quá khứ. Khối này có thể được chạy nhiều lần và một cái gì đó thu thập tất cả thông tin gỡ lỗi trong nhật ký để phân tích khi truy tìm vấn đề, nhưng việc in bị chậm và vì vậy nó thường bị tắt. Tôi có thể thay thế dòng đầu tiên someMethodvà mất thông tin về tmpnguồn gốc từ đâu. Hoặc tôi có thể cam kết một phiên bản sạch và quên rằng một số phiên bản trước đây có mẩu bánh mì hữu ích đó (và thiếu mã cần thiết được thêm vào trong các phiên bản sau). ... Tôi đã tìm kiếm một sự đánh đổi lý tưởng về điều này từ lâu rồi.
Paul Brinkley

Tôi hiểu rồi. Rõ ràng, ngôn ngữ bạn chọn không có bộ xử lý trước. ;-)
5gon12eder

Hiện tại, aye. :-) Mặc dù công bằng mà nói, tôi đã thấy một loại công cụ tương tự trong C và C ++, và cũng không dễ để loại bỏ các biến không sử dụng trong các trường hợp đó (cả phụ lục?). ... Việc dự án C / C ++ lớn cuối cùng của tôi được thực hiện vào thời điểm IDE không tồn tại (cảnh báo trình biên dịch yêu cầu chạy "gcc -pedantic") cũng không giúp ích được gì.
Paul Brinkley

0

Thật dễ dàng khi bạn viết mã để trộn lẫn hai biến. Bạn tính một biến B nhưng sau đó sử dụng thay vì một số biến A được tạo trước đó.

Vì vậy, một lý do có thể cho một biến không được sử dụng là có một lỗi trong mã của bạn. Đó là lý do tại sao trình biên dịch cảnh báo bạn. Nếu bạn "không làm" các biến không sử dụng, nó thậm chí là một tặng cho đã chết.

Khi bạn thấy một cảnh báo như vậy, bạn nên xác minh mã của mình và sửa nó hoặc xóa biến vi phạm. Nếu bạn không xóa nó, bạn sẽ ngừng chú ý đến những cảnh báo này và bạn cũng có thể vô hiệu hóa chúng hoàn toàn. Nhưng sau đó, bạn cuối cùng sẽ mất một buổi chiều gỡ lỗi mã vì một sai lầm ngớ ngẩ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.