Là Dependency Injection có giá trị bên ngoài UnitTesting


17

Với một hàm tạo sẽ không bao giờ phải sử dụng bất kỳ triển khai khác nhau nào của một số đối tượng mà nó khởi tạo, liệu nó có thực tế khi sử dụng DI không? Rốt cuộc, chúng tôi vẫn có thể muốn kiểm tra đơn vị.

Lớp trong câu hỏi khởi tạo một vài lớp khác trong hàm tạo của nó và các lớp mà nó sử dụng là khá cụ thể. Nó sẽ không bao giờ sử dụng thực hiện khác. Chúng ta có hợp lý trong việc tránh cố gắng lập trình lên một giao diện không?



3
KISS - luôn là cách tiếp cận tốt nhất.
Phản ứng

5
Theo tôi câu hỏi này cụ thể hơn so với đề xuất trùng lặp. thiết kế cho tương lai-thay đổi hoặc giải quyết vấn đề trong tầm tay , do đó tôi bỏ phiếu để không đóng cái này
k3b

1
Không đủ khả năng kiểm tra lý do?
ConditionRacer

Không thực sự nghe giống như một bản sao nhiều như trả lời chính nó. Nếu nó sẽ không bao giờ, bao giờ xảy ra, thiết kế cho nó không thiết kế cho những thay đổi trong tương lai. Ngay cả các phi hành gia kiến ​​trúc chỉ thiết kế cho những thay đổi sẽ không bao giờ xảy ra do phán đoán tồi.
Steve314

Câu trả lời:


13

Nó phụ thuộc vào mức độ chắc chắn của bạn rằng "không bao giờ, bao giờ" là chính xác (trong thời gian ứng dụng của bạn sẽ được sử dụng).

Nói chung:

  • Đừng sửa đổi thiết kế của bạn chỉ để kiểm tra. Kiểm tra đơn vị là có để phục vụ bạn, không phải ngược lại.
  • Đừng lặp lại chính mình. Làm cho một giao diện sẽ chỉ có một người thừa kế là vô dụng.
  • Nếu một lớp không thể kiểm tra được thì có khả năng nó không linh hoạt / có thể mở rộng cho các trường hợp sử dụng thực tế. Đôi khi điều đó tốt - bạn không thể cần sự linh hoạt đó, nhưng đơn giản / độ tin cậy / khả năng duy trì / hiệu suất / bất cứ điều gì quan trọng hơn.
  • Nếu bạn không biết, hãy viết mã cho giao diện. Yêu cầu thay đổi.

12
Hầu như đã cho bạn -1 vì "không sửa đổi thiết kế của bạn chỉ để kiểm tra". Để đạt được khả năng kiểm tra là IMHO một trong những lý do hàng đầu để thay đổi thiết kế! Nhưng những điểm khác của bạn là ok.
Doc Brown

5
@docBrown - (và những người khác) Tôi khác ở đây với nhiều người, và có lẽ thậm chí là đa số. ~ 95% thời gian, làm cho mọi thứ có thể kiểm tra cũng làm cho chúng linh hoạt hoặc mở rộng. Bạn nên có điều đó trong thiết kế của bạn (hoặc thêm nó vào thiết kế của bạn) hầu hết thời gian - khả năng kiểm tra bị nguyền rủa. ~ 5% khác có các yêu cầu kỳ lạ ngăn chặn sự linh hoạt này có lợi cho một thứ khác, hoặc rất cần thiết / không thay đổi đến mức bạn sẽ phát hiện ra khá nhanh nếu nó bị hỏng, ngay cả khi không có các bài kiểm tra chuyên dụng.
Telastyn

4
có thể chắc chắn, nhưng tuyên bố đầu tiên của bạn ở trên có thể bị hiểu sai quá dễ dàng vì "để lại mã được thiết kế tồi vì đó là khi mối quan tâm duy nhất của bạn là khả năng kiểm tra".
Doc Brown

