Cách xóa chức năng hoặc tính năng khi sử dụng TDD


20

Trong các văn bản về TDD, tôi thường đọc về "loại bỏ trùng lặp" hoặc "cải thiện khả năng đọc" trong bước tái cấu trúc. Nhưng điều gì làm cho tôi loại bỏ một chức năng không sử dụng?

Ví dụ, giả sử có một lớp Cvới các phương thức a()b(). Bây giờ tôi nghĩ sẽ tốt hơn nếu có một phương pháp f()được hướng vào C. Trong thực tế, f()thay thế tất cả các cuộc gọi đến b()ngoại trừ các bài kiểm tra đơn vị được xác định / mô tả b(). Nó không cần thiết nữa - ngoại trừ các bài kiểm tra.

Là nó tiết kiệm để chỉ loại bỏ b()và tất cả các bài kiểm tra đã sử dụng nó? Đó có phải là một phần của "cải thiện khả năng đọc"?


3
Chỉ cần thêm một thử nghiệm khác để kiểm tra xem hàm có tồn tại không, và sau đó đi sửa các testcase bị lỗi;)
Filip Haglund

@FilipHaglund Tùy thuộc vào ngôn ngữ, điều này có thể có thể. Nhưng như tài liệu mã này sẽ trông lạ.
TobiMcNamobi

1
Chỉ dành cho bất cứ ai có thể không biết rõ hơn: bình luận của @ FilipHaglund rõ ràng là một trò đùa. Đừng làm vậy.
jhyot

Câu trả lời:


16

Phải, tất nhiên. Mã dễ đọc nhất là mã không có ở đó.

Điều đó nói rằng, tái cấu trúc thường có nghĩa là cải thiện mã mà không thay đổi hành vi của nó. Nếu bạn nghĩ về một cái gì đó cải thiện mã, chỉ cần làm điều đó. Không cần lắp nó vào lỗ chim bồ câu trước khi bạn được phép làm điều đó.


@ jpmc26 Nhanh nhẹn, đàn ông, nhanh nhẹn! :-)
TobiMcNamobi

1
"Mã dễ đọc nhất là mã không có ở đó." - Tôi đang treo câu nói đó trên tường: D
winkbrace

27

Loại bỏ một phương thức công khai không phải là "tái cấu trúc" - tái cấu trúc đang thay đổi việc thực hiện trong khi tiếp tục vượt qua các thử nghiệm hiện có.

Tuy nhiên, loại bỏ một phương pháp không cần thiết là một thay đổi thiết kế hoàn toàn hợp lý.

TDD rút ra điều này ở một mức độ nào đó, bởi vì khi xem xét các bài kiểm tra, bạn có thể thấy rằng nó đang thử nghiệm một phương pháp không cần thiết. Các bài kiểm tra đang thúc đẩy thiết kế của bạn, bởi vì bạn có thể đi "Nhìn này, bài kiểm tra này không liên quan gì đến mục tiêu của tôi".

Nó có thể tiết lộ nhiều hơn ở các cấp độ thử nghiệm cao hơn, kết hợp với các công cụ bao phủ mã. Nếu bạn chạy thử nghiệm tích hợp với phạm vi bảo hiểm mã và thấy rằng các phương thức không được gọi, đó là một đầu mối mà phương thức không được sử dụng. Phân tích mã tĩnh cũng có thể chỉ ra rằng các phương thức không được sử dụng.

Có hai cách tiếp cận để loại bỏ một phương thức; cả hai đều làm việc trong những hoàn cảnh khác nhau:

  1. Xóa phương thức. Thực hiện theo các lỗi biên dịch, để xóa bất kỳ mã phụ thuộc và kiểm tra. Nếu bạn hài lòng rằng các xét nghiệm bị ảnh hưởng là dùng một lần, hãy cam kết thay đổi của bạn. Nếu không, cuộn lại.

  2. Xóa các bài kiểm tra mà bạn cảm thấy đã lỗi thời. Chạy toàn bộ bộ thử nghiệm của bạn với phạm vi bảo hiểm mã. Xóa các phương thức chưa được thực hiện bởi bộ thử nghiệm.

(Điều này giả định rằng bộ thử nghiệm của bạn có phạm vi bảo hiểm tốt để bắt đầu).


10

Trong thực tế, f () thay thế tất cả các lệnh gọi đến b () ngoại trừ các thử nghiệm đơn vị đã xác định / mô tả b ()

IMHO chu trình TDD điển hình sẽ như thế này:

  • viết các bài kiểm tra thất bại cho f () (có thể dựa trên các bài kiểm tra cho b ()): các bài kiểm tra chuyển sang màu đỏ

  • thực hiện f () -> kiểm tra trở thành màu xanh

  • refactor : -> xóa b () và tất cả các thử nghiệm cho b ()

Bước cuối cùng, bạn có thể xem xét loại bỏ b () trước và xem điều gì xảy ra (khi sử dụng ngôn ngữ được biên dịch, trình biên dịch chỉ nên phàn nàn về các thử nghiệm hiện có, khi không, các thử nghiệm đơn vị cũ cho b sẽ thất bại, vì vậy nó là rõ ràng bạn cũng phải loại bỏ chúng).


4

Vâng, nó là.

Mã tốt nhất, không có lỗi nhất, dễ đọc nhất là mã không tồn tại. Cố gắng viết càng nhiều mã càng tốt trong khi đáp ứng yêu cầu của bạn.


9
Bạn đã bỏ lỡ phần "làm thế nào để".
JeffO

2

