web-dev-qa-db-fra.com

J'ai changé une signature de méthode et j'ai maintenant plus de 25 000 erreurs. Et maintenant?

J'ai commencé un nouvel emploi récemment où je travaille sur une très grande application (15M loc). Dans mon travail précédent, nous avions une application de taille similaire, mais (pour le meilleur ou pour le pire), nous avons utilisé OSGi, ce qui signifie que l'application a été décomposée en de nombreux microservices qui pouvaient être modifiés, compilés et déployés indépendamment. La nouvelle application n'est qu'une grande base de code, avec peut-être quelques .dll.

Je dois donc changer l'interface de cette classe, car c'est ce que mon patron m'a demandé de faire. Ils l'ont d'abord écrit avec des hypothèses qui ne se généralisaient pas trop bien, et depuis un certain temps, ils évitent le problème de la refactorisation car il est si étroitement couplé. J'ai changé d'interface et maintenant il y a plus de 25 000 erreurs. Certaines des erreurs se trouvent dans des classes avec des noms de sondage importants comme "XYZPriceCalculator" qui vraiment ne devraient pas se casser. Mais je ne peux pas démarrer l'application pour vérifier si elle fonctionne jusqu'à ce que toutes les erreurs soient résolues. Et de nombreux tests unitaires font directement référence à cette interface, ou sont couplés à des classes de base qui font référence à cette interface, donc simplement les réparer est une tâche assez énorme en soi. De plus, je ne sais pas vraiment comment toutes ces pièces s'assemblent, donc même si je pouvais le faire démarrer, je ne sais pas vraiment à quoi cela ressemblerait si les choses étaient brisées.

Je n'ai jamais vraiment fait face à un problème comme celui-ci lors de mon dernier emploi. Que fais-je?

169
user788497

25000 erreurs signifient essentiellement "ne touchez pas à cela". Changez-le en arrière. Créez une nouvelle classe qui a l'interface souhaitée et déplacez lentement les consommateurs de la classe vers la nouvelle. Selon la langue, vous pouvez marquer l'ancienne classe comme obsolète, ce qui peut provoquer toutes sortes d'avertissements du compilateur, mais ne cassera pas réellement votre build.

Malheureusement, ces choses se produisent dans les anciennes bases de code. Il n'y a pas grand-chose que vous puissiez faire à ce sujet, sauf lentement pour améliorer les choses. Lorsque vous créez les nouvelles classes, assurez-vous de les tester correctement et de les créer à l'aide des principes SOLID afin qu'elles soient plus faciles à modifier à l'avenir.

350
Stephen

Diviser et conquérir avec des refactorisations

Souvent, diviser le changement que vous devez effectuer en étapes plus petites peut vous aider, car vous pouvez ensuite effectuer la plupart des étapes plus petites d'une manière qui ne casse pas du tout le logiciel. Les outils de refactoring aident beaucoup à ces tâches.

Diviser

Tout d'abord, identifiez les plus petits changements possibles (en termes de changements logiques, pas en termes de LoC modifié) qui résument le changement que vous souhaitez réaliser. Essayez surtout d'isoler les étapes qui sont de purs refactorings et qui peuvent être effectuées par des outils.

Conquérir

Pour les cas compliqués comme le vôtre, il peut être judicieux d'effectuer une petite refactorisation à la fois, puis de laisser le problème reposer, afin que tous les systèmes d'intégration continue puissent vérifier le changement, et peut-être que l'équipe de test a également regardé. Cela valide les étapes que vous effectuez.

Pour effectuer une refactorisation particulière, vous avez absolument besoin d'un support d'outils pour un cas où vous avez 25 000 sites d'appel de la méthode que vous souhaitez modifier. Peut-être la recherche et le remplacement fonctionnent également, mais pour un cas aussi critique, cela me ferait peur.

Exemple

En C #, par exemple, il est possible d'utiliser Resharper à changer la signature d'une méthode. Si le changement est assez simple, par ex. en ajoutant un nouveau paramètre, , vous pouvez spécifier la valeur à utiliser sur les sites d'appel qui auraient sinon une erreur de compilation.

Vous êtes alors immédiatement dans une base de code sans erreur et pouvez exécuter tous les tests unitaires, qui passeront, car il s'agissait uniquement d'une refactorisation.

