Có phải tiêm phụ thuộc của Poor Man là một cách tốt để giới thiệu khả năng kiểm tra cho một ứng dụng cũ không?


14

Trong năm vừa qua, tôi đã tạo ra một hệ thống mới bằng cách sử dụng Dependency Injection và bộ chứa IOC. Điều này đã dạy tôi rất nhiều về DI!

Tuy nhiên, ngay cả sau khi tìm hiểu các khái niệm và các mẫu thích hợp, tôi coi đó là một thách thức để tách mã và giới thiệu một thùng chứa IOC vào một ứng dụng cũ. Ứng dụng này đủ lớn đến mức một triển khai thực sự sẽ trở nên quá sức. Ngay cả khi giá trị được hiểu và thời gian được cấp. Ai đã dành thời gian cho những thứ như thế này ??

Mục tiêu của khóa học là đưa các bài kiểm tra đơn vị vào logic kinh doanh!
Logic nghiệp vụ được đan xen với các cuộc gọi cơ sở dữ liệu ngăn chặn thử nghiệm.

Tôi đã đọc các bài báo và tôi hiểu được sự nguy hiểm của Tiêm phụ thuộc của Người nghèo như được mô tả trong bài viết này của Los Techies . Tôi hiểu nó không thực sự tách rời bất cứ điều gì.
Tôi hiểu rằng nó có thể liên quan đến việc tái cấu trúc toàn hệ thống vì việc triển khai đòi hỏi phải phụ thuộc mới. Tôi sẽ không xem xét sử dụng nó trên một dự án mới với bất kỳ kích thước nào.

Câu hỏi: Có ổn không khi sử dụng DI của Poor Man để giới thiệu khả năng kiểm tra ứng dụng cũ và bắt đầu bóng lăn?

Ngoài ra, việc sử dụng DI của Poor Man như một cách tiếp cận cơ bản để tiêm phụ thuộc thực sự có phải là một cách có giá trị để giáo dục về nhu cầu và lợi ích của nguyên tắc này không?

Bạn có thể cấu trúc lại một phương thức có sự phụ thuộc cuộc gọi cơ sở dữ liệu và trừu tượng mà gọi đến phía sau một giao diện không? Chỉ cần có sự trừu tượng hóa đó sẽ làm cho phương thức đó có thể kiểm tra được do việc triển khai giả có thể được truyền qua quá tải hàm tạo.

Cuối cùng, một khi nỗ lực đạt được những người ủng hộ, dự án có thể được cập nhật để triển khai một thùng chứa IOC và các nhà xây dựng sẽ ở ngoài đó để thực hiện các tóm tắt.



2
Chỉ cần một lưu ý. I consider it a challenge to decouple code and introduce an IOC container into a legacy applicationtất nhiên rồi Nó được đặt tên là nợ kỹ thuật. Đây là lý do tại sao trước bất kỳ cuộc cải cách lớn nào, nó thích hợp hơn là các nhà tái cấu trúc nhỏ và continuos. Giảm các lỗi thiết kế chính và chuyển sang IoC sẽ ít thách thức hơn.
Laiv

Câu trả lời:


25

Bài phê bình về tiêm chích của Poor Man trong NerdDinner ít liên quan đến việc bạn có sử dụng DI Container hay không so với việc thiết lập các lớp học của bạn một cách chính xác.

Trong bài báo, họ nói rằng

public class SearchController : Controller {

    IDinnerRepository dinnerRepository;

    public SearchController() : this(new DinnerRepository()) { }

    public SearchController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }
}

là không chính xác bởi vì, trong khi hàm tạo đầu tiên cung cấp cơ chế dự phòng thuận tiện để xây dựng lớp, nó cũng tạo ra một phụ thuộc ràng buộc chặt chẽ với DinnerRepository.

Tất nhiên, biện pháp khắc phục chính xác không phải là, như Los Techies gợi ý, để thêm một thùng chứa DI, mà là để loại bỏ các hàm tạo vi phạm.

public class SearchController : Controller 
{
    IDinnerRepository dinnerRepository;

    public SearchController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }
}

Các lớp còn lại bây giờ có các phụ thuộc của nó được đảo ngược đúng. Bây giờ bạn có thể tự do tiêm những phụ thuộc đó theo cách bạn muốn.


Cảm ơn những suy nghĩ của bạn! Tôi hiểu "nhà xây dựng vi phạm" và làm thế nào chúng ta nên tránh nó. Tôi hiểu rằng việc có sự phụ thuộc này không làm mất đi bất cứ điều gì, nhưng nó KHÔNG cho phép thử nghiệm đơn vị. Tôi ở phía đầu của việc giới thiệu DI và nhận các bài kiểm tra đơn vị tại chỗ càng nhanh càng tốt. Tôi đang cố gắng tránh sự phức tạp của DI / IOC Container hoặc xuất xưởng sớm trong trò chơi này. Như đã đề cập, sau này khi hỗ trợ cho DI phát triển, chúng ta có thể triển khai Container và loại bỏ các "nhà xây dựng vi phạm" đó.
Airn5485

