Làm cách nào tôi có thể giảm nỗ lực thủ công để bọc thư viện bên thứ ba bằng mô hình đối tượng lớn hơn?


16

Giống như tác giả của câu hỏi này từ năm 2012 câu hỏi này từ năm 2013 , tôi có một thư viện bên thứ 3 mà tôi cần bọc để kiểm tra đúng ứng dụng của mình. Câu trả lời hàng đầu nêu:

Bạn luôn muốn bọc các loại và phương thức của bên thứ ba đằng sau một giao diện. Điều này có thể tẻ nhạt và đau đớn. Đôi khi bạn có thể viết một trình tạo mã hoặc sử dụng một công cụ để làm điều này.

Trong trường hợp của tôi, thư viện dành cho một mô hình đối tượng và do đó có số lượng lớn hơn các lớp và phương thức cần được gói để chiến lược này thành công. Ngoài việc đơn thuần là "tẻ nhạt và đau đớn", điều này trở thành một rào cản khó kiểm tra.

Trong 4 năm kể từ câu hỏi này, tôi biết rằng các khung cách ly đã đi một chặng đường dài. Câu hỏi của tôi là: bây giờ có tồn tại một cách đơn giản hơn để đạt được hiệu quả của việc gói đầy đủ các thư viện của bên thứ 3 không? Làm thế nào tôi có thể giảm đau trong quá trình này và giảm nỗ lực thủ công?


Câu hỏi của tôi không phải là một bản sao của các câu hỏi tôi liên kết ban đầu, vì câu hỏi của tôi là về việc giảm nỗ lực thủ công. Những câu hỏi khác chỉ hỏi nếu gói có ý nghĩa, không làm thế nào nỗ lực có thể được giữ nhỏ.


Ngôn ngữ lập trình nào, và bạn đang nói về loại thư viện nào?
Doc Brown

@DocBrown C # và thư viện thao tác PDF.
Tom Wright

2
Tôi đã bắt đầu một bài đăng trên meta để tìm một số hỗ trợ để mở lại câu hỏi của bạn.
Doc Brown

Cảm ơn @DocBrown - Tôi hy vọng rằng sẽ có một số quan điểm thú vị ngoài kia.
Tom Wright

1
Khi chúng tôi không nhận được câu trả lời tốt hơn trong 48 giờ tới, tôi sẽ đặt tiền thưởng cho việc này.
Doc Brown

Câu trả lời:


4

Giả sử bạn không tìm kiếm một khung mô phỏng, bởi vì chúng cực kỳ phổ biến và dễ tìm , có một vài điều đáng chú ý phía trước:

  1. Có "không bao giờ" bất cứ điều gì bạn nên "luôn luôn" làm.
    Không phải lúc nào cũng tốt nhất để kết thúc một thư viện bên thứ ba. Nếu ứng dụng của bạn thực chất phụ thuộc vào một thư viện hoặc nếu nó được xây dựng theo nghĩa đen xung quanh một hoặc hai thư viện cốt lõi, đừng lãng phí thời gian của bạn để gói nó. Nếu các thư viện thay đổi, ứng dụng của bạn sẽ cần phải thay đổi .
  2. Bạn có thể sử dụng các bài kiểm tra tích hợp.
    Điều này đặc biệt đúng xung quanh các ranh giới ổn định, nội tại đối với ứng dụng của bạn hoặc không thể dễ dàng bị chế giễu. Nếu những điều kiện đó được đáp ứng, việc gói và chế nhạo sẽ phức tạp và tẻ nhạt. Trong trường hợp đó, tôi sẽ tránh cả hai: không quấn và không chế nhạo; chỉ cần viết bài kiểm tra tích hợp. (Nếu kiểm tra tự động là mục tiêu.)
  3. Các công cụ và khung có thể loại bỏ sự phức tạp logic.
    Về nguyên tắc, một công cụ chỉ có thể cắt giảm nồi hơi. Tuy nhiên, không có thuật toán tự động hóa nào để lấy giao diện phức tạp và làm cho nó đơn giản - hãy để một mình lấy giao diện X và điều chỉnh nó cho phù hợp với nhu cầu của bạn. (Chỉ bạn biết thuật toán đó !) Vì vậy, trong khi chắc chắn có những công cụ có thể tạo ra các hàm bao mỏng, tôi đề nghị rằng chúng không phổ biến vì cuối cùng, bạn vẫn cần mã hóa một cách thông minh, và do đó, bằng tay, đối với giao diện ngay cả khi nó ẩn đằng sau một trình bao bọc.