1
Tại sao bạn lại nói "Tạo một giao diện sẽ chỉ có một người thừa kế là vô dụng."? Giao diện có thể làm việc như một hợp đồng.
kaptan

2
@kaptan - vì đối tượng cụ thể có thể hoạt động tốt như hợp đồng. Làm hai chỉ có nghĩa là bạn cần viết mã hai lần (và sửa đổi mã hai lần khi nó thay đổi). Cấp, phần lớn các giao diện sẽ có nhiều triển khai (không thử nghiệm) hoặc tại bạn cần chuẩn bị cho sự kiện đó. Nhưng đối với trường hợp hiếm hoi đó, tất cả những gì bạn cần là một vật bịt kín đơn giản, chỉ cần sử dụng trực tiếp.
Telastyn

12

Chúng ta có hợp lý trong việc tránh cố gắng lập trình lên một giao diện không?

Mặc dù lợi thế của mã hóa đối với một giao diện là khá rõ ràng, bạn nên tự hỏi chính xác những gì đạt được bằng cách không làm điều đó.

Câu hỏi tiếp theo là: một phần trách nhiệm của lớp trong câu hỏi có chọn thực hiện hay không? Điều đó có thể hoặc không thể là trường hợp và bạn nên hành động phù hợp.

Cuối cùng, luôn có tiềm năng cho một số hạn chế ngớ ngẩn thoát ra khỏi màu xanh. Bạn có thể muốn chạy cùng một đoạn mã đồng thời và khả năng tiêm thực thi có thể giúp đồng bộ hóa. Hoặc sau khi định hình ứng dụng của bạn, bạn có thể phát hiện ra bạn muốn có một chiến lược phân bổ khác với khởi tạo đơn giản. Hoặc các mối quan tâm xuyên suốt xuất hiện và bạn không có hỗ trợ AOP trong tay. Ai biết?

YAGNI đề nghị rằng khi viết mã, điều quan trọng là không thêm bất cứ thứ gì thừa. Một trong những điều mà các lập trình viên có xu hướng thêm vào mã của họ mà không hề hay biết, đó là những giả định không cần thiết. Giống như "phương pháp này có thể có ích" hoặc "điều này sẽ không bao giờ thay đổi". Cả hai thêm lộn xộn vào thiết kế của bạn.


2
+1 để trích dẫn YAGNI ở đây làm đối số cho DI, không chống lại nó.
Doc Brown

4
@DocBrown: Xem xét rằng YAGNI có thể được sử dụng ở đây, để biện minh cho việc không sử dụng DI. Tôi nghĩ đó là một cuộc tranh luận chống lại YAGNI là một biện pháp hữu ích cho mọi thứ.
Steven Evers

1
+1 cho các giả định không cần thiết được đưa vào YAGNI, thứ đã đánh vào đầu chúng tôi một vài lần
Izkata

@SteveEvers: Tôi nghĩ rằng việc sử dụng YAGNI để biện minh cho việc bỏ qua nguyên tắc đảo ngược phụ thuộc sẽ loại trừ sự thiếu hiểu biết về YAGNI hoặc DIP hoặc thậm chí có thể một số nguyên tắc cơ bản hơn về lập trình và lý luận. Bạn chỉ nên bỏ qua DIP nếu bạn cần - một tình huống trong đó YAGNI đơn giản là không thể áp dụng theo bản chất của nó.
back2dos

@ back2dos: Giả sử DI hữu ích vì 'có thể yêu cầu' và "ai biết?" chính xác là sự suy nghĩ rằng YAGNI có ý định chiến đấu, thay vào đó bạn đang sử dụng nó như một sự biện minh cho công cụ và cơ sở hạ tầng bổ sung.
Steven Evers

7