Các constructor mặc định là không cần thiết cho các bài kiểm tra đơn vị. Bạn có thể trao bất kỳ phụ thuộc nào bạn muốn cho lớp mà không có nó, bao gồm cả một đối tượng giả.
Robert Harvey

2
@ Airn5485 hãy cẩn thận rằng bạn không quá trừu tượng hóa. Các thử nghiệm đó sẽ kiểm tra các hành vi có ý nghĩa - kiểm tra rằng XServicemột tham số truyền cho một tham số XRepositoryvà trả về những gì nó nhận lại không quá hữu ích cho bất kỳ ai và cũng không cung cấp cho bạn nhiều khả năng mở rộng. Viết bài kiểm tra đơn vị của bạn để kiểm tra hành vi có ý nghĩa và đảm bảo rằng các thành phần của bạn không quá hẹp đến mức bạn thực sự chuyển tất cả logic của bạn sang gốc thành phần.
Ant P

Tôi không hiểu làm thế nào bao gồm các nhà xây dựng vi phạm sẽ giúp cho các bài kiểm tra đơn vị, chắc chắn nó làm điều ngược lại? Loại bỏ hàm tạo vi phạm để DI được triển khai đúng cách và vượt qua phụ thuộc bị chế giễu khi bạn khởi tạo các đối tượng.
Rob

@Rob: Không. Đó chỉ là một cách thuận tiện để các nhà xây dựng mặc định đứng lên một đối tượng hợp lệ.
Robert Harvey

16

Bạn đưa ra một giả định sai ở đây về "DI của người nghèo" là gì.

Tạo một lớp có hàm tạo "lối tắt" vẫn tạo khớp nối không phải là DI của người nghèo.

Không sử dụng một thùng chứa, và tạo ra tất cả các mũi tiêm và ánh xạ bằng tay, người nghèo của DI.

Thuật ngữ "người nghèo của DI" nghe có vẻ như là một điều xấu. Vì lý do đó, thuật ngữ "DI thuần túy" được khuyến khích ngày nay vì nó có vẻ tích cực hơn và thực sự mô tả chính xác hơn quá trình.

Không chỉ hoàn toàn tốt khi sử dụng DI của người nghèo / thuần túy để giới thiệu DI vào một ứng dụng hiện có, đây cũng là một cách sử dụng DI hợp lệ cho nhiều ứng dụng mới. Và như bạn nói, mọi người nên sử dụng DI thuần túy trên ít nhất một dự án để thực sự hiểu cách DI hoạt động, trước khi xử lý trách nhiệm đối với "phép thuật" của một container IoC.


8
DI "Người nghèo" hoặc "Tinh khiết", tùy theo bạn thích, cũng giảm nhẹ rất nhiều vấn đề với các container IoC. Tôi đã từng sử dụng các thùng chứa IoC cho mọi thứ nhưng thời gian càng trôi qua tôi càng muốn tránh chúng hoàn toàn.
Ant P

7
@AntP, tôi với bạn: Tôi hoàn toàn DI 100% trong những ngày này và chủ động tránh các container. Nhưng tôi (chúng tôi) là thiểu số trong số điểm đó theo như tôi có thể nói.
David Arno

2
Có vẻ rất buồn - khi tôi rời khỏi trại "ma thuật" của các container IoC, thư viện chế giễu và cứ thế ôm lấy OOP, đóng gói, kiểm tra tay đôi và xác minh trạng thái, có vẻ như xu hướng ma thuật vẫn còn lên. +1 dù sao đi nữa.
Ant P

3
@AntP & David: Thật tốt khi biết tôi không cô đơn trong trại 'Pure DI'. Container DI được tạo ra để giải quyết sự thiếu hụt trong các ngôn ngữ. Họ thêm giá trị theo nghĩa đó. Nhưng trong suy nghĩ của tôi, câu trả lời thực sự là sửa các ngôn ngữ (hoặc chuyển sang các ngôn ngữ khác) và không xây dựng hành trình trên đầu chúng.
JimmyJames

1

Sự thay đổi của Paragidm trong các nhóm kế thừa / cơ sở mã là vô cùng rủi ro:

Bất cứ khi nào bạn đề xuất "cải tiến" cho mã kế thừa và có các lập trình viên "di sản" trong nhóm, bạn chỉ nói với mọi người rằng "họ đã làm sai" và bạn trở thành Kẻ thù trong suốt thời gian còn lại của họ với công ty.

Sử dụng DI Framework như một cái búa để đập vỡ tất cả các móng tay sẽ chỉ làm cho mã kế thừa trở nên tồi tệ hơn trong mọi trường hợp. Nó cũng cực kỳ rủi ro cá nhân.

