Séparation des projets Java

12

J'ai un grand projet java et nous utilisons maven pour notre cycle de construction. Ce projet est largement utilisé - dans d'autres projets, dans diverses applications, dont certains y sont contenus et d'autres ailleurs ... Pour être honnête, c'est un peu le bordel (divers bits ajoutés à différents moments pour des fins), et je voudrais le nettoyer un peu. De plus, il n'est pas entièrement testé (beaucoup de bits ont été ajoutés sans tests d'unité et d'intégration appropriés), et il y a des tests qui prennent beaucoup de temps à exécuter ou qui ne passent pas réellement ... (uh-oh) - donc les tests sont désactivés dans le cycle de construction de maven (encore une fois, uh-oh).

Je pense à séparer ce grand projet en plus petits projets spécifiques, de telle sorte que le sous-projet «final» (ou plusieurs sous-projets) reprendrait les différents sous-projets dont il aurait besoin.

Ma pensée est la suivante:

  • si je sépare le grand projet en plusieurs sous-projets, cela montre clairement quelle est la responsabilité de chaque projet.
  • en me séparant en sous-projets, je peux ensuite nettoyer les tests de chaque sous-projet individuellement et activer les tests de ce sous-projet dans le cycle de construction de maven.

Je suis légèrement préoccupé par l'impact que cela pourrait avoir sur le temps de construction.

  • L'imposition d'une structure sur le grand projet (c'est-à-dire dans des sous-projets plus petits) ralentirait-elle le compilateur?

De plus, j'ai une légère inquiétude sur l'impact que cela pourrait avoir sur le temps d'édition dans les IDE (nous utilisons principalement Intellij). Intellij semble construire chaque projet tour à tour à travers l'arbre de dépendance - c'est-à-dire que si C dépend de B dépend de A, et je change A, il n'essaiera pas de construire B à moins que A ne compile, et ainsi de suite. C'est sans doute avantageux, mais j'ai constaté que si - par exemple, je change une interface en A qui est largement utilisée en B et C, il faut un certain temps pour corriger toutes les erreurs de ce changement ...

Une autre question est de savoir comment utiliser les classes d'usine. Certains aspects du projet dépendent de pots externes. De temps en temps (heureusement pas souvent), ceux-ci sont mis à jour et nous devons migrer. Nous avons tendance à gérer cela en utilisant une classe Factory qui pointe vers les versions correctes du code externe (nous n'avons donc pas à modifier toutes les implémentations dans la base de code).