Điều đó nói rằng, có những chiến thuật bạn có thể sử dụng bằng nhiều ngôn ngữ để tránh tham chiếu trực tiếp đến một lớp học. Và trong một số trường hợp, bạn có thể "giả mạo" một giao diện hoặc trình bao bọc mỏng không thực sự tồn tại. Ví dụ, trong C #, tôi sẽ đi một trong hai tuyến đường:

  1. Sử dụng một nhà máy và gõ ngầm .

Bạn có thể tránh nỗ lực gói hoàn toàn một lớp phức tạp với combo nhỏ này:

// "factory"
class PdfDocumentFactory {
  public static ExternalPDFLibraryDocument Build() {
    return new ExternalPDFLibraryDocument();
  }
}

// code that uses the factory.
class CoreBusinessEntity {
  public void DoImportantThings() {
    var doc = PdfDocumentFactory.Build();

    // ... i have no idea what your lib does, so, I'm making stuff but.
    // but, you can do whatever you want here without explicitly
    // referring to the library's actual types.
    doc.addHeader("Wee");
    doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
    return doc.exportBinaryStreamOrSomething();
  }
}

Nếu bạn có thể tránh lưu trữ các đối tượng này với tư cách là thành viên, thông qua cách tiếp cận "chức năng" hơn hoặc bằng cách lưu trữ chúng trong từ điển (hoặc bất cứ điều gì ), phương pháp này có lợi ích của việc kiểm tra kiểu thời gian biên dịch mà không cần các đối tượng kinh doanh cốt lõi của bạn cần biết chính xác họ đang làm việc với lớp nào

Tất cả những gì được yêu cầu là, tại thời điểm biên dịch, lớp được trả về bởi nhà máy của bạn thực sự có các phương thức mà đối tượng kinh doanh của bạn đang sử dụng.

  1. Sử dụng kiểu gõ động .

Điều này cũng giống như sử dụng cách gõ ngầm , nhưng liên quan đến một sự đánh đổi khác: Bạn mất kiểm tra kiểu biên dịch và có được khả năng thêm ẩn danh phụ thuộc bên ngoài với tư cách là thành viên lớp và tiêm phụ thuộc của bạn.

class CoreBusinessEntity {
  dynamic Doc;

  public void InjectDoc(dynamic Doc) {
    Doc = doc;
  }

  public void DoImortantThings() {
    Doc.addHeader("Wee");
    Doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
    return Doc.exportBinaryStreamOrSomething();
  }
}

Với cả hai chiến thuật, khi nói đến thời gian để chế nhạo ExternalPDFLibraryDocument, như tôi đã nói ở trên, bạn có một số việc phải làm - nhưng, nó làm việc bạn cần phải làm nào . Và, với cấu trúc này, bạn đã tránh tẻ nhạt xác định 100 lớp lớp bao bọc nhỏ. Bạn chỉ đơn giản là sử dụng thư viện mà không cần nhìn thẳng vào nó - phần lớn.

Với tất cả những gì đã nói, có ba lý do lớn mà tôi vẫn sẽ xem xét rõ ràng là gói thư viện của bên thứ ba - không có lý do nào gợi ý sử dụng công cụ hoặc khung:

  1. Thư viện cụ thể không bản chất của ứng dụng.
  2. Nó sẽ là rất tốn kém để trao đổi mà không gói nó.
  3. Tôi không thích API.

Nếu tôi không có mối quan tâm cấp độ nào trong cả ba lĩnh vực đó, bạn sẽ không thực hiện bất kỳ nỗ lực đáng kể để bọc lại. Và, nếu bạn có một số lo ngại trong cả ba lĩnh vực, một trình bao bọc mỏng được tạo tự động sẽ không thực sự có ích.

Nếu bạn đã quyết định bọc thư viện, việc sử dụng thời gian hiệu quả và hiệu quả nhất của bạn là xây dựng ứng dụng của bạn theo giao diện bạn muốn ; không chống lại API hiện có.

Đặt một cách khác, chú ý lời khuyên cổ điển: hoãn mọi quyết định bạn có thể. Xây dựng "cốt lõi" của ứng dụng của bạn đầu tiên. Mã chống lại các giao diện cuối cùng sẽ làm những gì bạn muốn, cuối cùng sẽ được thực hiện bởi "công cụ ngoại vi" chưa tồn tại. Cầu những khoảng trống khi cần thiết.

