2009-12-31 37 views
15

Tôi có một nắm bắt tốt về kiểm tra đơn vị, DI, mocks, và tất cả sự tốt đẹp chính thiết kế cần phải có gần như mã đầy đủ như con người có thể (chính trách nhiệm duy nhất, suy nghĩ 'làm thế nào tôi sẽ kiểm tra điều này' như tôi mã, v.v ...).thiết kế ứng dụng có kích thước trung bình lớn khi thực hiện TDD?

Ứng dụng gần đây nhất của tôi, tôi không mã thực hiện TDD thực. Tôi đã kiểm tra đơn vị trong tâm trí khi tôi mã hóa, và viết các bài kiểm tra của tôi sau khi viết mã, tái cấu trúc, vv .. Tôi đã làm TDD khi nó 'dễ' để làm ... tuy nhiên tôi đã không nắm bắt tốt như Tôi làm ngay bây giờ ... Đó là dự án đầu tiên tôi sử dụng đầy đủ các khung công tác DI, mocking, vv và lần đầu tiên có toàn bộ mã bảo mật - và tôi đã học được rất nhiều từ nó khi tôi đi cùng. Tôi đang ngứa để được giao cho dự án tiếp theo của tôi vì vậy tôi có thể mã nó hoàn toàn làm TDD từ đầu.

Tôi biết đây là một câu hỏi rộng, và tôi đã ra lệnh TDD bằng ví dụ và XP Unleashed, nhưng tôi hy vọng cho một tổng quan ngắn gọn về cách bạn thiết kế/viết một ứng dụng lớn làm TDD.

Bạn có viết toàn bộ đơn đăng ký, không sử dụng gì ngoài phân tích mã không? (ví dụ: viết tất cả các chữ ký chức năng, giao diện, cấu trúc và viết toàn bộ ứng dụng nhưng không viết bất kỳ triển khai thực tế nào)? Tôi có thể hình dung nó hoạt động ở kích thước nhỏ giữa, nhưng điều này thậm chí có thể trên các ứng dụng lớn?

Nếu không, bạn sẽ viết kiểm tra đơn vị đầu tiên của mình cho hàm mức cao nhất trong hệ thống bằng cách nào? Cho phép nói ví dụ - trên một dịch vụ web, nơi bạn có một chức năng gọi là DoSomethingComplicated (param1, ..., param6) tiếp xúc với thế giới. Rõ ràng, việc viết bài kiểm tra đầu tiên cho một hàm đơn giản như AddNumbers() là tầm thường - nhưng khi hàm ở trên cùng của ngăn xếp cuộc gọi như thế này?

Bạn vẫn thiết kế trước? Rõ ràng bạn vẫn muốn làm thiết kế 'kiến trúc' - ví dụ, biểu đồ luồng hiển thị IE nói chuyện với IIS nói chuyện với một dịch vụ cửa sổ qua WCF nói về Cơ sở dữ liệu SQL ... một ERD hiển thị tất cả các bảng SQL và các trường của chúng, vv ... nhưng những gì về thiết kế lớp học? Tương tác giữa các lớp, v.v. Bạn có thiết kế này lên phía trước, hoặc chỉ tiếp tục viết mã stub, tái cấu trúc các tương tác khi bạn đi cùng, cho đến khi toàn bộ điều kết nối và trông giống như nó sẽ làm việc?

Bất cứ lời khuyên được nhiều đánh giá

Trả lời

12

Tôi có viết toàn bộ đơn đăng ký, không sử dụng gì ngoài phân tích mã không?

