Quelle est la manière la plus efficace de partager du code entre des applications .NET?

15

Dans notre travail, nous avons plusieurs applications .net différentes qui partagent beaucoup de fonctionnalités de base. Nous avons construit ces applications en utilisant une architecture propre à n niveaux, mais nous avons atteint ce moment où nous nous rendons compte que nous avons ré-implémenté les mêmes fonctions plusieurs fois. Évidemment, cela viole DRY, et nous aimerions corriger cela. Nous utilisons déjà Nuget avec un certain succès pour le code de colle commun (câblage IoC, journalisation, paramètres), mais nous aimerions également partager nos couches de données et d'entreprise entre toutes nos applications. L'idée est que l'interface utilisateur ne traiterait que les parties de la couche métier dont elle a réellement besoin.

Cela semble être un problème simple au premier abord, mais le développement en cours pourrait fournir des écueils et nous ne savons pas comment procéder. Disons que nous créons notre couche d'entreprise unique pour les gouverner tous. Par souci de concision, je l'appellerai «Fondation». Nous portons nos applications pour utiliser la Fondation, et tout fonctionne à merveille. La Fondation est distribuée à des couches d'interface utilisateur légères via nuget, et nous avons l'air bien. Mais ensuite, nous commençons à ajouter des fonctionnalités à nos applications et nous rencontrons des problèmes.

Disons que nous travaillons sur le projet A et que nous ajoutons une nouvelle fonctionnalité qui nécessite des modifications de Foundation. Nous apportons les modifications à la fondation (Foundation-A) et les poussons vers le flux de pépites en tant que package instable. Le projet A obtient le dernier package nuget, et tout va bien. Pendant ce temps, un autre développeur travaille sur le projet B. Il obtient la dernière fondation du contrôle de code source, mais la prend dans une branche stable, de sorte qu'il ne comporte pas de modifications dans le projet A. Il fait des changements et crée Foundation-B. Et tout va bien. Mais ensuite, nous découvrons les fonctionnalités d'implémentation de Foundation-A et Foundation-B qui pourraient réellement partager du code, nous les combinons donc. Pendant ce temps, Foundation-C flotte là-bas avec ses propres changements. Finalement, Foundation-B est prêt pour la production, nous le poussons donc. Mais ensuite, nous devons mettre à jour la production A, B,

Cela semble pouvoir fonctionner, mais nous sommes inquiets de travailler avec différents schémas de base de données et de garder tout synchronisé entre les différentes branches du référentiel Foundation ainsi que les référentiels Project A, B et C. Il semble que cela prendra probablement beaucoup de travail manuel, ce qui ouvre la possibilité d'erreurs. Je voudrais que ce soit aussi automatisé que possible.

Voici la pile que nous utilisons: C #, TFS avec intégration continue, Nuget. Nos applications sont toutes de différents types d'applications ASP.NET. Nous sommes prêts à examiner différents SCM si cela facilite les choses.

Je cherche des moyens de garder Nuget sain d'esprit avec nos différentes branches de code source. Nous ne voulons pas pousser accidentellement le code de développement en production car nous référençons le mauvais paquet Nuget.

Josh
la source
De plus, si ce n'est pas un bon forum pour une discussion comme celle-ci, quelqu'un peut-il en suggérer un meilleur?
Josh

Réponses:

9

Nous apportons les modifications à la fondation (Foundation-A) et les poussons vers le flux de pépites en tant que package instable.

Voici où commence votre problème ... Ne faites pas ça.

Toute modification apportée à Foundation v1.0 devrait être intrinsèquement valable pour tous les consommateurs de Foundation, sinon elle n'appartient pas à Foundation. Donc, lorsque vous créez le paquet nuget, faites-le en tant que version officielle et stable de Foundation (c'est-à-dire v1.1), ou ne le faites pas du tout.

Le projet B devrait construire ses améliorations Foundation comme il le ferait normalement, mais (dans un bon mode de gestion des sources) devrait fusionner dans les modifications du tronc (v1.1) avant de pousser une fondation stable (v1.2) vers nuget.