Nỗ lực này có thể không cảm thấy như tiết kiệm thời gian; nhưng nếu bạn cảm thấy bạn cần một cái bọc, đây là cách hiệu quả nhất để làm điều đó một cách an toàn.

Nghĩ theo cách này.

Bạn cần mã hóa thư viện này trong một số góc tối của mã của bạn - ngay cả khi nó được gói lại. Nếu bạn chế nhạo thư viện trong quá trình thử nghiệm, sẽ không thể tránh khỏi nỗ lực thủ công ở đó - ngay cả khi nó được gói lại. Nhưng, điều đó không có nghĩa là bạn cần trực tiếp thừa nhận thư viện đó theo tên trong toàn bộ phần lớn ứng dụng của bạn.

TLD

Nếu thư viện đáng để bọc, hãy sử dụng các chiến thuật để tránh phổ biến, tham chiếu trực tiếp đến thư viện bên thứ 3 của bạn, nhưng không sử dụng phím tắt để tạo các trình bao bọc mỏng. Xây dựng logic kinh doanh của bạn trước tiên, hãy cân nhắc về các giao diện của bạn và xuất hiện các bộ điều hợp của bạn một cách hữu cơ, khi cần thiết.

Và, nếu nói đến nó, đừng sợ các bài kiểm tra tích hợp. Chúng hơi mập hơn một chút, nhưng chúng vẫn đưa ra bằng chứng về mã làm việc và chúng vẫn có thể dễ dàng được thực hiện để giữ hồi quy.


2
Đây là một bài viết khác không trả lời câu hỏi - rõ ràng không phải là "khi nào cần bọc", mà là "làm thế nào để giảm nỗ lực thủ công".
Doc Brown

1
Xin lỗi, nhưng tôi nghĩ rằng bạn đã bỏ lỡ điểm cốt lõi của câu hỏi. Tôi không thấy các đề xuất của bạn có thể làm giảm bất kỳ nỗ lực thủ công nào trong việc gói. Giả sử lib trong cổ phần có một mô hình đối tượng phức tạp là API, với một số hàng chục lớp và hàng trăm phương thức. API của nó là tốt vì nó được sử dụng tiêu chuẩn, nhưng làm thế nào để bọc nó để thử nghiệm đơn vị với ít đau / nỗ lực hơn?
Doc Brown

1
TLDR; nếu bạn muốn có điểm thưởng, hãy cho chúng tôi biết những điều chúng tôi chưa biết ;-)
Doc Brown

1
@DocBrown Tôi đã không bỏ lỡ điểm. Nhưng, tôi nghĩ rằng bạn đã bỏ lỡ điểm câu trả lời của tôi. Đầu tư đúng công sức giúp bạn tiết kiệm rất nhiều công việc. Có những tác động thử nghiệm - nhưng đó chỉ là tác dụng phụ. Sử dụng một công cụ để tự động tạo một trình bao bọc mỏng xung quanh thư viện vẫn khiến bạn xây dựng thư viện cốt lõi của mình xung quanh API của người khác và xây dựng các mô hình giả - đó rất nhiều nỗ lực không thể tránh khỏi nếu bạn khăng khăng rời khỏi thư viện các bài kiểm tra của bạn.
Svidgen

1
@DocBrown Điều này thật vô lý. "Lớp vấn đề này có một lớp công cụ hay cách tiếp cận nào không?" Đúng. Tất nhiên là thế. Mã hóa phòng thủkhông nhận được giáo điều về các bài kiểm tra đơn vị ... như câu trả lời của tôi nói. Nếu bạn đã có một trình bao bọc mỏng được tạo tự động, nó sẽ mang lại giá trị gì!? ... Nó sẽ không cho phép bạn tiêm phụ thuộc để thử nghiệm, bạn vẫn phải làm điều đó bằng tay. Và nó sẽ không cho phép bạn trao đổi thư viện, bởi vì bạn vẫn đang mã hóa API của thư viện ... bây giờ nó chỉ là gián tiếp.
Svidgen

9

Đừng kiểm tra đơn vị mã đó. Viết các bài kiểm tra tích hợp thay thế. Trong một số trường hợp, kiểm tra đơn vị, chế giễu, tẻ nhạt và đau đớn. Bỏ các bài kiểm tra đơn vị và viết các bài kiểm tra tích hợp thực sự khiến nhà cung cấp gọi ra.