Không, không theo nghĩa nhỏ nhất - nghe có vẻ giống như một cách tiếp cận rất lãng phí. Chúng tôi phải luôn nhớ rằng lý do cơ bản để thực hiện TDD là phản hồi nhanh. Một bộ thử nghiệm tự động có thể cho chúng tôi biết nếu chúng tôi đã phá vỡ bất cứ điều gì nhanh hơn nhiều so với một thử nghiệm thủ công có thể.Nếu chúng ta đợi kết nối với nhau cho đến giây phút cuối cùng, chúng tôi không nhận được phản hồi nhanh - trong khi chúng tôi có thể nhận phản hồi nhanh từ các bài kiểm tra đơn vị của mình, chúng tôi sẽ không biết ứng dụng có hoạt động chung hay không. Bài kiểm tra đơn vị chỉ là một hình thức kiểm tra mà chúng tôi cần thực hiện để xác minh ứng dụng.

Một cách tiếp cận tốt hơn là bắt đầu với các tính năng quan trọng nhất và làm việc theo cách của bạn trong từ đó, sử dụng một từ ngoài vào trong cách tiếp cận. Điều này thường có nghĩa là bắt đầu với một số giao diện người dùng.

Cách tôi làm là tạo giao diện người dùng mong muốn. Vì chúng ta thường không thể phát triển giao diện người dùng với TDD, tôi chỉ cần tạo Chế độ xem với công nghệ được lựa chọn. Không có thử nghiệm ở đó, nhưng tôi kết nối giao diện người dùng với một số API (tốt nhất là sử dụng databinding khai báo), và đó là khi thử nghiệm bắt đầu.

Lúc đầu, tôi sẽ TDD Mô hình trình bày/mô hình hiển thị và bộ điều khiển tương ứng của mình, có thể mã hóa cứng một số phản hồi để thấy giao diện người dùng hoạt động. Ngay sau khi tôi có cái gì đó không phát nổ khi bạn chạy nó, tôi kiểm tra trong mã (nhớ, nhiều nhỏ check-in gia tăng).

Sau đó, tôi làm việc theo cách của mình theo chiều dọc xuống tính năng đó và đảm bảo rằng giao diện người dùng cụ thể này có thể đi tới nguồn dữ liệu (hoặc bất kỳ) nào, bỏ qua tất cả các tính năng khác.

Khi tính năng được thực hiện, tôi có thể bắt đầu tính năng tiếp theo. Cách tôi hình ảnh quá trình này là tôi điền vào các ứng dụng bằng cách làm một lát dọc tại một thời gian cho đến khi tất cả các tính năng được thực hiện.

Khởi động ứng dụng greenfield theo cách này luôn mất thêm thời gian dài cho tính năng đầu tiên vì đây là nơi bạn phải kết nối mọi thứ, vì vậy hãy chọn thứ gì đó đơn giản (như Chế độ xem ban đầu của ứng dụng) để giữ mọi thứ càng đơn giản càng tốt. Khi tính năng đầu tiên được thực hiện, những tính năng tiếp theo trở nên dễ dàng hơn nhiều vì các nền tảng hiện đã có sẵn.

Tôi vẫn thiết kế ở phía trước?

Không nhiều, không. Tôi thường có một thiết kế tổng thể trong tâm trí trước khi tôi bắt đầu, và khi tôi làm việc trong một nhóm, chúng tôi phác họa kiến ​​trúc tổng thể này trên một tấm bảng hoặc một bản chiếu trước khi chúng tôi bắt đầu.

này là nhiều hơn hoặc ít hơn giới hạn

  • Số lượng và tên của lớp (UI, trình bày logic, Domain Model, truy cập dữ liệu, vv).
  • Các công nghệ được sử dụng (WPF, ASP.NET MVC, SQL Server, .NET 3.5 hoặc không có điều gì)
  • Làm sao chúng ta cấu trúc mã sản xuất và mã kiểm tra, và những công nghệ chúng tôi sử dụng
  • yêu cầu chất lượng đối với các mã kiểm tra (lập trình ghép đôi, phân tích mã tĩnh, tiêu chuẩn mã hóa, v.v.)

Phần còn lại chúng tôi tìm ra khi chúng tôi đi, nhưng chúng tôi sử dụng nhiều phiên thiết kế đặc biệt tại bảng trắng khi chúng tôi đi cùng.

+0

