En supposant que vous ne recherchiez pas un cadre moqueur, car ils sont ultra-omniprésents et faciles à trouver , il y a quelques choses à noter à l'avance:
- Il n'y a "jamais" quelque chose que vous devriez "toujours" faire.
Il n'est pas toujours préférable de conclure une bibliothèque tierce. Si votre application est intrinsèquement dépendante d'une bibliothèque, ou si elle est littéralement construite autour d'une ou deux bibliothèques principales, ne perdez pas votre temps à la boucler. Si les bibliothèques changent, votre application devra quand même changer .
- Il est acceptable d'utiliser des tests d'intégration.
Cela est particulièrement vrai autour des limites qui sont stables, intrinsèques à votre application ou qui ne peuvent pas être facilement moquées. Si ces conditions sont remplies, l'emballage et la moquerie seront compliqués et fastidieux. Dans ce cas, j'éviterais les deux: ne pas envelopper et ne pas se moquer; il suffit d'écrire des tests d'intégration. (Si les tests automatisés sont un objectif.)
- Les outils et le cadre ne peuvent pas éliminer la complexité logique.
En principe, un outil ne peut couper que sur le passe-partout. Mais, il n'y a pas d'algorithme automatisable pour prendre une interface complexe et la rendre simple - sans parler de prendre l'interface X et de l'adapter à vos besoins. (Vous seul connaissez cet algorithme!) Donc, même s'il existe sans aucun doute des outils qui peuvent générer des wrappers fins, je dirais qu'ils ne sont pas déjà omniprésents car, en fin de compte, vous devez toujours coder intelligemment, et donc manuellement, contre l'interface même si elle est cachée derrière un wrapper.
Cela dit, il existe des tactiques que vous pouvez utiliser dans de nombreuses langues pour éviter de vous référer directement à une classe. Et dans certains cas, vous pouvez «simuler» une interface ou un wrapper mince qui n'existe pas réellement. En C #, par exemple, je choisirais l'une des deux voies:
- Utilisez une fabrique et une saisie implicite .
Vous pouvez éviter l'effort d'encapsuler complètement une classe complexe avec ce petit 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 vous pouvez éviter de stocker ces objets en tant que membres, soit par une approche plus "fonctionnelle", soit en les stockant dans un dictionnaire (ou autre ), cette approche a l'avantage de vérifier le type au moment de la compilation sans que vos entités métier principales n'aient besoin de savoir exactement avec quelle classe ils travaillent.
Tout ce qui est requis, c'est qu'au moment de la compilation, la classe renvoyée par votre fabrique contient en fait les méthodes que votre objet métier utilise.
- Utilisez la saisie dynamique .
C'est dans la même veine que l'utilisation du typage implicite , mais implique un autre compromis: vous perdez les vérifications de type compilation et avez la possibilité d'ajouter anonymement des dépendances externes en tant que membres de la classe et injectez vos dépendances.
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();
}
}
Avec ces deux tactiques, quand vient le temps de se moquer ExternalPDFLibraryDocument
, comme je l'ai dit plus tôt, vous avez du travail à faire - mais c'est un travail que vous devez faire de toute façon . Et, avec cette construction, vous avez évité de définir fastidieusement des centaines de petites classes de wrapper minces. Vous avez simplement utilisé la bibliothèque sans la regarder directement - pour la plupart.
Cela dit, il y a trois grandes raisons pour lesquelles j'envisagerais toujours de conclure explicitement une bibliothèque tierce - aucune ne suggérant l'utilisation d'un outil ou d'un framework:
- La bibliothèque spécifique n'est pas intrinsèque à l'application.
- Il serait très coûteux d'échanger sans le boucler.
- Je n'aime pas l'API elle-même.
Si je n'ai pas un certain niveau de préoccupation dans ces trois domaines, vous ne faites aucun effort important pour conclure. Et, si vous avez des inquiétudes dans les trois domaines, un wrapper mince généré automatiquement ne va pas vraiment aider.
Si vous avez décidé de conclure une bibliothèque, l'utilisation la plus efficace et la plus efficace de votre temps est de créer votre application avec l'interface que vous souhaitez ; pas contre une API existante.
Autrement dit, tenez compte du conseil classique: reporter toutes les décisions que vous pouvez. Créez d'abord le «cœur» de votre application. Codez contre des interfaces qui finiront par faire ce que vous voulez, qui seront finalement remplies par des "choses périphériques" qui n'existent pas encore. Comblez les lacunes au besoin.
Cet effort peut ne pas ressembler à un gain de temps; mais si vous sentez que vous avez besoin d'un emballage, c'est le moyen le plus efficace de le faire en toute sécurité.
Pense-y de cette façon.
Vous devez coder par rapport à cette bibliothèque dans un coin sombre de votre code - même s'il est terminé. Si vous vous moquez de la bibliothèque pendant les tests, il y a inévitablement un effort manuel - même si elle est terminée. Mais cela ne signifie pas que vous devez reconnaître directement cette bibliothèque par son nom dans la majeure partie de votre application.
TLDR
Si la bibliothèque vaut la peine d'être emballée, utilisez des tactiques pour éviter les références directes et étendues à votre bibliothèque tierce, mais ne prenez pas de raccourcis pour générer des enveloppes minces. Construisez d'abord votre logique métier, réfléchissez à vos interfaces et sortez vos adaptateurs de manière organique, au besoin.
Et, si cela arrive, n'ayez pas peur des tests d'intégration. Ils sont un peu plus flous, mais ils offrent toujours des preuves de fonctionnement du code, et ils peuvent toujours être facilement effectués pour garder les régressions à distance.