Bạn nên xóa đi b()một khi nó không còn được sử dụng, vì lý do tương tự rằng nó mong muốn không thêm các chức năng không được sử dụng ở nơi đầu tiên. Cho dù bạn gọi nó là "khả năng đọc" hay cái gì khác, tất cả những thứ khác đều bằng nhau, đó là một cải tiến cho mã mà nó không chứa bất cứ thứ gì nó không sử dụng. Vì lợi ích của việc có ít nhất một biện pháp cụ thể mà tốt hơn là không nên có nó, loại bỏ nó đảm bảo rằng chi phí bảo trì trong tương lai của nó sau khi thay đổi đó bằng không!

Tôi chưa tìm thấy bất kỳ kỹ thuật đặc biệt nào cần thiết để thực sự loại bỏ nó bằng các thử nghiệm của nó, vì mọi suy nghĩ thay thế b()bằng một thứ mới tất nhiên phải đi kèm với việc xem xét tất cả các mã hiện đang gọi b()và các thử nghiệm là một tập hợp con của "tất cả mã ".

Dòng lý luận thường hoạt động với tôi là tại thời điểm mà tôi nhận thấy f()đã b()bị lỗi thời, do đó, b()ít nhất nên bị phản đối, và tôi đang tìm kiếm tất cả các cuộc gọi b()với ý định thay thế chúng bằng các cuộc gọi đến f(), tôi cũng xem xét mã kiểm tra . Cụ thể, nếu b()không còn cần thiết thì tôi có thể và nên loại bỏ các bài kiểm tra đơn vị của nó.

Bạn hoàn toàn chính xác rằng không có gì buộc tôi phải chú ý rằng điều đó b()không còn cần thiết nữa. Đó là vấn đề về kỹ năng (và, như mỏng nói, báo cáo bảo hiểm mã trong các bài kiểm tra cấp cao hơn). Nếu chỉ kiểm tra đơn vị và không có kiểm tra chức năng, hãy tham khảo b(), sau đó tôi có thể lạc quan một cách thận trọng rằng nó không phải là một phần của bất kỳ giao diện được xuất bản nào và do đó loại bỏ nó không phải là một thay đổi vi phạm đối với bất kỳ mã nào không thuộc quyền kiểm soát trực tiếp của tôi.

Chu trình đỏ / xanh / tái cấu trúc không đề cập rõ ràng đến việc xóa các kiểm tra. Hơn nữa, loại bỏ b()vi phạm nguyên tắc mở / đóng vì rõ ràng thành phần của bạn đang mở để sửa đổi. Vì vậy, nếu bạn muốn nghĩ về bước này như một cái gì đó bên ngoài TDD đơn giản, hãy tiếp tục. Ví dụ: bạn có thể có một số quy trình để khai báo một bài kiểm tra "xấu", có thể được áp dụng trong trường hợp này để xóa bài kiểm tra với lý do nó kiểm tra một thứ không nên có (hàm không cần thiết b()).

Tôi nghĩ rằng trong thực tế, hầu hết mọi người có thể cho phép thực hiện một số lượng thiết kế lại nhất định cùng với chu trình đỏ / xanh / tái cấu trúc hoặc họ coi việc loại bỏ các bài kiểm tra đơn vị dư thừa là một phần hợp lệ của "tái cấu trúc" mặc dù nói đúng nó không phải là tái cấu trúc Nhóm của bạn có thể quyết định bao nhiêu kịch tính và giấy tờ nên tham gia để chứng minh cho quyết định này.

Dù sao, nếu b()quan trọng thì sẽ có các thử nghiệm chức năng cho nó và những thử nghiệm đó sẽ không bị loại bỏ nhẹ, nhưng bạn đã nói rằng chỉ có các thử nghiệm đơn vị. Nếu bạn không phân biệt chính xác giữa các thử nghiệm đơn vị (được viết theo thiết kế bên trong hiện tại của mã mà bạn đã thay đổi) và thử nghiệm chức năng (được viết thành giao diện được xuất bản, có lẽ bạn không muốn thay đổi) thì bạn cần thận trọng hơn về việc loại bỏ các bài kiểm tra đơn vị.


2

Một điều cần luôn cố gắng ghi nhớ là hiện tại chúng tôi đang sử dụng các bản sửa lỗi MÃ với KIỂM SOÁT PHIÊN BẢN. Mã bị xóa đó không thực sự biến mất ... nó vẫn còn ở đâu đó trong lần lặp trước. Vì vậy, thổi nó đi! Hãy tự do với phím xóa, bởi vì bạn luôn có thể quay lại và truy xuất phương thức tao nhã quý giá mà bạn nghĩ có thể sẽ hữu ích vào một ngày nào đó ... nếu một ngày nào đó sẽ đến. Nó đây rồi.

Tất nhiên, điều đó đi cùng với sự cảnh giác của các căn bệnh và sự nguy hiểm của các bản phát hành không tương thích ngược ... các ứng dụng bên ngoài dựa trên việc triển khai giao diện của bạn, hiện đang bị mồ côi bởi mã (không được chấp nhận) của bạn.


Xóa mã không phải là một vấn đề nói chung. Tôi thích xóa để xóa các dòng, chức năng, hoặc ... tốt, toàn bộ mô-đun! Nếu có thể. Và tôi làm tất cả điều này có hoặc không có TDD. Nhưng: Có một điểm trong quy trình làm việc TDD nơi mã (không phải dupli) bị xóa không? Nếu không, nó sẽ bị xóa. Nhưng có phải không? Đó là câu hỏi của tôi.
TobiMcNamobi
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.