Cảm ơn phản hồi tuyệt vời và chi tiết. Nghe có vẻ giống như cách tôi mã hóa ứng dụng cuối cùng của mình .. (ngoại trừ tôi 'lừa' viết bài kiểm tra đầu tiên ở hầu hết các địa điểm) Có lẽ chuyển đổi từ kiểm thử đơn vị sang TDD không thực sự thay đổi cách tôi thiết kế và kiến ​​trúc nhiều như tôi suy nghĩ ... Vì vậy, tôi phải hỏi - là bạn rất nghiêm ngặt với các bài kiểm tra đầu tiên? Bao giờ thấy rằng chỉ đơn giản, nó chỉ dễ dàng hơn để viết mã trước khi thử nghiệm? Nếu vậy, điều này xảy ra như thế nào? Và trong bất kỳ mẫu/tình huống cụ thể nào? – dferraro

+2

Tôi rất nghiêm khắc khi nói đến thử nghiệm đầu tiên, vì tôi thấy rằng giai đoạn * Red * của Red/Green/Refactor là rất quan trọng - Tôi thường viết một bài kiểm tra hóa ra thành màu xanh ngay lập tức, mặc dù ý định ngược lại. Điều này có nghĩa là thử nghiệm không kiểm tra những gì tôi nghĩ rằng nó đã được thử nghiệm, vì vậy nó phải được viết lại. Điều này xảy ra với tôi xấp xỉ. một lần một ngày, nhưng biện pháp bảo vệ này không có sẵn khi bạn viết các bài kiểm tra sau đó. Rất hiếm khi tôi tăng đột biến mà không thử nghiệm, nhưng khi điều đó xảy ra, tôi xóa mã tăng đột biến khi tôi hoàn tất và sau đó thực hiện đúng TDD dựa trên trải nghiệm tăng đột biến của tôi. –

1

1 câu hỏi Tốt

Tôi thật sự không biết câu trả lời, nhưng tôi sẽ bắt đầu với việc xây dựng các khối lớp mà tôi có thể kiểm tra sau đó xây dựng vào ứng dụng, không với các công cụ cấp cao nhất. Và có, tôi sẽ có một thiết kế thô sơ của các giao diện, nếu không tôi nghĩ rằng bạn sẽ tìm thấy những giao diện thay đổi thường xuyên như bạn refactor rằng nó sẽ là một sự cản trở thực sự.

TDD Ví dụ sẽ không giúp tôi không nghĩ. IIRC nó đi qua một ví dụ đơn giản. Tôi đang đọc The Art of Unit Testing của Roy Osherove và trong khi nó có vẻ bao gồm các công cụ và kỹ thuật như mocks và stubs, ví dụ cho đến nay cũng khá đơn giản và tôi không thấy nó cho bạn biết cách tiếp cận một dự án lớn.

19
  • Bạn có thiết kế trước không?

Tất nhiên là bạn có. Bạn đã có một ứng dụng lớn trước mặt bạn.Bạn phải có một số ý tưởng về cấu trúc nó sẽ có trước khi bạn bắt đầu viết các bài kiểm tra và mã. Bạn không cần phải làm tất cả chi tiết, nhưng bạn nên có một số ý tưởng cơ bản về các lớp, các thành phần và các giao diện. Ví dụ, nếu bạn đang làm việc trên một hệ thống dịch vụ web, bạn nên biết những dịch vụ cấp cao nhất là gì, và có một sự gần đúng đầu tiên của chữ ký của họ.

  • Bạn có viết toàn bộ ứng dụng bằng cách sử dụng mã vạch không?

Không. Bạn chỉ phân phát nếu chúng thực sự khó kiểm soát trong thử nghiệm. Ví dụ, tôi muốn loại bỏ cơ sở dữ liệu và giao diện người dùng. Tôi cũng sẽ phân tích các giao diện của bên thứ ba. Đôi khi tôi sẽ khai thác ra một trong những thành phần của riêng tôi nếu nó làm tăng đáng kể thời gian thử nghiệm, hoặc nó buộc tôi tạo ra dữ liệu thử nghiệm quá phức tạp. Nhưng hầu hết thời gian tôi cho phép các bài kiểm tra của tôi hoạt động trên một hệ thống tích hợp khá tốt.