Ngay cả trong những trường hợp hạn chế nhất như vậy, nó có thể được sử dụng trong các trường hợp thử nghiệm sẽ khiến cho các trường hợp thử nghiệm đó trở thành mã "không chuẩn" và "nước ngoài", tốt nhất sẽ chỉ bị đánh dấu @Ignorekhi chúng bị hỏng hoặc tệ hơn liên tục bị phàn nàn bởi Các lập trình viên kế thừa có nhiều đầu mối nhất với quản lý và được viết lại "chính xác" với tất cả "thời gian lãng phí cho các bài kiểm tra đơn vị" này chỉ đổ lỗi cho bạn.

Giới thiệu khuôn khổ DI, hoặc thậm chí là khái niệm "Pure DI" cho một dòng ứng dụng kinh doanh, ít hơn một cơ sở mã di sản khổng lồ mà không có sự quản lý, nhóm và đặc biệt là tài trợ của nhà phát triển chính sẽ là hồi chuông báo tử cho bạn về mặt xã hội và chính trị trong nhóm / công ty. Làm những việc như thế này là vô cùng rủi ro và có thể là tự sát chính trị theo cách tồi tệ nhất.

Dependency Injection là một giải pháp tìm kiếm một vấn đề.

Bất kỳ ngôn ngữ nào với các hàm tạo theo định nghĩa đều sử dụng phép nội suy phụ thuộc theo quy ước nếu bạn biết bạn đang làm gì và hiểu cách sử dụng đúng hàm tạo, đây chỉ là một thiết kế tốt.

Tiêm phụ thuộc chỉ hữu ích với liều lượng nhỏ cho một phạm vi rất hẹp:

  • Những thứ thay đổi nhiều hoặc có nhiều triển khai thay thế bị ràng buộc tĩnh.

    • Trình điều khiển JDBC là một ví dụ hoàn hảo.
    • Các máy khách HTTP có thể thay đổi từ nền tảng này sang nền tảng khác.
    • Hệ thống đăng nhập thay đổi theo nền tảng.
  • Các hệ thống plugin có các plugin có thể định cấu hình có thể được xác định trong mã cấu hình trong khung của bạn và được phát hiện tự động khi khởi động và được tải / tải lại động trong khi chương trình đang chạy.


10
Ứng dụng sát thủ cho DI là thử nghiệm đơn vị. Như bạn đã chỉ ra, hầu hết các phần mềm sẽ không cần nhiều DI. Nhưng các bài kiểm tra cũng là một ứng dụng khách của mã này, vì vậy chúng ta nên thiết kế để kiểm tra. Đặc biệt, điều này có nghĩa là đặt các đường nối trong thiết kế của chúng tôi, nơi các bài kiểm tra có thể quan sát hành vi. Điều này không yêu cầu khung DI ưa thích, nhưng nó yêu cầu các phụ thuộc có liên quan được thực hiện rõ ràng và có thể thay thế.
amon

4
Nếu các nhà phát triển của chúng tôi biết nếu tiến lên những gì có thể thay đổi, đó sẽ là một nửa trận chiến. Tôi đã có những bước phát triển dài, nơi rất nhiều thứ được cho là "cố định" đã thay đổi. Chứng minh tương lai ở đây và ở đó sử dụng DI không phải là điều xấu. Sử dụng nó ở khắp mọi nơi tất cả các thời gian lập trình sùng bái hàng hóa.
Robbie Dee

kiểm tra quá mức sẽ chỉ có nghĩa là họ bị cũ và bị đánh dấu bỏ qua thay vì cập nhật trong tương lai. DI trong mã di sản là một nền kinh tế sai lầm. Tất cả những gì họ sẽ tồn tại là biến bạn thành "kẻ xấu" vì đã đưa tất cả "mã không chuẩn, quá phức tạp mà không ai hiểu được" này vào cơ sở mã. Bạn đã được cảnh báo.

4
@JarrodRoberson, đó thực sự là một môi trường độc hại. Một trong những dấu hiệu chính của một nhà phát triển giỏi là họ nhìn lại mã họ đã viết trong quá khứ và nghĩ, "ugh, tôi đã thực sự viết điều đó à? Điều đó thật sai lầm!" Đó là bởi vì họ đã phát triển như một nhà phát triển và học hỏi những điều mới. Một người nhìn vào mã họ đã viết năm năm trước và thấy không có gì sai với nó đã không học được gì trong năm năm đó. Vì vậy, nếu nói với dân gian, họ đã làm sai trong quá khứ khiến bạn trở thành kẻ thù, sau đó chạy trốn khỏi công ty đó thật nhanh, vì họ là một đội cuối cùng sẽ kìm hãm bạn và giảm bạn xuống mức kém.
David Arno

1
Không chắc chắn tôi đồng ý với những kẻ xấu nhưng đối với tôi, điểm mấu chốt của vấn đề này là bạn không cần DI để thực hiện kiểm tra đơn vị. Việc thực hiện DI để làm cho mã dễ kiểm tra hơn chỉ là khắc phục vấn đề.
Ant 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.