web-dev-qa-db-fra.com

Les externes de Subversion sont-ils un anti-modèle?

Subversion vous permet d'incorporer des copies de travail d'autres référentiels en utilisant externals , ce qui permet un contrôle de version facile des logiciels de bibliothèque tiers dans votre projet.

Bien que ceux-ci semblent idéaux pour la réutilisation des bibliothèques et le contrôle de version de logiciel du fournisseur , ils ne sont pas sans leurs critiques :

Veuillez ne pas utiliser les externes Subversion (ou similaires dans d'autres outils), ils sont un anti-pattern et, par conséquent, inutiles

Y a-t-il des risques cachés dans l'utilisation d'externes? Veuillez expliquer pourquoi ils seraient considérés comme un anti-modèle.

68
Ken

Je suis l'auteur de la citation de la question, qui provient d'un réponse précédente .

Jason a raison de se méfier de brèves déclarations comme la mienne et de demander une explication. Bien sûr, si j'expliquais complètement tout dans cette réponse, j'aurais besoin d'avoir écrit un livre.

Mike a également raison de souligner que l'un des problèmes avec une fonctionnalité de type svn:external Est que les changements dans la source ciblée pourraient casser votre propre source, surtout si cette source ciblée se trouve dans un référentiel dont vous ne possédez pas .

En expliquant plus en détail mon commentaire, permettez-moi d'abord de dire qu'il existe des moyens "sûrs" d'utiliser la fonctionnalité svn:external, Comme avec tout autre outil ou fonctionnalité. Cependant, je me réfère à cela comme un anti-modèle parce que la fonctionnalité est beaucoup plus susceptible d'être mal utilisée. D'après mon expérience, il a toujours été mal utilisé, et je me trouve très peu susceptible de l'utiliser de cette manière sûre ni de recommander jamais cette utilisation. Veuillez noter en outre que je veux dire AUCUN dénigrement envers l'équipe Subversion - j'adore Subversion, même si je prévois de passer à Bazaar.

Le principal problème avec cette fonctionnalité est qu'elle encourage et elle est généralement utilisée pour lier directement la source d'une construction ("projet") à la source d'une autre, ou pour lier le projet à un binaire (DLL, JAR, etc.) dont cela dépend. Aucune de ces utilisations n'est sage et elles constituent un anti-modèle.

Comme je l'ai dit dans mon autre réponse, je crois qu'un principe essentiel pour les versions logicielles est que chaque projet construit exactement UN livrable binaire ou primaire. Cela peut être considéré comme une application du principe de séparation des préoccupations au processus de construction. Ceci est particulièrement vrai pour un projet référençant directement la source d'un autre, ce qui est également une violation du principe de encapsulation . Une autre forme de ce type de violation tente de créer une hiérarchie de construction pour construire un système entier ou un sous-système en appelant de manière récursive des sous-versions. Maven encourage/applique fortement ce comportement, ce qui est l'une des nombreuses raisons pour lesquelles je ne le recommande pas.

Enfin, je trouve que diverses questions pratiques rendent cette fonctionnalité indésirable. D'une part, svn:external A quelques caractéristiques comportementales intéressantes (mais les détails m'échappent pour le moment). D'autre part, je trouve toujours que j'ai besoin que de telles dépendances soient explicitement visibles pour mon projet (processus de construction), et non enterrées comme certaines métadonnées de contrôle de source.

Alors, quelle est une manière "sûre" d'utiliser cette fonctionnalité? Je considérerais que c'est quand il est utilisé temporairement par une seule personne, comme un moyen de "configurer" un environnement de travail. Je pouvais voir où un programmeur pourrait créer son propre dossier dans le référentiel (ou un pour chaque programmeur) où il configurerait des liens svn:external Vers les diverses autres parties du référentiel sur lesquelles il travaille actuellement. Ensuite, une extraction de ce dossier créera une copie de travail de tous leurs projets en cours. Lorsqu'un projet est ajouté ou terminé, les définitions svn:external Peuvent être ajustées et la copie de travail mise à jour de manière appropriée. Cependant, je préfère une approche qui n'est pas liée à un système de contrôle de source particulier, comme le faire avec un script qui appelle les extractions.

Pour mémoire, ma plus récente exposition à ce problème a eu lieu au cours de l'été 2008 chez un client consultant qui utilisait svn:external À grande échelle - TOUT était lié pour produire un seul exemplaire de travail principal. Leurs scripts de construction basés sur Ant & Jython (pour WebLogic) ont été construits sur cette copie de travail principale. Le résultat net: RIEN ne pouvait être construit de manière autonome, il y avait littéralement des dizaines de sous-projets, mais aucun n'était sûr à vérifier/travailler seul. Par conséquent, tout travail sur ce système nécessitait d'abord une extraction/mise à jour de plus de 2 Go de fichiers (ils placent également les binaires dans le référentiel). Faire quoi que ce soit était un exercice futile, et je suis parti après avoir essayé pendant trois mois (il y avait beaucoup d'autres anti-modèles présents également).