Tôi phải nói rằng tôi thực sự không thích kiểu thử nghiệm phụ thuộc nhiều vào mock và cuống. Đừng làm cho tôi sai, tôi nghĩ rằng mocks và khai là rất hữu ích cho tách từ những điều đó là khó khăn để kiểm tra. Nhưng tôi không thích viết những thứ khó kiểm tra, và vì vậy tôi không sử dụng nhiều mock và stubs.

  • Làm cách nào để bạn viết bài kiểm tra đơn vị đầu tiên cho một chức năng ở mức cao?

Hầu hết các chức năng cấp cao đều có hành vi thoái hóa. Ví dụ, đăng nhập là một hàm mức khá cao và có thể rất phức tạp. Nhưng nếu bạn cố gắng đăng nhập mà không có tên người dùng và không có mật khẩu, phản hồi từ hệ thống sẽ khá đơn giản. Viết các bài kiểm tra đó cũng sẽ rất đơn giản. Vì vậy, bạn bắt đầu với các trường hợp thoái hóa. Một khi bạn đã cạn kiệt chúng, bạn chuyển sang cấp độ phức tạp tiếp theo. Ví dụ: nếu người dùng cố gắng đăng nhập bằng tên người dùng nhưng không có mật khẩu thì sao? Từng chút một, bạn leo lên các bậc thang phức tạp, không bao giờ giải quyết các khía cạnh phức tạp hơn cho đến khi các khía cạnh ít phức tạp hơn đang trôi qua.

Điều đáng chú ý là chiến lược này hoạt động tốt đến mức nào. Bạn có thể nghĩ rằng bạn chỉ cần được leo xung quanh các cạnh tất cả các thời gian và không bao giờ nhận được để thịt; nhưng đó không phải là những gì xảy ra. Thay vào đó bạn thấy mình thiết kế cấu trúc bên trong của mã dựa trên tất cả các trường hợp thoái hóa và ngoại lệ. Khi bạn cuối cùng có được xung quanh dòng chảy chính, bạn thấy rằng cấu trúc của mã mà bạn đang làm việc trên có một lỗ đẹp chỉ là hình dạng phù hợp để cắm luồng chính vào.

  • Vui lòng không tạo Giao diện người dùng đầu tiên.

Giao diện người dùng là những điều gây hiểu lầm. Chúng khiến bạn tập trung vào các khía cạnh sai của hệ thống. Thay vào đó, hãy tưởng tượng rằng hệ thống của bạn phải có nhiều giao diện người dùng khác nhau. Một số sẽ là web, một số sẽ là khách hàng dày, một số sẽ được văn bản thuần túy. Thiết kế hệ thống của bạn để hoạt động bình thường không phân biệt giao diện người dùng. Nhận tất cả các quy tắc kinh doanh hoạt động trước tiên, với tất cả các bài kiểm tra đã qua. Sau đó cắm giao diện người dùng sau. Tôi biết điều này bay khi đối mặt với rất nhiều sự khôn ngoan thông thường, nhưng tôi sẽ không làm theo cách nào khác.

  • Vui lòng không thiết kế cơ sở dữ liệu trước.

Cơ sở dữ liệu là chi tiết. Lưu các chi tiết cho sau này. Thay vào đó, hãy thiết kế hệ thống của bạn như thể bạn không biết loại cơ sở dữ liệu nào bạn đang sử dụng, Giữ bất kỳ khái niệm lược đồ, bảng, hàng và cột nào ngoài lõi của hệ thống. Thực hiện các quy tắc kinh doanh của bạn như thể tất cả dữ liệu được lưu giữ trong bộ nhớ mọi lúc. Sau đó, thêm cơ sở dữ liệu sau, khi bạn đã nhận được tất cả các quy tắc kinh doanh hoạt động.Một lần nữa, tôi biết điều này bay khi đối mặt với một số trí tuệ thông thường, nhưng hệ thống ghép nối với cơ sở dữ liệu quá sớm là một nguồn của rất nhiều thiết kế bị biến dạng nặng.

