Làm cách nào để có được API ban đầu bằng cách sử dụng TDD?


12

Đây có thể là một câu hỏi khá ngớ ngẩn vì tôi đang ở những nỗ lực đầu tiên của mình tại TDD. Tôi yêu cảm giác tự tin mà nó mang lại và nói chung là cấu trúc mã tốt hơn nhưng khi tôi bắt đầu áp dụng nó vào một cái gì đó lớn hơn các ví dụ đồ chơi một lớp, tôi gặp khó khăn.

Giả sử, bạn đang viết một thư viện các loại. Bạn biết những gì nó phải làm, bạn biết một cách chung về cách nó được triển khai (kiến trúc khôn ngoan), nhưng bạn cứ "khám phá" rằng bạn cần thay đổi API công khai khi bạn viết mã. Có lẽ bạn cần chuyển đổi phương thức riêng tư này thành mô hình chiến lược (và bây giờ cần phải vượt qua một chiến lược bị chế giễu trong các thử nghiệm của bạn), có lẽ bạn đã đặt sai trách nhiệm ở đây và ở đó và chia một lớp hiện có.

Khi bạn đang cải thiện mã hiện có, TDD có vẻ rất phù hợp, nhưng khi bạn viết mọi thứ từ đầu, API bạn viết kiểm tra sẽ hơi "mờ" trừ khi bạn thiết kế lớn trước. Bạn làm gì khi bạn đã có 30 bài kiểm tra về phương pháp có chữ ký của nó (và đối với phần đó, hành vi) đã thay đổi? Đó là rất nhiều thử nghiệm để thay đổi một khi chúng cộng lại.


3
30 thử nghiệm trên một phương pháp? Âm thanh như phương pháp đó có quá nhiều phức tạp, hoặc bạn đang viết quá nhiều bài kiểm tra.
Minthos

Vâng, tôi có thể đã phóng đại một chút để bày tỏ quan điểm của mình. Sau khi kiểm tra mã, tôi thường có ít hơn 10 phương thức cho mỗi thử nghiệm với hầu hết các phương thức đều dưới 5. Nhưng toàn bộ phần "quay lại và thay đổi chúng" đã khá bực bội.
Vytautas Mackonis

6
@Minthos: Tôi có thể nghĩ ra 6 bài kiểm tra trên đỉnh đầu rằng bất kỳ phương pháp nào lấy chuỗi thường sẽ thất bại hoặc hoạt động kém so với bản viết đầu tiên (null, trống, quá dài, không được định vị đúng, tỷ lệ hoàn hảo kém) . Tương tự cho các phương pháp lấy một bộ sưu tập. Đối với một phương pháp không tầm thường, 30 âm thanh lớn, nhưng không quá phi thực tế.
Steven Evers

Câu trả lời:


13

Những gì bạn gọi là "thiết kế lớn lên phía trước" tôi gọi "lập kế hoạch hợp lý cho kiến ​​trúc lớp học của bạn."

Bạn không thể phát triển một kiến ​​trúc từ các bài kiểm tra đơn vị. Ngay cả chú Bob nói thế.

Nếu bạn không suy nghĩ về kiến ​​trúc, nếu những gì bạn đang làm thay vào đó là bỏ qua kiến ​​trúc và ném các bài kiểm tra lại với nhau và khiến chúng vượt qua, bạn sẽ phá hủy thứ sẽ cho phép tòa nhà đứng vững vì đó là sự tập trung vào cấu trúc của hệ thống và các quyết định thiết kế vững chắc đã giúp hệ thống duy trì tính toàn vẹn cấu trúc của nó.

http://s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf , Trang 4

Tôi nghĩ sẽ hợp lý hơn khi tiếp cận TDD từ góc độ xác nhận thiết kế kết cấu của bạn. Làm thế nào để bạn biết thiết kế không chính xác nếu bạn không thử nghiệm nó? Và làm thế nào để bạn xác minh rằng những thay đổi của bạn là chính xác mà không thay đổi các thử nghiệm ban đầu?

Phần mềm "mềm" chính xác vì nó có thể thay đổi. Nếu bạn không thoải mái về số lượng thay đổi, hãy tiếp tục tích lũy kinh nghiệm trong thiết kế kiến ​​trúc và số lượng thay đổi bạn sẽ cần thực hiện đối với kiến ​​trúc ứng dụng của bạn sẽ giảm theo thời gian.


Vấn đề là, ngay cả với "kế hoạch hợp lý", bạn mong đợi rất nhiều thay đổi. Tôi thường để nguyên khoảng 80% kiến ​​trúc ban đầu của mình với một số thay đổi ở giữa. 20% đó là những gì làm phiền tôi.
Vytautas Mackonis

2
Tôi nghĩ đó chỉ là bản chất của phát triển phần mềm. Bạn không thể mong đợi có được toàn bộ kiến ​​trúc ngay lần thử đầu tiên.
Robert Harvey

2
+1 và nó không đối nghịch với TDD. TDD bắt đầu khi bạn bắt đầu viết mã, chính xác là khi thiết kế kết thúc. TDD có thể giúp bạn thấy những gì bạn đã bỏ lỡ trong thiết kế của mình, cho phép bạn cấu trúc lại thiết kế và triển khai và tiếp tục.
Steven Evers