Nó phụ thuộc vào các thông số khác nhau nhưng đây là một vài lý do tại sao bạn vẫn muốn sử dụng DI:

  • Tôi tin rằng việc kiểm tra là một lý do chính đáng
  • các lớp mà đối tượng của bạn yêu cầu có thể được sử dụng ở những nơi khác - nếu bạn tiêm chúng, nó cho phép bạn tập hợp các tài nguyên (ví dụ: nếu các lớp trong câu hỏi là các luồng hoặc kết nối cơ sở dữ liệu - bạn không muốn mỗi lớp của bạn tạo mới kết nối)
  • nếu việc khởi tạo các đối tượng khác có thể thất bại, mã cao hơn ngăn xếp có thể sẽ xử lý các vấn đề tốt hơn so với lớp của bạn, điều mà sau đó có thể chỉ đơn giản là chuyển tiếp các lỗi

Điểm mấu chốt: bạn có thể sống mà không cần DI trong trường hợp đó nhưng có khả năng sử dụng DI sẽ kết thúc bằng mã sạch hơn.


3

Khi bạn thiết kế một chương trình hoặc một tính năng, một phần của quá trình suy nghĩ sẽ là cách bạn sẽ kiểm tra nó. Dependency Injection là một trong những công cụ kiểm tra và nên được coi là một phần của hỗn hợp.

Các lợi ích bổ sung của Dependency Injection và sử dụng giao diện thay vì các lớp cũng có lợi khi ứng dụng được mở rộng, nhưng chúng cũng có thể được thêm vào mã nguồn sau đó khá dễ dàng và an toàn khi sử dụng tìm kiếm và thay thế. - ngay cả trên các dự án rất lớn.


2
 > Dependency Injection worth it **outside** of UnitTesting?
 > Are we justified in avoiding trying to program to an interface?

Nhiều câu trả lời cho câu hỏi này có thể được tranh luận là "bạn có thể cần nó bởi vì .." là YAGNI nếu bạn không muốn làm gì không đáng tin.

Nếu bạn đang hỏi những lý do nào bên cạnh những điều không cần thiết phải lập trình đến một giao diện

, Dependency Injection đáng giá bên ngoài UnitTesting nếu bạn cần đảo ngược quyền kiểm soát . Ví dụ: nếu một thực hiện mô-đun cần một mô-đun khác không thể truy cập trong lớp của nó.

Ví dụ: nếu bạn có các mô-đun gui=> businesslayer=> driver=> common.

Trong kịch bản này businesslayercó thể sử dụng drivernhưng driverkhông thể sử dụng businesslayer.

Nếu drivercần một số chức năng cao hơn, bạn có thể thực hiện chức năng này trong businesslayerđó thực hiện một giao diện trong commonlớp. driverchỉ cần biết giao diện trong commonlớp.


1

Có bạn - trước hết, hãy quên việc kiểm thử đơn vị là một lý do để thiết kế mã của bạn xung quanh các công cụ kiểm tra đơn vị, không bao giờ nên uốn cong thiết kế mã của bạn để phù hợp với một ràng buộc nhân tạo. Nếu các công cụ của bạn buộc bạn phải làm điều này, hãy lấy các công cụ tốt hơn (ví dụ: Microsoft Fakes / Moles cho phép bạn có nhiều tùy chọn hơn để tạo các đối tượng giả).

Ví dụ, bạn có chia các lớp của mình thành các phương thức công khai chỉ vì các công cụ kiểm tra không hoạt động với các phương thức riêng tư? (Tôi biết sự khôn ngoan phổ biến là giả vờ rằng bạn không cần thử nghiệm các phương pháp riêng tư, nhưng tôi cảm thấy đây là một phản ứng đối với khó khăn khi làm như vậy với các công cụ hiện tại, không phải là phản ứng thực sự khi không cần thử nghiệm riêng tư).,

