Üçüncü taraf kitaplıklarını daha büyük bir nesne modeliyle sarmalama çabalarını nasıl azaltabilirim?


15

Bu sorunun 2012'deki yazarı ve 2013'teki sorunun yazarı gibi, başvurumu düzgün bir şekilde test etmek için sarmam gereken bir üçüncü taraf kütüphanem var. En iyi cevap şunu belirtir:

Her zaman üçüncü taraf türlerini ve yöntemlerini bir arabirimin arkasına sarmak istersiniz. Bu sıkıcı ve acı verici olabilir. Bazen bir kod üreticisi yazabilir veya bunu yapmak için bir araç kullanabilirsiniz.

Benim durumumda, kütüphane bir nesne modeli içindir ve sonuç olarak bu stratejinin başarılı olması için sarılması gereken daha fazla sayıda sınıf ve yöntem vardır. Sadece "sıkıcı ve acı verici" olmanın ötesinde, bu test için zor bir engel haline gelir.

Bu sorunun üzerinden geçen 4 yıl içinde, izolasyon çerçevelerinin uzun bir yol kat ettiğinin farkındayım. Benim sorum şu: 3. parti kütüphanelerinin tam paketlenmesinin etkisini elde etmenin daha basit bir yolu var mı? Acıyı bu süreçten nasıl çıkarabilirim ve manuel çabayı nasıl azaltabilirim?


Sorum, başlangıçta bağlandığım soruların bir kopyası değil, çünkü sorum, manuel sarma çabasını azaltmakla ilgili. Bu diğer sorular, sarmanın mantıklı olup olmadığını soruyor, çabanın nasıl küçük tutulabileceğini değil.


Hangi programlama dilinden ve ne tür bir kitaplıktan bahsediyorsunuz?
Doc Brown

@DocBrown C # ve bir PDF manipülasyon kütüphanesi.
Tom Wright

2
Sorunuzu yeniden açmak için biraz destek bulmak amacıyla meta'da bir yayın başlattım .
Doc Brown

@DocBrown teşekkürler - Orada bazı ilginç bakış açıları olacağını umuyorum.
Tom Wright

1
Önümüzdeki 48 saat içinde daha iyi yanıt alamadığımızda, bunun üzerine bir ödül vereceğim.
Doc Brown

Yanıtlar:


4

Alaycı bir çerçeve aramıyorsanız, ultra yaygın ve kolay bulunabildikleri için , dikkat çekmeye değer birkaç şey var:

  1. "Her zaman" yapmanız gereken "asla" hiçbir şey yoktur.
    Bir üçüncü taraf kütüphanesini hazırlamak her zaman en iyisi değildir. Uygulamanız özünde bir kitaplığa bağımlıysa veya kelimenin tam anlamıyla bir veya iki çekirdek kitaplığın etrafında oluşturulmuşsa, zamanınızı harcamayın. Kitaplıklar değişirse, uygulamanız yine de değişmelidir .
  2. Entegrasyon testlerini kullanmakta sorun yoktur.
    Bu, özellikle kararlı, uygulamanızın özünde olan veya kolayca alay edilemeyen sınırlar için geçerlidir. Bu şartlar yerine getirilirse, sarma ve alaycı olacaktır karmaşık ve sıkıcı olabilir. Bu durumda, ikisinden de kaçınırdım: sarmayın ve alay etmeyin; entegrasyon testlerini yazmanız yeterlidir. (Otomatik test bir hedefse.)
  3. Araçlar ve çerçeve mantıksal karmaşıklığı ortadan kaldıramaz.
    Prensip olarak, bir alet sadece kazan plakasını kesebilir. Ancak, karmaşık bir arabirim almak ve basitleştirmek için otomatikleştirilebilir bir algoritma yoktur - X arabirimini alarak ve ihtiyaçlarınıza göre uyarlamak yerine . (Sadece bu algoritmayı biliyorsunuz !) Şüphesiz , ince sarmalayıcılar oluşturabilen araçlar olsa da , bunların zaten her yerde bulunmadığını öneririm, çünkü sonunda, sadece akıllı ve dolayısıyla manuel olarak kodlamanız gerekiyor, bir sargının arkasında gizlenmiş olsa bile arabirime karşı .

Bununla birlikte, doğrudan bir sınıfa başvurmaktan kaçınmak için birçok dilde kullanabileceğiniz taktikler vardır . Ve bazı durumlarda, gerçekte mevcut olmayan bir arayüz veya ince bir ambalajı "satabilirsiniz" . Örneğin, C # 'da iki rotadan birine giderdim:

  1. Fabrika ve örtük yazma kullanın .

Bu küçük kombo ile karmaşık bir sınıfı tamamen sarma çabasından kaçınabilirsiniz:

// "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();
  }
}

Bu nesneleri daha "işlevsel" bir yaklaşımla veya bir sözlüğe (ya da her neyse ) depolayarak üye olarak saklamaktan kaçınabiliyorsanız , bu yaklaşım, temel iş varlıklarınızın tam olarak bilmesine gerek kalmadan derleme zamanı tür denetleme avantajına sahiptir. hangi sınıfla çalışıyorlar.