2
Thật ra theo Bob (và tôi đồng ý với anh ta hết lòng) viết mã là thiết kế. Có một kiến ​​trúc cấp cao chắc chắn là cần thiết nhưng thiết kế không kết thúc khi bạn viết mã.
Michael Brown

Câu trả lời thực sự tốt mà đánh vào đầu đinh. Tôi thấy rất nhiều người, cả cho và chống TDD, những người dường như "không thiết kế lớn lên phía trước" là "không thiết kế gì cả, chỉ là mã" khi nó thực sự là một cuộc tấn công chống lại các giai đoạn thiết kế thác nước điên rồ cũ. Thiết kế luôn là một khoản đầu tư thời gian tốt và rất quan trọng cho sự thành công của bất kỳ dự án không tầm thường nào.
sara

3

Nếu bạn làm TDD. Bạn không thể thay đổi chữ ký và hành vi mà không cần phải kiểm tra nó. Vì vậy, 30 bài kiểm tra thất bại đã bị xóa trong quá trình hoặc thay đổi / tái cấu trúc cùng với mã. Hoặc bây giờ chúng đã lỗi thời, an toàn để xóa.

Bạn không thể bỏ qua 30 lần màu đỏ trong chu kỳ tái cấu trúc màu đỏ-xanh lá cây của bạn?

Các thử nghiệm của bạn nên được tái cấu trúc dọc theo mã sản xuất của bạn. Nếu bạn có đủ khả năng, hãy chạy lại tất cả các thử nghiệm sau mỗi thay đổi.

Đừng ngại xóa các bài kiểm tra TDD. Một số thử nghiệm kết thúc thử nghiệm các khối xây dựng để đạt được kết quả mong muốn. Kết quả mong muốn ở cấp độ chức năng là những gì được tính. Các thử nghiệm xung quanh các bước trung gian trong thuật toán bạn đã chọn / phát minh có thể có hoặc không có nhiều giá trị khi có nhiều cách để đạt được kết quả hoặc ban đầu bạn rơi vào ngõ cụt.

Đôi khi bạn có thể tạo một số bài kiểm tra tích hợp tốt, giữ chúng và xóa phần còn lại. Nó phần nào phụ thuộc vào việc bạn làm việc từ trong ra ngoài hay từ trên xuống và bạn thực hiện những bước lớn như thế nào.


1

Như Robert Harvey vừa nói, có lẽ bạn đang cố gắng sử dụng TDD cho một thứ cần được xử lý bởi một công cụ khái niệm khác (đó là: "thiết kế" hoặc "mô hình hóa").

Cố gắng thiết kế (hoặc "mô hình") hệ thống của bạn theo một cách khá trừu tượng ("chung chung", "mơ hồ"). Ví dụ: nếu bạn phải tạo mô hình một chiếc ô tô, chỉ cần có một lớp xe với một số phương thức và lĩnh vực mơ hồ, như startEngine () và int ghế. Đó là: mô tả những gì bạn muốn phơi bày ra công chúng , chứ không phải cách bạn muốn thực hiện nó. Cố gắng chỉ hiển thị các chức năng cơ bản (đọc, viết, bắt đầu, dừng, v.v.) và để lại mã khách hàng được xây dựng trên đó (Chuẩn bị MyScene (), killTheEnemy (), v.v.).

Viết các bài kiểm tra của bạn giả sử giao diện công cộng đơn giản này.

Thay đổi hành vi nội bộ của các lớp và phương thức của bạn bất cứ khi nào bạn cần.

Nếu và khi bạn cần thay đổi giao diện công cộng và bộ thử nghiệm của mình, hãy dừng lại và suy nghĩ. Rất có thể đây là một dấu hiệu cho thấy có gì đó không đúng trong API của bạn và trong thiết kế / mô hình hóa của bạn.

Việc thay đổi API không phải là bất thường. Hầu hết các hệ thống ở phiên bản 1.0 của chúng đều cảnh báo rõ ràng cho các lập trình viên / người dùng trước những thay đổi có thể có trong API của họ. Mặc dù vậy, một luồng thay đổi API liên tục, không được kiểm soát là dấu hiệu rõ ràng của thiết kế xấu (hoặc hoàn toàn thiếu).

BTW: Bạn thường chỉ nên có một số ít các bài kiểm tra cho mỗi phương pháp. Một phương pháp, theo định nghĩa, nên thực hiện một "hành động" được xác định rõ ràng trên một số loại dữ liệu. Trong một thế giới hoàn hảo, đây sẽ là một hành động tương ứng với một thử nghiệm duy nhất. Trong thế giới thực, không có gì bất thường (và không sai) khi có một vài "phiên bản" khác nhau của cùng một hành động và một vài thử nghiệm tương ứng khác nhau. Để chắc chắn, bạn nên tránh để có 30 bài kiểm tra trên cùng một phương pháp. Đây là một dấu hiệu rõ ràng cho thấy phương thức này cố gắng làm quá nhiều (và mã nội bộ của nó được phát triển ngoài tầm kiểm soát).


0

Tôi nhìn nó từ quan điểm của người dùng. Ví dụ: nếu API của bạn cho phép tôi tạo một đối tượng Person có tên và tuổi, thì tốt hơn nên có một hàm tạo (tên chuỗi, int age) và phương thức truy cập cho tên và tuổi. Thật đơn giản để tạo trường hợp thử nghiệm cho Người mới có và không có tên và tuổi.

đôi

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.