Gần đây tôi đã nói chuyện về gỡ lỗi cho Cộng đồng Java Luân Đôn. Trong phần Hỏi & Đáp của buổi nói chuyện, có người đã hỏi tôi về cách tiếp cận Phát triển theo định hướng thử nghiệm của tôi. Trước đây, tôi nhìn môn tu luyện đó theo một cách tích cực hơn. Viết nhiều bài kiểm tra. Làm thế nào điều đó có thể là xấu?
Nhưng khi thời gian trôi qua, tôi nhìn nó ở một khía cạnh khác.
Tôi thấy nó là một công cụ rất hạn chế có các trường hợp sử dụng rất cụ thể. Nó không phù hợp với loại dự án tôi xây dựng và thường cản trở các quy trình trôi chảy mà lẽ ra nó phải thúc đẩy. Nhưng hãy quay lại một giây. Tôi thực sự thích bài đăng này phân tách các loại và sự cố trong TDD. Nhưng hãy đơn giản hóa nó một chút, hãy làm rõ rằng mọi bài PR đều phải có mức độ phủ sóng tốt. Đây không phải là TDD. Nó chỉ là lập trình tốt.
TDD còn hơn thế nữa. Trong đó, chúng ta cần xác định các ràng buộc và sau đó giải quyết vấn đề. Cách tiếp cận đó có tốt hơn để giải quyết vấn đề và sau đó xác minh các ràng buộc là chính xác không? Đó là tiền đề cốt lõi của TDD so với việc chỉ viết phạm vi kiểm tra tốt.
TDD là một cách tiếp cận thú vị. Nó đặc biệt hữu ích khi làm việc với các ngôn ngữ được gõ lỏng lẻo. Trong những tình huống đó, TDD thật tuyệt vời vì nó đóng vai trò của một trình biên dịch và kẻ nói dối nghiêm ngặt.
Có những trường hợp khác mà nó có ý nghĩa. Khi chúng tôi đang xây dựng một hệ thống có đầu vào và đầu ra được xác định rất rõ ràng. Tôi đã gặp rất nhiều trường hợp này khi xây dựng các khóa học và tài liệu. Khi làm việc với dữ liệu trong thế giới thực, điều này đôi khi xảy ra khi chúng ta có phần mềm trung gian xử lý dữ liệu và xuất dữ liệu ở định dạng được xác định trước.
Ý tưởng là xây dựng phương trình với các biến ẩn ở giữa. Sau đó, mã hóa trở thành điền vào phương trình. Nó rất thuận tiện trong những trường hợp như vậy. Mã hóa trở thành điền vào chỗ trống.
“Phát triển theo định hướng thử nghiệm LÀ Sổ sách kế toán kép. Cùng một kỷ luật. Cùng một lý luận. Cùng một kết quả." – Chú Bob Martin
Tôi cho rằng Kiểm tra hơi giống với sổ sách kế toán kép. Đúng. Chúng ta nên thử nghiệm. Câu hỏi đặt ra là chúng ta nên xây dựng mã của mình dựa trên các thử nghiệm của mình hay ngược lại? Ở đây câu trả lời không đơn giản như vậy.
Nếu chúng ta có một hệ thống tồn tại từ trước với các bài kiểm tra, thì TDD hoàn toàn có ý nghĩa trên thế giới. Nhưng thử nghiệm một hệ thống chưa được xây dựng. Có một số trường hợp nó có ý nghĩa, nhưng không thường xuyên như người ta nghĩ.
Yêu cầu lớn đối với TDD là “thiết kế của nó”. Các thử nghiệm thực sự là thiết kế hệ thống và sau đó chúng tôi triển khai thiết kế đó. Vấn đề với điều này là chúng ta cũng không thể gỡ lỗi một thiết kế. Trước đây tôi có làm dự án cho một công ty lớn của Nhật. Công ty này có một trong những bộ sách thiết kế phụ lục lớn nhất, chi tiết nhất. Dựa trên các thông số kỹ thuật thiết kế này, công ty đã xây dựng hàng nghìn bài kiểm tra. Chúng tôi đã phải vượt qua một số lượng lớn các bài kiểm tra với hệ thống của mình. Lưu ý rằng hầu hết thậm chí không tự động.
Các bài kiểm tra đã có lỗi. Có nhiều triển khai cạnh tranh nhưng không ai trong số họ tìm thấy lỗi trong các thử nghiệm. Tại sao? Tất cả đều sử dụng cùng một mã nguồn triển khai tham chiếu. Chúng tôi là nhóm đầu tiên bỏ qua điều đó và thực hiện triển khai phòng sạch. Nó kéo dài những lỗi này trong mã, một số trong số đó là lỗi hiệu suất nghiêm trọng đã ảnh hưởng đến tất cả các bản phát hành trước đó.
Nhưng vấn đề thực sự là tiến độ chậm. Công ty không thể tiến lên một cách nhanh chóng. Những người ủng hộ TDD sẽ nhanh chóng nhận xét rằng một dự án TDD dễ tái cấu trúc hơn vì các thử nghiệm đảm bảo cho chúng tôi rằng chúng tôi sẽ không có hồi quy. Nhưng điều này áp dụng cho các dự án có thử nghiệm được thực hiện sau khi thực tế.
TDD tập trung nhiều vào thử nghiệm đơn vị nhanh. Việc chạy thử nghiệm tích hợp chậm hoặc thử nghiệm dài hạn có thể chạy qua đêm trên hệ thống TDD là không thực tế. Làm thế nào để bạn xác minh quy mô và tích hợp vào một hệ thống chính?
Trong một thế giới lý tưởng, mọi thứ sẽ chỉ cần nhấp vào vị trí giống như lego. Tôi không sống trong một thế giới như vậy, Các bài kiểm tra tích hợp thất bại nặng nề. Đây là những thất bại tồi tệ nhất với các lỗi khó theo dõi nhất. Tôi thà thất bại trong các bài kiểm tra đơn vị, đó là lý do tại sao tôi có chúng. Chúng rất dễ sửa chữa. Nhưng ngay cả với vùng phủ sóng hoàn hảo, họ cũng không kiểm tra kết nối đúng cách. Chúng tôi cần các bài kiểm tra tích hợp và họ tìm ra những lỗi khủng khiếp nhất.
Do đó, TDD nhấn mạnh quá mức vào các bài kiểm tra đơn vị “tốt để có”, hơn là các bài kiểm tra tích hợp thiết yếu. Vâng, bạn nên có cả hai. Nhưng tôi phải có các bài kiểm tra tích hợp. Những thứ đó không phù hợp hoàn toàn với quy trình TDD.
Tôi viết thử nghiệm theo cách tôi chọn trong từng trường hợp cụ thể. Nếu tôi gặp trường hợp thử nghiệm trước là điều đương nhiên, tôi sẽ sử dụng nó. Nhưng đối với hầu hết các trường hợp, việc viết mã trước có vẻ tự nhiên hơn đối với tôi. Việc xem lại các con số bao phủ là rất hữu ích khi viết bài kiểm tra và đây là điều tôi làm sau khi thực tế.
Như tôi đã đề cập trước đây, tôi chỉ kiểm tra phạm vi bảo hiểm cho các bài kiểm tra tích hợp. Tôi thích các bài kiểm tra đơn vị và theo dõi mức độ phù hợp ở đó vì tôi cũng muốn có mức độ phù hợp tốt ở đó. Nhưng đối với chất lượng, chỉ có các bài kiểm tra tích hợp mới quan trọng. PR cần các bài kiểm tra đơn vị, tôi không quan tâm liệu chúng tôi có viết chúng trước khi triển khai hay không. Chúng ta nên đánh giá kết quả.
Khi Tesla đang xây dựng các nhà máy Model 3, nó đã rơi vào tình trạng sản xuất tồi tệ. Nguồn gốc của các vấn đề là nỗ lực của họ để tự động hóa mọi thứ. Nguyên tắc Pareto áp dụng hoàn hảo cho tự động hóa. Một số thứ rất khó tự động hóa và làm cho toàn bộ quá trình trở nên tồi tệ hơn rất nhiều.
Một điểm mà điều này thực sự không thành công là trong thử nghiệm giao diện người dùng. Các giải pháp như Selenium, v.v. đã đạt được những bước tiến lớn trong việc thử nghiệm giao diện người dùng web. Tuy nhiên, độ phức tạp là rất lớn và các bài kiểm tra rất mong manh. Chúng tôi kết thúc với các bài kiểm tra khó duy trì. Tồi tệ hơn, chúng tôi thấy giao diện người dùng khó tái cấu trúc hơn vì chúng tôi không muốn viết lại các bài kiểm tra.
Chúng tôi có thể vượt qua 80% chức năng đã thử nghiệm, nhưng có một điểm làm giảm lợi nhuận đối với tự động hóa. Trong những môi trường đó, TDD có vấn đề. Chức năng này rất dễ dàng nhưng việc xây dựng các bài kiểm tra trở nên không thể thực hiện được.
Tôi không chống lại TDD nhưng tôi không khuyên dùng nó và tôi không sử dụng nó một cách hiệu quả. Khi bắt đầu với một bài kiểm tra hợp lý, tôi có thể làm điều đó, nhưng đó không thực sự là TDD. Tôi đánh giá mã dựa trên kết quả. TDD có thể mang lại kết quả tuyệt vời nhưng nó thường nhấn mạnh quá mức vào các bài kiểm tra đơn vị. Các bài kiểm tra tích hợp quan trọng hơn đối với chất lượng trong thời gian dài.
Tự động hóa là tuyệt vời. Cho đến khi nó dừng lại. Có một điểm mà các bài kiểm tra tự động không có nhiều ý nghĩa. Chúng ta sẽ tiết kiệm được rất nhiều thời gian và công sức để chấp nhận điều đó và tập trung nỗ lực của mình vào một hướng hiệu quả.
Đây là từ sự thiên vị của tôi với tư cách là một nhà phát triển Java, những người thích các ngôn ngữ nghiêm ngặt, an toàn về kiểu. Các ngôn ngữ như JavaScript và Python có thể hưởng lợi từ số lượng bài kiểm tra lớn hơn vì tính linh hoạt của chúng. Do đó TDD có ý nghĩa hơn trong những môi trường đó.
Tóm lại, thử nghiệm là tốt. Mặc dù vậy, TDD không thực hiện các bài kiểm tra tốt hơn. Đó là một cách tiếp cận thú vị nếu nó phù hợp với bạn. Trong một số trường hợp, nó rất lớn. Nhưng ý tưởng rằng TDD là cần thiết hoặc thậm chí nó sẽ cải thiện đáng kể mã kết quả, không có ý nghĩa gì.
Cũng được xuất bản ở đây.