EDIT: Expliquez les constructions récursives -

Au fil des ans (en particulier la dernière décennie), j'ai construit des systèmes massifs pour les entreprises Fortune 500 et les grandes agences gouvernementales impliquant de nombreuses dizaines de sous-projets organisés en hiérarchies de répertoires de plusieurs niveaux. J'ai utilisé des projets/solutions Microsoft Visual Studio pour organiser des systèmes basés sur .NET, Ant ou Maven 2 pour les systèmes basés sur Java, et j'ai commencé à utiliser distutils et setuptools (easyinstall) pour les systèmes basés sur Python. Ces systèmes ont également inclus d'énormes bases de données généralement dans Oracle ou Microsoft SQL Server.

J'ai eu beaucoup de succès en concevant ces constructions massives pour la facilité d'utilisation et la répétabilité. Ma norme de conception est qu'un nouveau développeur peut se présenter le premier jour, recevoir un nouveau poste de travail (peut-être directement de Dell avec juste une installation de système d'exploitation typique), recevoir un document de configuration simple (généralement une seule page d'instructions d'installation), et être en mesure de configurer entièrement le poste de travail et de construire le système complet à partir de la source, sans surveillance, sans assistance, et en une demi-journée ou moins. L'appel de la construction elle-même implique l'ouverture d'une commande Shell, le passage au répertoire racine de l'arborescence source et l'émission d'une commande sur une ligne pour TOUT construire.

Malgré ce succès, la construction d'un système de construction aussi massif nécessite beaucoup de soin et une adhésion étroite à des principes de conception solides, tout comme la construction d'une application/d'un système critique pour l'entreprise. J'ai trouvé qu'une partie cruciale est que chaque projet (qui produit un seul artefact/livrable) doit avoir un seul script de construction, qui doit avoir une interface bien définie (commandes pour appeler des parties du processus de construction), et il doit rester seul de tous les autres (sous) projets. Historiquement, il est facile de construire tout le système, mais difficile/impossible de construire une seule pièce. Ce n'est que récemment que j'ai appris à m'assurer soigneusement que chaque projet est vraiment autonome.

En pratique, cela signifie qu'il doit y avoir au moins deux couches de scripts de construction. La couche la plus basse est constituée des scripts de création de projet qui produisent chaque livrable/artefact. Chacun de ces scripts réside dans le répertoire racine de l'arborescence des sources de son projet (en effet, ce script DÉFINIT l'arborescence des sources de son projet), ces scripts ne connaissent rien au contrôle de source, ils s'attendent à être exécutés à partir de la ligne de commande, ils référencent tout dans le projet relatif au script de construction, et ils référencent leurs dépendances externes (outils ou artefacts binaires, aucun autre projet source) en fonction de quelques paramètres configurables (variables d'environnement, fichiers de configuration, etc.).

La deuxième couche de scripts de construction est également destinée à être appelée à partir de la ligne de commande, mais ceux-ci connaissent le contrôle de code source. En effet, cette deuxième couche est souvent un script unique qui est invoqué avec un nom de projet et une version, puis il extrait la source du projet nommé dans un nouveau répertoire temporaire (peut-être spécifié sur la ligne de commande) et invoque son script de construction.

Il peut être nécessaire de disposer de plus de variantes pour prendre en charge les serveurs d'intégration continue, plusieurs plates-formes et divers scénarios de version.

Parfois, il est nécessaire d'avoir une troisième couche de scripts qui invoque la deuxième couche de scripts (qui invoquent la première couche) dans le but de créer des sous-ensembles spécifiques de l'ensemble du projet global. Par exemple, chaque développeur peut avoir son propre script qui construit les projets sur lesquels il travaille aujourd'hui. Il peut y avoir un script pour tout construire afin de générer la documentation principale ou pour calculer des métriques.

Quoi qu'il en soit, j'ai trouvé que tenter de traiter le système comme une hiérarchie de projets est contre-productif. Il lie les projets les uns aux autres afin qu'ils ne puissent pas être librement construits seuls, ou dans des emplacements arbitraires (répertoire temporaire sur le serveur d'intégration continue), ou dans un ordre arbitraire (en supposant que les dépendances sont satisfaites). Souvent, tenter de forcer une hiérarchie casse toute intégration IDE) que l'on pourrait tenter.