Une fois que la signature de la méthode semble bonne, vous pouvez remplacer les valeurs ajoutées par Resharper comme arguments au paramètre nouvellement introduit. C'est plus une refactorisation plus, mais vous avez une base de code sans erreur et pouvez exécuter les tests après chaque ligne que vous modifiez.

Parfois ça ne marche pas

C'est une approche très utile pour des cas comme le vôtre, où vous avez beaucoup de sites d'appels. Et vous avez maintenant un logiciel qui fonctionne, il peut donc être possible de faire de petites étapes de refactoring pour changer un peu la signature, puis faire une autre.

Malheureusement, cela ne fonctionnera pas si le changement de signature est trop complexe et ne peut pas être décomposé en petits changements. Mais c'est rare; la division du problème en problèmes plus petits montre généralement que c'est c'est possible.

79
theDmi

Clarifiez votre tâche avec votre patron pour l'aider à comprendre le problème et vos besoins en tant que développeur de logiciels professionnel.

Si vous faites partie d'une équipe, recherchez le développeur principal et demandez-lui des conseils.

Bonne chance.

36
mmehl

Ne le touche pas. Ne commettez rien.

Au lieu de cela, asseyez-vous sur votre chaise et criez "Heeeeelp !!!!!" aussi fort que possible.

Eh bien, pas exactement comme ça, mais demandez conseil à l'un de vos collègues seniors. Si vous avez 25 000 erreurs, vous ne corrigez pas les erreurs, vous corrigez la cause des erreurs. Et un collègue senior devrait être en mesure de vous conseiller comment pour faire le changement que votre patron veut sans les 25 000 erreurs impliquées. Il existe différentes façons de procéder, mais ce qui est bon dépend de votre situation spécifique.

Et il se peut que le patron ait dit à vos collègues seniors de faire le même changement, et ils ont dit "non". Parce qu'ils savaient ce qui allait se passer. Voilà pourquoi on vous a confié le travail.

28
gnasher729

Les API retranchées ne peuvent pas simplement être modifiées. Si vous vraiment devez les changer, anootate et/ou documentez-les comme obsolètes (par tout moyen autorisé par la langue) et documentez l'API à utiliser à la place. L'ancienne API peut ensuite être progressivement supprimée ... peut-être très lentement en fonction de votre budget de refactoring.

22
Kevin Krumwiede

Évaluer

Évaluez si cette modification est nécessaire ou si vous pouvez ajouter une nouvelle méthode et déconseiller l'autre.

Transférer

Si un changement est nécessaire; alors un plan de migration est nécessaire.

La première étape consiste à introduire la nouvelle méthode et à faire en sorte que l'ancienne méthode masse ses arguments afin qu'elle puisse appeler la nouvelle. Cela peut nécessiter de coder en dur quelques éléments; C'est très bien.

C'est un point de commit: vérifiez que tous les tests passent, commit, Push.

Migrer

Le travail chargé migre tous les appelants de l'ancienne méthode vers la nouvelle. Heureusement, cela peut se faire progressivement grâce au transitaire.

Donc vas-y; n'hésitez pas à utiliser des outils pour vous aider (sed étant le plus basique, il y en a d'autres).

Marquez l'ancienne méthode comme obsolète (avec un soupçon de passage à la nouvelle méthode); cela vous aidera à repérer si vous avez oublié quelque chose et vous aidera si un collègue introduit un appel à l'ancienne méthode pendant que vous travaillez dessus.

C'est un point de commit (ou peut-être plusieurs points de commit): vérifiez que tous les tests passent, commit, Push.

Supprimer