Gerekli olan tek şey, derleme zamanında fabrikanız tarafından döndürülen sınıfın aslında üzerinde iş nesnenizin kullandığı yöntemlere sahip olmasıdır.

  1. Dinamik yazmayı kullanın .

Bu, örtük yazmayı kullanmakla aynıdır , ancak başka bir takas içerir: Derleme türü denetimleri kaybedersiniz ve sınıf üyeleri olarak anonim olarak dış bağımlılıklar ekleme ve bağımlılıklarınızı enjekte etme yeteneği kazanırsınız .

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();
  }
}

Bu taktiklerin her ikisinde de, ExternalPDFLibraryDocumentdaha önce de belirttiğim gibi, alay etme zamanı geldiğinde , yapmanız gereken bir işiniz var - ama yine de yapmanız gereken iş . Ve bu yapı ile, 100'lü ince küçük sargı sınıflarını sık sık tanımlamaktan kaçındınız. Sadece ettik kullanılan - ona doğrudan bakmadan kütüphane çoğunlukla.

Tüm bunlarla birlikte, açıkça bir üçüncü taraf kütüphanesini tamamlamayı düşündüğüm üç büyük neden var - bunların hiçbiri bir araç veya çerçeve kullanmayı ima etmiyor:

  1. Belirli bir kitaplık uygulamanın kendisine özgü değildir .
  2. Sarmadan takas etmek çok pahalı olurdu .
  3. API'nin kendisini sevmiyorum.

Ben bu alanların üçünde de bazı seviye endişe yoksa, sen yok herhangi yapmak önemli Toparlamanın çaba. Ayrıca, her üç alanda da endişeleriniz varsa, otomatik olarak oluşturulan ince bir sargı gerçekten yardımcı olmaz.

Bir kütüphaneyi tamamlamaya karar verdiyseniz, zamanınızın en verimli ve etkili kullanımı, uygulamanızı istediğiniz arayüze göre oluşturmaktır ; mevcut bir API'ya karşı değil.

Başka bir deyişle, klasik tavsiyeye dikkat edin: Yapabileceğiniz her kararı erteleyin. Önce uygulamanızın "çekirdeğini" oluşturun. Sonunda ne istediğinizi yapacak ve sonuçta henüz mevcut olmayan "çevresel şeyler" tarafından yerine getirilecek arabirimlere karşı kodlayın . Boşlukları gerektiği gibi köprü haline getirin.

Bu çaba olmayabilir hissetmek zaman kaydedilen gibi; ancak bir sargıya ihtiyacınız olduğunu düşünüyorsanız, bunu güvenli bir şekilde yapmanın en etkili yoludur .

Bu şekilde düşün.

Sarılmış olsa bile , kodunuzun karanlık bir köşesinde bu kütüphaneye kod yazmanız gerekir . Test sırasında kütüphaneye alay ederseniz, sarılmış olsa bile kaçınılmaz manuel çaba var . Ama, bu doğrudan o kütüphaneyi kabul etmek gerekir anlamına gelmez adıyla uygulamanızın toplu boyunca.

TLDR

Kitaplık kaydırılmaya değerse, 3. taraf kitaplığınıza yaygın, doğrudan referansları önlemek için taktik kullanın, ancak ince sarmalayıcılar oluşturmak için kısayol kullanmayın. Önce iş mantığınızı oluşturun, arayüzleriniz hakkında bilinçli olun ve gerektiğinde adaptörlerinizi organik olarak ortaya çıkarın .

Ve eğer söz konusu olursa, entegrasyon testlerinden korkmayın. Biraz daha bulanıklar, ancak yine de çalışma kodunun kanıtını sunuyorlar ve gerilemeleri uzak tutmak için kolayca yapılabilirler.


2
Açıkça oldu - Bu, başka bir soruya cevap değil yazıdır değil "ne zaman sarmak için" değil, "nasıl manuel çaba azaltmak için".
Doc Brown

1
Üzgünüm, ama sorunun özünü kaçırdığınızı düşünüyorum. Önerilerinizin sarma konusunda manuel çabaları nasıl azaltabileceğini görmüyorum . Söz konusu lib'in, düzinelerce sınıf ve yüzlerce yöntemle API olarak karmaşık bir nesne modeline sahip olduğunu varsayın. API'si standart kullanımda olduğu gibi iyidir, ancak daha az ağrı / çaba ile birim testi için nasıl sarılabilirim?
Doc Brown

1
TLDR; bonus puanları istiyorsanız, bize zaten bilmediğimiz bir şey söyleyin ;-)
Doc Brown

1
@DocBrown Bu noktayı kaçırmadım. Ama, bence sen benim cevabın noktayı kaçırdın. Yatırım sağ çaba size bir sürü iş kaydeder. Test sonuçları var - ama bu sadece bir yan etki. Hangi - bir aracı kullanarak automagicallylar hala başkasının API etrafında çekirdek oluşturmaya başlayın ve mocks bina yaprakları bir kütüphane etrafında ince bir sarmalayıcı oluşturmak olduğunu çaba olamaz kütüphane out bırakarak üzerine size eğer ediyoruz ısrarcı kaçınılması Testlerinizin.
svidgen