Pour le moment, tout cela fait partie du grand projet, mais je pense qu'en passant à des sous-projets, je pourrais développer un nouveau projet pour la mise en œuvre d'un nouveau code externe, m'assurer que le sous-projet est entièrement fonctionnel et testé, et puis changez les dépendances / classe d'usine dans le projet utilisateur. Cependant, cela est rendu plus compliqué par l'utilisation extensive d'interfaces tout au long du grand projet. Par exemple

  • sous-projet A - contient des interfaces
  • sous-projet B - dépend de A pour les interfaces et l'ancien pot externe
  • sous-projet C - dépend de B (et donc de A et de l'ancien pot externe), et contient une classe Factory qui utilise les implémentations d'interfaces de B

Si je dois changer le pot externe de B, je peux:

  • créer le sous-projet B_ii - dépend à nouveau de A, et maintenant le nouveau pot externe
  • une fois pleinement fonctionnel, je peux ajouter la dépendance de C à B_ii, et changer la classe Factory pour utiliser les nouvelles implémentations d'interfaces.
  • lorsque tout fonctionne, je peux ensuite supprimer la dépendance de C par rapport au B d'origine et, si vous le souhaitez, supprimer le sous-projet B.

  • Est-ce une façon sensée de procéder?

Donc, en général, mes questions sont:

  • Quelqu'un a-t-il une expérience de la rupture de grands projets? Y a-t-il des conseils / astuces que vous seriez prêt à partager?
  • Quel impact cela a-t-il eu sur vos temps de développement et de construction?
  • Quels conseils pourriez-vous offrir pour structurer une telle rupture d'un tel projet?
paiement
la source
Notez que vous pouvez créer un projet parent avec A, B et C extraits séparément les uns à côté des autres. Cela permet par exemple à IntelliJ d'avoir tous les trois en mémoire en même temps, et de faire des refactorings à travers les limites du module.
Thorbjørn Ravn Andersen

Réponses:

10

Je vais faire une première coupe rapide à ce sujet (excellent Q BTW!):

L'imposition d'une structure sur le grand projet (c'est-à-dire dans des sous-projets plus petits) ralentirait-elle le compilateur?

Pas suffisamment pour que cela importe, le surcoût est en fait dans les invocations Maven.

De plus, j'ai une légère inquiétude sur l'impact que cela pourrait avoir sur le temps d'édition dans les IDE (nous utilisons principalement Intellij). Intellij semble construire chaque projet tour à tour à travers l'arbre de dépendance - c'est-à-dire que si C dépend de B dépend de A, et je change A, il n'essaiera pas de construire B à moins que A ne compile, et ainsi de suite. C'est sans doute avantageux, mais j'ai constaté que si - par exemple, je change une interface en A qui est largement utilisée en B et C, il faut un certain temps pour corriger toutes les erreurs de ce changement ...

Différents IDE ont leurs différentes forces en ce qui concerne les liaisons Maven et la gestion des dépendances. La situation actuelle semble être que cela fonctionne principalement sur les derniers Eclipse, Netbeans et IntelliJ - mais vous devrez enseigner à vos développeurs la double urgence de "Actualiser les fichiers source à partir du disque et reconstruire tous les projets maven associés".

Je trouve que je dois le faire de moins en moins ces jours-ci. Avoir un disque SSD fait une énorme différence ici BTW.

couper les paragraphes des classes d'usine

La gestion des dépendances est extrêmement importante, quelle que soit la technologie (Maven / Ivy / autre) utilisée pour vous aider à la mettre en œuvre.

Je commencerais par obtenir les rapports détaillés du plugin de dépendance Maven et ferais le point sur ce que vous avez. De manière générale, vous définissez la dépendance dans la gestion des dépendances du POM aussi haut que possible dans la chaîne alimentaire, mais pas plus haut. Donc, si deux de vos sous-modules utilisent une dépendance externe, transférez-la dans leur POM parent et ainsi de suite.

La mise à niveau des fichiers JAR externes doit toujours être effectuée comme un mini-projet approprié. Évaluez pourquoi vous effectuez une mise à niveau, modifiez le code source pour profiter de toutes les nouvelles fonctionnalités / corrections de bogues, etc. Le simple fait de sauter la version sans cette analyse et ce travail vous causera des ennuis.

Donc, en général, mes questions sont:

Quelqu'un a-t-il une expérience de la rupture de grands projets? Y a-t-il des> trucs / astuces que vous seriez prêt à partager?

  • Les interfaces et l'injection de dépendance sont vos amis.
  • Le livre de Michael Feather sur la gestion efficace du code hérité est une lecture incontournable.
  • Les tests d'intégration sont votre ami
  • Diviser les sous-projets en foo-api (interfaces uniquement!) Et foo-core et avoir des modules qui ne dépendent que de foo-api aide beaucoup et impose la séparation
  • Les modules Jboss et / ou OSGi peuvent aider à appliquer une séparation propre

Quel impact cela a-t-il eu sur vos temps de développement et de construction?

Impact très mineur sur les temps de développement et de construction - un gain de temps considérable pour notre pipeline global de livraison continue.

Quels conseils pourriez-vous offrir pour structurer une telle rupture d'un tel projet?

Faites les petites choses correctement et les grandes choses ont tendance à tomber proprement par la suite. Donc, divisez les choses petit à petit - ne procédez pas à une restructuration massive du lot à moins d'avoir un pourcentage élevé de couverture avec vos tests d'intégration.

Ecrivez des tests d'intégration avant la scission - vous devriez plus ou moins obtenir les mêmes résultats après la scission.

Dessinez des diagrammes de la modularité que vous avez maintenant et où vous voulez vous rendre. Concevez des étapes intermédiaires.

N'abandonnez pas - certains rasages Yak jettent désormais les bases pour pouvoir "rapidement construire et refactoriser sans crainte" la fiche Shameless -> de Ben and I's The Well-Grounded Java Developer .

Bonne chance!

Martijn Verburg
la source
0

Mon point de vue sur ce point n'est séparé que lorsque cela est nécessaire. Cependant, cela soulève la question suivante: comment puis-je déterminer si cela est nécessaire?

  • Lorsque l'artefact est différent (c.-à-d. Ne construisez pas le fichier EAR, WAR, JAR, intégration-testing-jar dans le même projet).
  • Lorsque, pendant la séparation, vous remarquez que du code doit exister dans plusieurs artefacts, les refactoriser en un nouveau.
  • Quand un autre projet en dehors de votre équipe veut utiliser quelque chose que vous avez dans votre projet.

L'une des raisons est que les développeurs doivent gérer plusieurs projets et essayer de comprendre à part quel package Java est le projet auquel il doit appartenir. J'ai été sur des projets où il est devenu vraiment anémique et j'ai eu un projet qui avait seulement quatre classes implémentant une fonctionnalité juste parce que c'est la direction architecturale. C'était également de retour avant que Maven ne soit populaire, donc les chemins de classe et ce qui n'a pas besoin d'être configuré à la fois sur les scripts IDE et Ant.

L'autre raison est que vous auriez plus de pièces mobiles à traiter en termes de plomberie des fichiers et que vous auriez probablement des spaghettis de dépendance avant de le savoir.

Le refactoring est également plus facile au sein d'un projet plutôt qu'entre projets.

Si le temps de construction est un problème, fournissez simplement un meilleur matériel.

Archimedes Trajano
la source