Zakładając, że nie szukasz kpiącego frameworka, ponieważ są one wszechobecne i łatwe do znalezienia , jest kilka rzeczy, na które warto zwrócić uwagę:
- „Nigdy” nic nie powinieneś „zawsze” robić.
Nie zawsze najlepiej jest zawinąć bibliotekę strony trzeciej. Jeśli twoja aplikacja jest wewnętrznie zależna od biblioteki lub jeśli jest dosłownie zbudowana wokół jednej lub dwóch podstawowych bibliotek, nie marnuj czasu na jej zamykanie. Jeśli biblioteki się zmienią, aplikacja i tak będzie musiała się zmienić .
- Można używać testów integracyjnych.
Jest to szczególnie prawdziwe w przypadku granic, które są stabilne, nieodłączne dla aplikacji lub których nie można łatwo wyśmiewać. Jeśli te warunki zostaną spełnione, pakowanie i kpiny będą skomplikowane i nużące. W takim przypadku unikałbym obu: nie zawijaj i nie kpij; po prostu napisz testy integracyjne. (Jeśli celem jest automatyczne testowanie).
- Narzędzia i środowisko nie mogą wyeliminować logicznej złożoności.
Zasadniczo narzędzie może ciąć tylko na płycie kotłowej. Ale nie ma algorytmu automatyzującego przyjmowanie złożonego interfejsu i upraszczanie go - nie mówiąc już o przyjmowaniu interfejsu X i dostosowywaniu go do własnych potrzeb. (Tylko ty znasz ten algorytm!) Tak więc, chociaż istnieją niewątpliwie narzędzia, które mogą generować cienkie opakowania, sugerowałbym, że nie są one już wszechobecne, ponieważ w końcu nadal musisz po prostu inteligentnie, a zatem ręcznie, kodować, przeciwko interfejsowi, nawet jeśli jest ukryty za opakowaniem.
To powiedziawszy, istnieją taktyki, których można użyć w wielu językach, aby uniknąć odwoływania się bezpośrednio do klasy. W niektórych przypadkach możesz „udawać” interfejs lub cienkie opakowanie, które tak naprawdę nie istnieje. Na przykład w języku C # wybrałbym jedną z dwóch tras:
- Użyj fabrycznego i niejawnego pisania .
Dzięki temu niewielkiemu zestawowi możesz uniknąć wysiłku pełnego pakowania złożonej klasy:
// "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();
}
}
Jeśli można uniknąć zapisywania tych obiektów jako członków, poprzez bardziej „funkcjonalny” podejścia lub przechowując je w słowniku (lub cokolwiek ), takie podejście ma tę zaletę sprawdzenia typu kompilacji bez swoich kluczowych podmiotów gospodarczych, którzy muszą wiedzieć dokładnie z jaką klasą pracują.
Wszystko, co jest wymagane, to aby w czasie kompilacji klasa zwrócona przez twoją fabrykę faktycznie posiadała metody używane przez obiekt biznesowy.
- Użyj dynamicznego pisania .
Podobnie jest w przypadku pisania niejawnego , ale wiąże się to z innym kompromisem: tracisz kontrole typu kompilacyjnego i zyskujesz możliwość anonimowego dodawania zależności zewnętrznych jako członków klasy i wstrzykiwania zależności.
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();
}
}
Z obu tych taktyk, gdy przychodzi czas na Mock ExternalPDFLibraryDocument
, jak wspomniano wcześniej, masz coś do zrobienia - ale jest to praca, którą trzeba zrobić, w każdym razie . Dzięki tej konstrukcji unikniesz żmudnego definiowania setek cienkich klas opakowań. Po prostu korzystałeś z biblioteki, nie patrząc bezpośrednio na nią - w większości.
Biorąc to wszystko pod uwagę, istnieją trzy ważne powody, dla których nadal rozważałbym jawne zamknięcie biblioteki strony trzeciej - żadna z nich nie sugerowałaby użycia narzędzia lub frameworka:
- Określona biblioteka nie jest nieodłączna dla aplikacji.
- Zamiana bez zawijania byłaby bardzo droga.
- Nie podoba mi się sam interfejs API.
Jeśli nie mam obaw o poziom we wszystkich tych trzech obszarach, nie podejmujesz żadnego znaczącego wysiłku, aby to podsumować. A jeśli masz jakieś obawy we wszystkich trzech obszarach, automatycznie wygenerowane cienkie opakowanie naprawdę nie pomoże.
Jeśli zdecydowałeś się owinąć biblioteka w górę, najbardziej skuteczne i efektywne wykorzystanie czasu jest, aby budować swoją aplikację przed interfejsu ty chcesz ; nie przeciwko istniejącemu API.
Innymi słowy, posłuchaj klasycznej rady: odłóż każdą decyzję, jaką możesz. Najpierw zbuduj „rdzeń” aplikacji. Kod przeciwko interfejsom, które w końcu zrobią to, co chcesz, co w końcu zostanie spełnione przez „peryferia”, które jeszcze nie istnieją. Uzupełnij luki według potrzeb.
Ten wysiłek może nie wydawać się oszczędnością czasu; ale jeśli uważasz, że potrzebujesz opakowania, jest to najbardziej skuteczny sposób, aby zrobić to bezpiecznie.
Pomyśl o tym w ten sposób.
Musisz zakodować tę bibliotekę w jakimś ciemnym rogu kodu - nawet jeśli jest on opakowany. Jeśli wyśmiejesz bibliotekę podczas testowania, nie da się uniknąć ręcznego wysiłku - nawet jeśli jest ona zapakowana. Nie oznacza to jednak, że musisz bezpośrednio potwierdzać tę bibliotekę według nazwy w większości aplikacji.
TLDR
Jeśli biblioteka jest warta pakowania, użyj taktyki, aby uniknąć powszechnych, bezpośrednich odniesień do biblioteki innej firmy, ale nie używaj skrótów do generowania cienkich opakowań. Najpierw zbuduj logikę biznesową, rozważnie swoje interfejsy i w razie potrzeby wyodrębnij adaptery w sposób organiczny .
A jeśli chodzi o to, nie bój się testów integracyjnych. Są trochę bardziej niepewne, ale wciąż oferują dowód działania kodu i nadal można je łatwo zrobić, aby powstrzymać regresję.