+0

Trả lời thú vị. Cảm ơn bạn lần nữa – dferraro

+1

"Vui lòng không tạo giao diện người dùng của bạn trước". Tôi rất không đồng ý. Nếu không có (tĩnh) giao diện người dùng đầu tiên bạn có thể chỉ cần mã hóa điều sai. Một bài đọc hay khác: http://www.codinghorror.com/blog/2008/04/ui-first-software-development.html –

+0

Một câu trả lời hay khác: http://stackoverflow.com/questions/1554419/when-i- tiến hành để phát triển-một-phần mềm-ui-thiết kế-hoặc-cơ sở dữ liệu-thiết kế-mà-nên –

1
  • Bạn có viết toàn bộ đơn đăng ký, không sử dụng mã nào?

Để kiểm tra hệ thống của chúng tôi, chúng tôi chủ yếu làm thử nghiệm đơn vị, tích hợp và dịch vụ từ xa. Trong các bài kiểm tra đơn vị, chúng tôi phát hành tất cả các hoạt động dài, tốn thời gian và dịch vụ bên ngoài, tức là hoạt động cơ sở dữ liệu, kết nối dịch vụ web hoặc bất kỳ kết nối nào với các dịch vụ bên ngoài. Điều này là để đảm bảo rằng các thử nghiệm của chúng tôi nhanh chóng, độc lập và không dựa vào phản hồi của bất kỳ dịch vụ bên ngoài nào để cung cấp cho chúng tôi phản hồi nhanh. Chúng tôi đã học được điều này một cách khó khăn bởi vì chúng tôi có một số thử nghiệm để thực hiện các hoạt động cơ sở dữ liệu khiến cho nó hoạt động chậm so với nguyên tắc "Các bài kiểm tra đơn vị phải chạy nhanh"

Trong thử nghiệm tích hợp, chúng tôi kiểm tra các hoạt động cơ sở dữ liệu vẫn không phải các dịch vụ web và các dịch vụ bên ngoài bởi vì điều đó có thể làm cho thử nghiệm trở nên giòn tùy thuộc vào tính khả dụng của chúng và chúng tôi sử dụng autotest để chạy các thử nghiệm ở chế độ nền trong khi chúng tôi đang mã hóa.

Tuy nhiên, để kiểm tra bất kỳ loại dịch vụ từ xa nào, chúng tôi có các thử nghiệm kết nối với dịch vụ bên ngoài, thực hiện thao tác trên chúng và nhận phản hồi. Điều quan trọng đối với thử nghiệm là phản ứng của họ và trạng thái kết thúc của họ nếu nó quan trọng đối với thử nghiệm. Điều quan trọng ở đây là, chúng tôi giữ các kiểu kiểm tra này trong một thư mục khác gọi là remote (đó là quy ước chúng ta tạo ra và theo dõi) và các kiểm tra từ xa này chỉ được chạy bởi máy chủ CI (continuous integration) khi chúng ta kết hợp bất kỳ mã nào với master/trunk branch và push/commit nó vào repo để chúng ta biết nhanh chóng nếu có bất kỳ thay đổi nào trong các dịch vụ bên ngoài có thể ảnh hưởng đến ứng dụng của chúng ta.

  • Tôi vẫn thiết kế ở phía trước?

Có nhưng chúng tôi không thiết kế lớn về cơ bản những gì chú Bob (Robert C. Martin) cho biết. Ngoài ra, chúng tôi nhận được bảng trắng trước khi đắm mình vào mã hóa và tạo một số Sơ đồ Hợp tác Lớp để làm rõ và chắc chắn rằng mọi người trong nhóm đều ở cùng một trang và điều này cũng giúp chúng tôi phân chia công việc giữa các thành viên trong nhóm .

Các vấn đề liên quan