Nói chung, bạn thuộc loại TDDer nào - "kẻ nhạo báng" như Fowler mô tả về họ, cần thay đổi mã cho phù hợp với các công cụ họ sử dụng, trong khi những người thử nghiệm "cổ điển" tạo ra các thử nghiệm tích hợp nhiều hơn trong tự nhiên (tức là kiểm tra lớp dưới dạng một đơn vị, không phải mỗi phương thức) vì vậy sẽ ít cần giao diện hơn, đặc biệt nếu bạn sử dụng các công cụ có thể giả định các lớp cụ thể.


3
Tôi không nghĩ rằng sự khôn ngoan phổ biến rằng các phương pháp riêng tư không nên thử nghiệm có liên quan gì đến khó khăn khi thử nghiệm chúng. Nếu có một lỗi trong một phương thức riêng tư, nhưng nó không ảnh hưởng đến hành vi của đối tượng, thì nó không ảnh hưởng gì cả. Nếu có một lỗi trong một phương thức riêng tư đã ảnh hưởng đến hành vi của đối tượng, thì sẽ có một thử nghiệm thất bại hoặc thiếu trên ít nhất một trong các phương thức công khai của một đối tượng.
Michael Shaw

Điều đó đi xuống cho dù bạn kiểm tra hành vi hoặc trạng thái. Rõ ràng, các phương thức riêng cần được kiểm tra theo một cách nào đó, nhưng nếu bạn là người TDD cổ điển, bạn sẽ kiểm tra chúng bằng cách kiểm tra lớp "nói chung", hầu hết mọi người sử dụng công cụ kiểm tra đều tập trung vào kiểm tra từng phương thức cá nhân ... và quan điểm của tôi là sau này thực sự không kiểm tra đúng vì họ bỏ lỡ cơ hội để thực hiện một bài kiểm tra đầy đủ. Vì vậy, tôi đồng ý với bạn, trong khi cố gắng làm nổi bật TDD đã bị lật đổ như thế nào bởi một số người (hầu hết?) Thực hiện thử nghiệm đơn vị ngày hôm nay.
gbjbaanb

1

Dependency Injection cũng làm cho nó rõ ràng hơn rằng đối tượng của bạn ĐÃ phụ thuộc.

Khi người khác sử dụng đối tượng của bạn một cách ngây thơ (không nhìn vào nhà xây dựng), họ sẽ thấy rằng họ sẽ cần thiết lập các dịch vụ, kết nối, v.v. Điều đó không rõ ràng vì họ không phải chuyển chúng cho nhà xây dựng . Vượt qua trong sự phụ thuộc làm cho nó rõ ràng hơn những gì cần thiết.

Bạn cũng có khả năng che giấu sự thật rằng lớp bạn có thể đang vi phạm SRP. Nếu bạn vượt qua trong nhiều phụ thuộc (hơn 3), lớp của bạn có thể đang làm quá nhiều và nên được tái cấu trúc. Nhưng nếu bạn đang tạo chúng trong hàm tạo, mùi mã này sẽ bị ẩn đi.


0

Tôi đồng ý với cả hai phe ở đây và vấn đề vẫn còn mở cho cuộc tranh luận theo ý kiến ​​của tôi. YAGNI yêu cầu tôi không giải quyết việc thay đổi mã của mình để phù hợp với giả định. Kiểm thử đơn vị không phải là vấn đề ở đây vì tôi tin chắc rằng sự phụ thuộc sẽ không bao giờ thay đổi. Nhưng nếu tôi đã thử nghiệm Đơn vị như dự định bắt đầu, tôi sẽ không bao giờ đạt đến điểm này. Như tôi cuối cùng đã đi vào DI.

Hãy để tôi cung cấp một sự thay thế khác cho kịch bản của tôi cụ thể

Với một mô hình nhà máy tôi có thể bản địa hóa các phụ thuộc ở một nơi. Khi kiểm tra tôi có thể thay đổi triển khai dựa trên ngữ cảnh và điều đó đủ tốt. Điều này không đi ngược lại với YAGNI vì những lợi ích của việc trừu tượng hóa một số công trình lớp.

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.