Lưu ý, các thử nghiệm này nên được chạy sau khi triển khai dưới dạng hoạt động tự động triển khai bài. Chúng không được chạy như một phần của bài kiểm tra đơn vị hoặc một phần của quá trình xây dựng.

Đôi khi một bài kiểm tra tích hợp phù hợp hơn một bài kiểm tra đơn vị trong một số phần nhất định của ứng dụng của bạn. Các vòng quay phải đi qua để làm cho mã "có thể kiểm tra" đôi khi có thể gây bất lợi.


2
Điều đầu tiên tôi nghĩ khi tôi đọc câu trả lời của bạn là "không thực tế đối với PDF, vì việc so sánh các tệp ở cấp độ nhị phân không cho bạn biết điều gì đã thay đổi hoặc nếu thay đổi có vấn đề". Sau đó, tôi tìm thấy bài SO cũ hơn này , cho biết nó thực sự có thể hoạt động (nên +1).
Doc Brown

@DocBrown công cụ trong liên kết SO không so sánh các tệp PDF ở cấp độ nhị phân. Nó so sánh cấu trúc và nội dung của các trang. Cấu trúc bên trong Pdf: safaribooksonline.com/l
Library / view / pdf

1
@linuxunil: vâng, tôi biết, như tôi đã viết, đầu tiên tôi nghĩ ... nhưng sau đó tôi đã tìm thấy giải pháp được đề cập ở trên.
Doc Brown

oh .. tôi hiểu rồi .. có lẽ 'nó thực sự có thể hoạt động' trong câu trả lời cuối cùng của bạn khiến tôi bối rối.
linuxunil

1

Theo tôi hiểu, cuộc thảo luận này tập trung vào các cơ hội để tự động hóa trình bao bọc hơn là gói ý tưởng và hướng dẫn thực hiện. Tôi sẽ cố gắng trừu tượng hóa từ ý tưởng vì đã có rất nhiều về nó ở đây.

Tôi thấy rằng chúng tôi đang chơi xung quanh các công nghệ .NET, do đó chúng tôi có khả năng phản chiếu mạnh mẽ trong tay. Bạn có thể xem xét:

  1. Công cụ như .NET Wrapper Class Generator . Tôi đã không sử dụng công cụ đó và tôi biết rằng nó hoạt động trên một chồng công nghệ cũ, nhưng có lẽ đối với trường hợp của bạn, nó sẽ phù hợp. Tất nhiên, chất lượng mã, hỗ trợ cho Phân đoạn phụ thuộc và phân vùng giao diện cần được nghiên cứu riêng. Có thể có những công cụ khác như vậy nhưng tôi đã không tìm kiếm nhiều.
  2. Viết công cụ của riêng bạn sẽ tìm kiếm trong hội đồng tham chiếu cho các phương thức / giao diện công cộng và thực hiện ánh xạ và tạo mã. Đóng góp cho cộng đồng sẽ được chào đón nhiều hơn!
  3. Nếu .NET không phải là một trường hợp ... có thể nhìn vào đây .

Tôi tin rằng tự động hóa như vậy có thể tạo thành một điểm cơ bản, nhưng không phải là một giải pháp cuối cùng. Tái cấu trúc mã thủ công sẽ được yêu cầu ... hoặc trong trường hợp xấu nhất là thiết kế lại vì tôi hoàn toàn đồng ý với những gì mà Svidgen đã viết:

Xây dựng ứng dụng của bạn dựa trên giao diện bạn muốn; không chống lại API của bên thứ 3.


Ok, ít nhất một ý tưởng làm thế nào vấn đề có thể được xử lý. Nhưng không dựa trên kinh nghiệm riêng cho trường hợp sử dụng này, tôi giả sử?
Doc Brown

Câu hỏi được dựa trên kinh nghiệm của riêng tôi về lĩnh vực kỹ thuật phần mềm (trình bao bọc, phản xạ, di)! Về các công cụ - Tôi đã không sử dụng nó như đã nêu trong asnwer.
tom3k

0

Thực hiện theo các hướng dẫn này khi tạo thư viện trình bao bọc:

  • chỉ hiển thị một tập hợp con nhỏ của thư viện bên thứ ba mà bạn cần ngay bây giờ (và mở rộng theo yêu cầu)
  • giữ cho trình bao bọc càng mỏng càng tốt (không có logic nào ở đó).

1
Chỉ tự hỏi tại sao bạn có 3 upvote cho một bài viết mà bỏ lỡ điểm của câu hỏi.
Doc Brown
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.