Enfin, la construction d'une hiérarchie massive de projets peut tout simplement être trop gourmande en performances. Par exemple, au printemps 2007, j'ai tenté une hiérarchie source modeste (Java plus Oracle) que j'ai construite à l'aide de Ant, qui a finalement échoué car la construction a toujours été abandonnée avec une Java OutOfMemoryException. C'était sur une station de travail de 2 Go RAM avec un espace de swap de 3,5 Go pour lequel j'avais réglé la JVM pour pouvoir utiliser toute la mémoire disponible. L'application/le système était relativement simple en termes de quantité de code, mais les invocations de build récursives ont fini par épuiser la mémoire, peu importe la quantité de mémoire que je lui ai donnée. au final je dépassais simplement les limites des outils (Java/Ant dans ce cas).

Alors rendez-vous service, construisez votre build en tant que projets autonomes, puis composez-les dans un système complet. Gardez-le léger et flexible. Prendre plaisir.

EDIT: Plus sur les antipatterns

À proprement parler, un anti-modèle est une solution courante qui semble résoudre le problème mais ne le fait pas, soit parce qu'il laisse des lacunes importantes, soit parce qu'il introduit des problèmes supplémentaires (souvent pires que le problème d'origine). Une solution implique nécessairement un ou plusieurs outils plus la technique pour les appliquer au problème en question. Par conséquent, il est exagéré de se référer à un outil ou à une caractéristique spécifique d'un outil comme un anti-modèle, et il semble que les gens détectent et réagissent à cet étirement - assez juste.

D'un autre côté, comme il semble être une pratique courante dans notre industrie de se concentrer sur les outils plutôt que sur la technique, c'est l'outil/la fonctionnalité qui retient l'attention (une enquête informelle des questions ici sur StackOverflow semble facilement illustrer). Mes commentaires, et cette question elle-même, reflètent cette pratique.

Cependant, il semble parfois particulièrement justifié de faire cet étirement, comme dans ce cas. Certains outils semblent "conduire" l'utilisateur à des techniques particulières pour les appliquer, au point que certains soutiennent que les outils façonnent la pensée (légèrement reformulé). C'est surtout dans cet esprit que je suggère que svn:external Est un anti-modèle.

Pour énoncer plus strictement le problème, l'anti-modèle est de concevoir une solution de construction qui inclut de lier des projets entre eux au niveau de la source, ou de mettre en version implicitement les dépendances entre les projets, ou de permettre à de telles dépendances de changer implicitement, car chacune d'elles invoque des projets très négatifs. conséquences. La nature de la fonctionnalité svn:external Rend très difficile d'éviter ces conséquences négatives.

Gérer correctement les dépendances entre les projets implique d'aborder ces dynamiques avec le problème de base, et les outils et techniques mènent sur une voie différente. Un exemple à considérer est Ivy , qui aide d'une manière similaire à Maven mais sans les nombreux inconvénients. J'étudie Ivy, associé à Ant, comme solution à court terme au problème de construction Java). À long terme, je cherche à intégrer les concepts et fonctionnalités de base dans un outil open-source qui facilite une solution multiplateforme.

70
Rob Williams

Je ne pense pas du tout que ce soit un anti-modèle. J'ai fait quelques recherches rapides sur Google et je n'ai rien trouvé ... personne ne se plaint que l'utilisation de svn: externals est mauvaise ou nuisible. Bien sûr, il y a quelques mises en garde dont vous devez être conscient ... et ce n'est pas quelque chose que vous devriez simplement saupoudrer fortement dans tous vos référentiels ... mais en ce qui concerne la citation originale, c'est juste son opinion personnelle (et subjective) . Il n'a jamais vraiment discuté de svn: externals, sauf pour les condamner comme un anti-pattern. De telles déclarations radicales sans aucun soutien ou au moins un raisonnement sur la manière dont la personne en est venue à faire la déclaration sont toujours suspectes.

Cela dit, l'utilisation d'externes pose certains problèmes. Comme Mike l'a répondu, ils peuvent être très utiles pour pointer vers les branches stables des logiciels publiés ... en particulier les logiciels que vous contrôlez déjà. Nous les utilisons en interne dans un certain nombre de projets pour les bibliothèques utilitaires et autres. Nous avons un petit groupe qui améliore et travaille sur la base de la bibliothèque utilitaire, mais ce code de base est partagé entre un certain nombre de projets. Nous ne voulons pas que diverses équipes vérifient simplement le code du projet utilitaire et nous ne voulons pas traiter un million de branches, donc pour nous, svn: externals fonctionne très bien. Pour certaines personnes, ils peuvent ne pas être la réponse. Cependant, je ne suis pas du tout d'accord avec l'affirmation "Veuillez ne pas utiliser…" et que ces outils représentent un anti-modèle.

65
Jason Coco

Le principal risque lié à l'utilisation de svn: externals est que le référentiel référencé sera modifié de manière à casser votre code ou à introduire une vulnérabilité de sécurité. Si le référentiel externe est également sous votre contrôle, cela peut être acceptable.

Personnellement, je n'utilise svn: externals que pour pointer vers les branches "stables" d'un référentiel que je possède.

19
Mike

Un vieux fil de discussion, mais je veux répondre à la préoccupation qu'un changement externe puisse casser votre code. Comme indiqué précédemment, cela est le plus souvent dû à une mauvaise utilisation de la propriété externe. Les références externes doivent, dans presque tous les cas, pointer vers un numéro de révision spécifique dans l'URI du référentiel externe. Cela garantit que l'externe ne changera jamais à moins que vous ne le changiez pour pointer vers un numéro de révision différent.

Pour certaines de nos bibliothèques internes, que nous utilisons comme externes dans nos projets d'utilisateurs finaux, j'ai trouvé utile de créer une balise de la bibliothèque dans la version Major.Minor, où nous n'appliquons aucune modification de rupture. Avec un schéma de contrôle de version en quatre points (Major.Minor.BugFix.Build), nous permettons à la balise d'être tenue à jour avec les modifications de BugFix.Build (encore une fois, sans aucune rupture). Cela nous permet d'utiliser une référence externe à l'étiquette sans numéro de révision. Dans le cas de modifications majeures ou autres, une nouvelle balise est créée.

Les externes eux-mêmes ne sont pas mauvais, mais cela n'empêche pas les gens d'en créer de mauvaises implémentations. Il ne faut pas beaucoup de recherche, juste un peu de lecture à travers une documentation, pour apprendre à les utiliser en toute sécurité et efficacement.

18
ulty4life

Si le plain external est un anti-pattern parce qu'il peut casser votre référentiel, alors un avec une révision explicite ne devrait pas.

Extrait de svn book :

Une définition externe est un mappage d'un répertoire local vers l'URL ** - et éventuellement une révision particulière - ** d'une ressource versionnée.

Je pense que tout dépend de votre objectif d'utiliser la fonctionnalité, ce n'est pas un anti-motif en soi.

9
smoothdeveloper

Il y a des failles évidentes dans les externes Subversion, mais nous semblons les utiliser raisonnablement avec succès pour inclure des bibliothèques (à la fois les nôtres et celles du fournisseur) dont dépend le projet actuel. Je ne les vois donc pas comme un "anti-modèle". Les points d'utilisation importants pour moi sont:

  • Ils pointent vers une révision ou une balise spécifique (jamais la tête) de l'autre projet.
  • Ils sont insérés dans le projet courant bien loin de son propre code source, etc. (par exemple dans un sous-répertoire appelé "support files").
  • Ils se réfèrent uniquement aux fichiers "d'interface" des autres projets (par exemple, dossier d'inclusion) et aux bibliothèques binaires (c'est-à-dire que nous n'obtenons pas la source complète de l'autre projet).

Je serais moi aussi intéressé par les risques majeurs de cet arrangement et par de meilleures approches.

8
luapyad

Dire que a est b ne fait pas a a b sauf si vous dites pourquoi il en est ainsi.

Le principal défaut que je vois avec les références externes dans Subversion est que vous n'êtes pas assuré que le référentiel est présent lorsque vous mettez à jour votre copie de travail.

Les références externes Subversion peuvent être utilisées et abusées, et la fonction elle-même n'est rien d'autre que cela, une fonction . On ne peut pas dire que ce soit un motif , ni un anti-motif .

J'ai lu la réponse de la personne que vous citez et je dois dire que je ne suis pas d'accord. Si votre projet nécessite des fichiers version XYZ d'un référentiel, une référence Subversion externe peut facilement vous le donner.

Oui, vous pouvez mal l'utiliser en ne spécifiant pas spécifiquement la version de cette référence dont vous avez besoin. Cela vous posera-t-il des problèmes? Probable!

Est-ce un anti-modèle? En fait ça dépend. Si vous suivez le lien donné par l'auteur du texte que vous citez, c'est à dire. ici , alors non. Que quelque chose puisse être utilisé pour fournir une mauvaise solution ne fait pas de toute la méthode de le faire un anti-modèle . Si c'était la règle, alors je dirais que les langages de programmation sont en gros des antipatterns, car dans chaque langage de programmation vous pouvez faire de mauvaises solutions .