D'autres projets qui peuvent utiliser les améliorations de la Fondation peuvent mettre à niveau leurs références de nuget le cas échéant, ou s'en tenir aux anciennes versions s'ils en ont besoin.

Je suis d'accord avec @Giedrius ; cela me semble être davantage un problème de contrôle de source / branchement dans le sens où si la branchement / fusion de Foundation est correctement gérée, les problèmes de gestion de paquet deviennent sans objet.

Eric King
la source
Oui, cela a du sens. Le problème réside dans l'application pratique. Lorsque vous effectuez des mises à jour de Foundation for v1.1, vous souhaitez utiliser ces modifications dans le projet B lors de votre développement. Si la façon dont vous avez partagé ce code est via nuget, vos options sont les suivantes: 1) Publier un nouveau package nuget, ou 2) Copier manuellement les DLL autour. Aucun de ceux-ci ne semble être un bon choix.
Josh
Une partie de cela peut être atténuée en ayant une suite de tests efficace, mais il y aura toujours des allers-retours lors de l'ajout de fonctionnalités.
Josh
@Josh Oui, les mises à jour de Foundation doivent être complètes et testables indépendamment de la façon dont Project B va les utiliser (car elles vont dans une bibliothèque partagée), donc `` publier un nouveau paquet de pépites '' est la voie naturelle à suivre. N'importez pas et n'utilisez pas Foundation v.Next dans Project B tant qu'il ne s'agit pas d'un package stable dans nuget. Il faut un peu de discipline, mais c'est beaucoup mieux que le gâchis de le faire autrement.
Eric King
1
Je comprends parfaitement ce que vous dites, mais je ne pense pas que ce soit très réaliste. Au fur et à mesure que vous développez une fonctionnalité, même si vous avez entièrement testé la logique métier et la couche d'accès aux données, il y aura des modifications avant qu'elle ne soit mise en production. Vous réalisez peut-être que vous devez ajouter une autre propriété à la logique métier, ou le propriétaire du produit revient avec des modifications ou des clarifications. Peut-être que certaines de vos hypothèses simplificatrices étaient fausses. Ce sont des choses qui arrivent tout le temps. Si vous êtes limité au verrouillage de la libération de votre logique de base, cela semble en effet très limité.
Josh
2
Comme nous le faisons depuis quelques mois, c'est essentiellement ce sur quoi nous nous sommes installés. Je pense que j'étais trop inquiet d'avoir un processus formel. Une fois que nous avons commencé à travailler dessus, les choses se sont très bien déroulées. Merci pour votre contribution.
Josh
4

Refactorisez votre code en double en fonctions applicables de manière plus abstraite et placez-les dans leurs propres bibliothèques ou frameworks. Rendez-les faiblement couplés et indépendants de l'architecture, et vous ne devriez jamais avoir de problème. Si vous avez besoin d'inspiration, étudiez comment le framework .NET résume les concepts à l'aide d'éléments tels que les interfaces, les génériques et les modèles de logiciels tels que Dispose().

N'oubliez pas non plus que tout le code en double n'est pas vraiment dupliqué; une partie est du code de colle ou du code qui est par ailleurs nécessaire pour maintenir l'architecture, alors ne vous inquiétez pas d'être trop SEC.

Robert Harvey
la source
Peut-être que je n'étais pas aussi clair que possible dans ma question. C'est à propos de ce qui vient ensuite. Vous avez fait tout cela, et maintenant vous devez partager efficacement votre code entre vos différents projets. Quelqu'un dit "utilisez simplement nuget pour cela" et cela sonne bien jusqu'à ce que vous entriez dans les détails et rencontriez des problèmes - comme la façon de synchroniser les différents changements de différentes branches et applications.
Josh
Eh bien, je suis d'accord avec Eric King. Le code de base doit être poussé en tant que version stable, et non instable. La clé est de maintenir une API stable: si vous savez que les signatures de vos méthodes de fondation ne changeront pas, vous pouvez pousser les méthodes en toute sécurité vers Foundation et les refactoriser plus tard sans rien casser.
Robert Harvey
4

Réutilisation du code

