Suponiendo que no está buscando un marco burlón, ya que son ultra ubicuos y fáciles de encontrar , hay algunas cosas que vale la pena señalar por adelantado:
- "Nunca" hay algo que "siempre" debas hacer.
No siempre es mejor concluir una biblioteca de terceros. Si su aplicación depende intrínsecamente de una biblioteca, o si está literalmente construida alrededor de una o dos bibliotecas principales, no pierda el tiempo terminando. Si las bibliotecas cambian, su aplicación deberá cambiar de todos modos.
- Está bien usar pruebas de integración.
Esto es especialmente cierto alrededor de límites que son estables, intrínsecos a su aplicación o que no se pueden burlar fácilmente. Si se cumplen esas condiciones, envolver y burlarse será complicado y tedioso. En ese caso, evitaría ambos: no envuelva y no se burle; solo escribe pruebas de integración. (Si las pruebas automatizadas son un objetivo).
- Las herramientas y el marco no pueden eliminar la complejidad lógica.
En principio, una herramienta solo puede reducir las repeticiones. Pero no existe un algoritmo automatizado para tomar una interfaz compleja y simplificarla, y mucho menos tomar la interfaz X y adaptarla a sus necesidades. (¡Solo usted conoce ese algoritmo!) Por lo tanto, si bien existen indudablemente herramientas que pueden generar envoltorios delgados, sugeriría que aún no son ubicuas porque, al final, todavía necesita codificar de manera inteligente y, por lo tanto, manualmente. contra la interfaz incluso si está oculto detrás de un contenedor.
Dicho esto, hay tácticas que puedes usar en muchos idiomas para evitar referirte directamente a una clase. Y en algunos casos, puede "fingir" una interfaz o envoltura delgada que en realidad no existe. En C #, por ejemplo, iría a una de dos rutas:
- Use una fábrica y tipeo implícito .
Puede evitar el esfuerzo de envolver completamente una clase compleja con este pequeño combo:
// "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();
}
}
Si puede evitar almacenar estos objetos como miembros, ya sea a través de un enfoque más "funcional" o almacenándolos en un diccionario (o lo que sea ), este enfoque tiene el beneficio de la verificación de tipos en tiempo de compilación sin que sus entidades comerciales centrales necesiten saber exactamente con qué clase están trabajando.
Todo lo que se requiere es que, en el momento de la compilación, la clase devuelta por su fábrica tenga los métodos que está utilizando su objeto comercial.
- Utiliza la escritura dinámica .
Esto está en la misma línea que usar el tipeo implícito , pero implica otra compensación: pierde las comprobaciones de tipo de compilación y obtiene la capacidad de agregar anónimamente dependencias externas como miembros de la clase e inyectar sus dependencias.
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();
}
}
Con estas dos tácticas, cuando llega el momento de burlarse ExternalPDFLibraryDocument
, como dije antes, tienes algo de trabajo que hacer, pero es un trabajo que deberías hacer de todos modos . Y, con esta construcción, ha evitado tediosamente definir cientos de clases de envoltorios pequeños y delgados. Simplemente ha utilizado la biblioteca sin mirarla directamente, en su mayor parte.
Dicho todo esto, hay tres grandes razones por las que aún consideraría concluir explícitamente una biblioteca de terceros, ninguna de las cuales sugiere un uso de una herramienta o marco:
- La biblioteca específica no es intrínseca a la aplicación.
- Sería muy costoso cambiarlo sin envolverlo.
- No me gusta la API en sí.
Si no tengo un nivel de preocupación en las tres áreas, no hagas ningún esfuerzo significativo para terminarlo. Y, si tiene alguna preocupación en las tres áreas, un envoltorio delgado generado automáticamente no será de gran ayuda.
Si ha decidido cerrar una biblioteca, el uso más eficiente y efectivo de su tiempo es construir su aplicación contra la interfaz que desee ; no contra una API existente.
Dicho de otra manera, preste atención al consejo clásico: posponga cada decisión que pueda. Cree primero el "núcleo" de su aplicación. Código contra interfaces que eventualmente harán lo que desea, que eventualmente se cumplirá con "cosas periféricas" que aún no existen. Cerrar las brechas según sea necesario.
Este esfuerzo puede no parecer un ahorro de tiempo; pero si siente que necesita un envoltorio, esta es la forma más eficiente de hacerlo de manera segura.
Piénsalo de esta manera.
Debe codificar contra esta biblioteca en algún rincón oscuro de su código, incluso si está envuelto. Si te burlas de la biblioteca durante las pruebas, hay un esfuerzo manual inevitable allí, incluso si está envuelto. Pero eso no significa que deba reconocer directamente esa biblioteca por su nombre en la mayor parte de su aplicación.
TLDR
Si vale la pena envolver la biblioteca, use tácticas para evitar referencias directas y generalizadas a su biblioteca de terceros, pero no tome atajos para generar envoltorios delgados. Desarrolle su lógica de negocios primero, sea deliberado sobre sus interfaces y haga emerger sus adaptadores orgánicamente, según sea necesario.
Y, si se trata de eso, no tenga miedo de las pruebas de integración. Son un poco más difusos, pero aún ofrecen evidencia de código de trabajo, y todavía se pueden hacer fácilmente para mantener a raya las regresiones.