Après un certain temps (peut-être aussi peu qu'une journée), supprimez simplement l'ancienne méthode.

10
Matthieu M.

Si votre modification de la signature de méthode n'est qu'un changement de nom, la solution simple consiste à utiliser des outils pour automatiser la modification dans les 25 000 classes qui référencent la méthode en question.

Je suppose que vous avez simplement édité le code manuellement, ce qui a provoqué toutes les erreurs. Je suppose également que vous connaissez bien Java (voir votre référence à OSGi), donc par exemple dans Eclipse (je ne sais pas quel environnement de programmation vous utilisez, mais d'autres environnements ont des outils de refactoring similaires) vous pouvez utiliser "Refactoring -> Renommer" pour mettre à jour toutes les références à la méthode, ce qui devrait vous laisser sans erreur.

Dans le cas où vous apportez d'autres modifications à la signature de méthode que simplement renommer (en changeant le nombre ou les types de paramètres), vous pouvez utiliser "Refactoring -> Changer la signature de méthode". Cependant, vous devrez probablement être plus prudent comme le suggèrent les autres réponses. En outre, quel que soit le type de modification, il peut être tout à fait une tâche de valider toutes ces modifications dans une base de code occupée.

8
MikkelRJ

Voici ma contribution.

J'ai commencé récemment un nouveau travail où je travaille sur une très grande application (15M lignes de code).

Vous n'êtes probablement pas familier avec le projet et ses "fonctionnalités". Avant de taper une seule ligne de code, il est important de bien connaître le projet. Faites donc une restauration de vos modifications et commencez par analyser le code. (Au moins celui affecté)

Comprendre la solution existante vous donne une meilleure perspective de l'endroit où vous vous engagez. Contextualiser la solution et son importance.

Comme l'a souligné @Greg, vous devriez pouvoir tester le code existant pour avoir une référence valide à comparer (tests de régression). Votre solution devrait être capable de générer les mêmes résultats que celle existante. À ce stade, vous ne vous souciez pas de savoir si les résultats sont bons ou non. Le premier objectif est de refactoriser, pas de corriger les bugs. Si la solution existante dit "2 + 2 = 42", votre solution devrait aussi. S'il ne lève pas d'exceptions, la vôtre ne devrait pas non plus. S'il renvoie des valeurs nulles, le vôtre devrait également renvoyer des valeurs nulles. Etc. Sinon, vous compromettrez 25 000 lignes de code.

C'est pour des raisons de rétro-compatibilité.

Pourquoi? Parce qu'en ce moment, c'est votre garantie unique de refactoriser avec succès.

Et de nombreux tests unitaires font directement référence à cette interface ou sont couplés à des classes de base qui font référence à cette interface.

Un moyen de garantir la rétro-compatibilité est urgent pour vous. Voici donc votre premier défi. Isolez le composant pour les tests unitaires.

Gardez à l'esprit que ces 25 000 lignes de code ont été créées en supposant les résultats possibles du code existant. Si vous ne rompez pas cette partie du contrat, vous êtes à mi-chemin de la solution finale. Si vous le faites, eh bien: que la force soit avec vous

Une fois que vous avez conçu et mis en œuvre le nouveau "contrat", remplacez l'ancien. Dépréciez-le ou retirez-le.

J'ai suggéré de laisser les bogues seuls car le refactoring et la correction des bogues sont des tâches différentes. Si vous essayez de les faire avancer ensemble, vous risquez d'échouer dans les deux cas. Vous pensez peut-être que vous avez trouvé des bogues, cependant, ils pourraient être des "fonctionnalités". Alors laissez-les tranquilles (pendant une minute).

25 000 lignes de code me semblent suffisamment problématiques pour me concentrer sur une seule tâche.

Une fois votre première tâche terminée. Exposez ces bugs/fonctionnalités à votre patron.

Enfin, comme @Stephen l'a dit:

Il n'y a pas grand-chose que vous puissiez faire à ce sujet, sauf lentement pour améliorer les choses. Lorsque vous créez les nouvelles classes, assurez-vous de les tester correctement et créez-les en utilisant les principes SOLID afin qu'elles soient plus faciles à changer à l'avenir

6
Laiv

Testez-le.

Tout le monde recommande de refactoriser afin qu'il y ait peu d'impact. Mais avec autant d'erreurs, même si vous réussissez à refactoriser avec aussi peu que 10 lignes de code (vous pouvez probablement), alors vous avez impacté 25 000 flux de code , même si vous n'avez pas eu besoin de les réécrire.

Donc, la prochaine chose à faire est de vous assurer que votre suite de tests de régression réussit avec brio. Et si vous n'en avez pas, faites-en un qui le fera. L'ajout d'une suite complète de tests de régression à votre projet monolithique semble ennuyeux, mais c'est un bon moyen d'augmenter la confiance dans les candidats à la sortie, ainsi que de les libérer plus rapidement si la suite est bien automatisée.

5
Greg