Plusieurs approches de la réutilisation du code ont été appréciées au fil des ans. Chaque approche a sa place, et surtout ses problèmes , mais les moyens viables de réutiliser le code dans .NET sont:

  1. Bibliothèque commune. Le code qui est nécessaire à plusieurs endroits est placé dans une bibliothèque commune, et toutes les autres parties de la base de code ont alors une seule référence à ce code. Le principal inconvénient est que vous vous retrouvez avec la majorité de votre projet en fonction de cette bibliothèque qui contient de nombreuses fonctions non liées. C'est une mauvaise idée du point de vue de l'assurance qualité.

  2. Code source commun. Le code nécessaire à plusieurs endroits est écrit une fois et placé dans un fichier source dans une structure de répertoire commune. Tous les projets qui ont besoin de ce code incluent alors ce fichier comme l'un de leurs fichiers source. Cela permet la réutilisation du code et les avantages de l'écriture unique en utilisent plusieurs. Pourtant. Son inconvénient est qu'il devient possible de compiler différentes parties du projet avec différentes versions de ce code - ce qui peut introduire des défauts subtils qui peuvent être très difficiles à détecter et à identifier par l'assurance qualité.

  3. Un service. Le code commun est implémenté en tant que service auquel d'autres aspects peuvent accéder. Cela présente l'avantage qu'il y aura un seul service dans un déploiement et évite les dépendances. Cependant, cela introduira une latence et des échecs. Ce type d'approche fonctionne bien dans les grands produits distribués où la haute disponibilité et la tolérance aux pannes sont déjà comprises et gérées.

Gérer NuGET

Ici, vous avez un problème beaucoup plus intéressant. Gestion de plusieurs configurations. Mon conseil ici est de ne pas gérer une clientèle diversifiée avec différentes versions de code, mais avec des fichiers de configuration. Il y a au moins 3 couches de données de configuration à gérer. Configuration de produit (interne) de base que le client ne voit jamais. Les options de configuration par défaut que votre client peut modifier et la dernière couche d'options de configuration que votre client a modifiée. En séparant ces différentes couches, vous pourrez déployer des mises à niveau sans détruire les configurations de vos clients.

Michael Shaw
la source
1

Je pense que le problème n'est pas dans le contrôle de nuget / source / branchement, mais dans ce qui se glisse dans le code de collage.

Robert a une bonne réponse, juste pour voir l'image entière, je recommande de penser aux dépendances que ces utilitaires communs apporteront dans chaque projet:

http://ayende.com/blog/3986/let-us-burn-all-those-pesky-util-common-libraries http://blog.jordanterrell.com/post/CommonUtility-Libraries-Dead.aspx

La meilleure façon d'éviter l'enfer que vous rencontrez est d'ouvrir votre code de colle. De cette façon, vous commencerez à vous soucier qu'aucune logique métier ne deviendrait publique, donc aucune dépendance concrète de projet ne se glisserait dans le code de colle, qu'elle serait suffisamment abstraite pour être réutilisée par n'importe qui, même en dehors de votre entreprise - et si ce collage le code sera assez bon - vous obtiendrez également la contribution de la communauté.

Giedrius
la source
Je ne parle pas de la gestion du code de colle. Nous avons déjà une solution pour cela et cela fonctionne bien. Je parle du partage de la logique métier. Par exemple, nos applications traitent de la gestion des organisations et des personnes. Donc, nous devons créer une personne, et il y a un tas de règles métier associées à la façon dont une personne doit être créée. Au lieu de le créer plusieurs fois, nous voulons avoir un package qui gère tout, de la construction de l'objet à la persistance que nous partageons entre les différents projets qui ont besoin de créer des gens.
Josh
0

La solution est simple: créez un projet séparé pour lui et gérez-le comme une chose distincte: ses propres exigences, tests, conventions, documentation, planification, personnes, etc. De cette façon, vous vous assurez que la qualité reste élevée et que les éventuels changements de rupture seront évalué avant de créer un problème.

Ou encore mieux: rendez-le "open-source" au sein de votre organisation. Tout le monde peut donc modifier le code, mais seules quelques personnes sélectionnées auront les droits de validation complets. Et ces personnes seront responsables d'assurer la qualité et les fonctionnalités correctes.

Euphorique
la source