1
@DocBrown Bu çok saçma. "Bu sorun sınıfının bir takım araçları ya da yaklaşımları var mı?" Evet. Tabii ki öyle. Savunma kodlaması ve birim testler hakkında dogmatik olmama ... cevabımın dediği gibi. Eğer varsa yaptığımız bir automagicallylar üretilen ince sarmalayıcı var, ne değer sağlayacaktır !? ... Test için bağımlılıkları enjekte etmenize izin vermez, yine de bunu manuel olarak yapmanız gerekir. Ve kütüphaneyi değiştirmenize izin vermez, çünkü hala kütüphanenin API'sine kod yazıyorsunuz ... şimdi sadece dolaylı.
svidgen

9

Bu kodu birim olarak test etmeyin. Bunun yerine entegrasyon testlerini yazın. Bazı durumlarda, birim, test alay, bir sıkıcı ve ağrılı. Ünite testlerinden kurtulun ve satıcıyı gerçekten çağıran entegrasyon testleri yazın.

Bu testlerin, dağıtımdan sonra otomatikleştirilmiş etkinlik olarak dağıtımdan sonra çalıştırılması gerektiğini unutmayın. Ünite testlerinin veya oluşturma sürecinin bir parçası olarak çalıştırılmazlar.

Bazen bir entegrasyon testi, uygulamanızın belirli bölümlerindeki birim testinden daha uygundur. Kodun "test edilebilir" olması için geçmesi gereken çemberler bazen zararlı olabilir.


2
Cevabımı okuduğumda düşündüğüm ilk şey "PDF için gerçekçi değil, çünkü dosyaları ikili düzeyde karşılaştırmak neyin değiştiğini veya değişikliğin sorunlu olup olmadığını söylemiyor". Sonra bu eski SO yazı bulundu , aslında işe yarayacağını gösterir (yani +1).
Doc Brown

@DocB SO linkindeki araç PDF'leri ikili düzeyde karşılaştırmaz. Sayfaların yapısını ve içeriğini karşılaştırır. Pdf iç yapısı: safaribooksonline.com/library/view/pdf-explained/9781449321581/…
linuxunil

1
@linuxunil: evet, biliyorum, yazdığım gibi, önce düşündüm ... ama sonra yukarıda belirtilen çözümü buldum.
Doc Brown

oh .. anlıyorum .. belki cevabınızın sonundaki 'aslında işe yarayabilir' kafamı karıştırdı.
linuxunil

1

Anladığım kadarıyla, bu tartışma, fikir ve uygulama yönergesini sarmak yerine sarıcı oluşturma otomasyonu fırsatlarına odaklanmaktadır . Burada zaten çok fazla şey olduğu için fikirden soyutlamaya çalışacağım.

.NET teknolojilerini oynadığımızı görüyorum, bu yüzden elimizde güçlü yansıma yetenekleri var. Şunları düşünebilirsiniz:

  1. .NET Wrapper Class Generator gibi bir araç . Bu aracı kullanmadım ve eski bir teknoloji yığını üzerinde çalıştığını biliyorum, ama belki sizin durumunuz için uygun olacaktır. Tabii ki, kod kalitesi, Bağımlılık Tersine Çevirme ve Arayüzler Segregasyonu desteği ayrı ayrı araştırılmalıdır. Belki bunun gibi başka araçlar da vardır ama çok fazla arama yapmadım.
  2. Başvurulan derlemede genel yöntemler / arabirimler için arama yapacak ve eşleme ve kod oluşturma işlemini gerçekleştirecek kendi aracınızı yazma. Topluluğa katkı memnuniyetle karşılanacaktır!
  3. .NET bir durum değilse ... belki buraya bakın .

Böyle bir otomasyonun bir temel nokta oluşturabileceğine inanıyorum, ancak nihai bir çözüm değil. Manuel kod yeniden düzenleme gerekli olacak ... ya da en kötü durumda svidgen ne yazdı tamamen katılıyorum gibi yeniden tasarım:

Uygulamanızı istediğiniz arayüze göre oluşturun; 3. taraf API'sına karşı değil.


Tamam, sorun nasıl en az bir fikir olabilir işlenebilir. Ama bu kullanım durumu için kendi deneyimlerine dayanarak, sanırım?
Doc Brown

Soru, yazılım mühendisliği alanı (sarmalayıcı, yansıma, di) ile ilgili kendi deneyimime dayanıyor! Aletlerle ilgili olarak - bunu asnwer'de belirtildiği gibi kullanmadım.
tom3k

0

Sarıcı kitaplıkları oluştururken bu yönergeleri izleyin:

  • şu anda ihtiyacınız olan üçüncü taraf kitaplığının yalnızca küçük bir alt kümesini ortaya çıkarın (ve istek üzerine genişletin)
  • sargıyı olabildiğince ince tutun (hiçbir mantık oraya ait değildir).

1
Sadece sorunun cevabını kaçırmayan bir gönderi için 3 oy aldınız mı?
Doc Brown
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.