229 votes

Que faire d’un fichier source 11000 lignes C++ ?

Nous avons donc cette énorme (11000 lignes énorme?) mainmodule.cpp fichier source dans notre projet et à chaque fois que j'ai toucher je grincer des dents.

Comme ce fichier est donc centrale et des grands, il continue d'accumuler plus de et plus de code et je ne peux pas penser à une bonne façon de le faire réellement commencer à se rétrécir.

Le fichier est utilisé et activement changé dans plusieurs (> 10) les versions de maintenance de notre produit et il est vraiment difficile de refactoriser. Si je "simplement" les diviser, disons pour commencer, en 3 fichiers, puis de fusionner les modifications de versions de maintenance deviendra un cauchemar. Et aussi si vous partagez un fichier avec une longue et riche histoire, de suivi et de vérification vieux changements dans l' SCC histoire devient tout à coup beaucoup plus difficile.

Le fichier contient essentiellement de la "main class" (principal travail interne de régulation et de coordination) de notre programme, de sorte que chaque fois qu'une fonctionnalité est ajoutée, il influe également sur ce fichier et à chaque fois qu'il grandit. :-(

Que feriez-vous dans cette situation? Toutes les idées sur la manière de faire de nouvelles fonctionnalités à un fichier source séparé, sans perturber le fonctionnement de l' SCC flux de travail?

(Note sur les outils: Nous utilisons C++ avec Visual Studio; Nous utilisons AccuRev comme SCC mais je crois que le type d' SCC n'a pas vraiment d'importance ici, Nous utilisons Araxis Merge faire de comparaison et fusion de fichiers)

129voto

Kirill V. Lyadvinsky Points 47627

La fusion ne sera plus un cauchemar que ce sera quand vous aurez 30000 LOC fichier dans l'avenir. Donc:

  1. Arrêter l'ajout de plus de code de ce fichier.
  2. Split.

Si vous ne pouvez pas arrêter de codage au cours de processus de refactorisation, vous pouvez laisser ce gros fichier comme c'est au moins pour un temps, sans ajouter plus de code à elle: car il contient une "classe principale", vous pouvez hériter d'elle et de garder classe héritée(es) avec les fonctions surchargées dans plusieurs nouvelles petites et bien conçu fichiers.

86voto

Steve Jessop Points 166970
  1. Trouver un peu de code dans le fichier qui est relativement stable (pas d'évolution rapide, et ne varie pas beaucoup entre les branches) et pourrait se présenter comme une unité indépendante. La déplacer dans son propre fichier, et d'ailleurs dans sa propre classe, dans toutes les branches. Parce que c'est stable, cela ne cause pas (beaucoup) de "maladroite" fusions qui doivent être appliquées à un fichier différent de celui qu'elles ont été faites à l'origine, lors de la fusion à la modification d'une branche à l'autre. Répétez.

  2. Trouver un peu de code dans le fichier qui, fondamentalement, ne s'applique qu'à un petit nombre de branches, et pourrait être le seul. N'importe pas si ça change vite ou pas, en raison du petit nombre de branches. Déplacer dans ses propres classes et les fichiers. Répétez.

Donc, nous nous sommes débarrassés du code qui est la même chose partout, et le code qui sont spécifiques à certaines branches.

Cela vous laisse avec un noyau de mal gérées code - il est nécessaire partout, mais c'est différent dans chaque branche (et/ou qu'il est en constante évolution, de sorte que certaines branches sont en cours d'exécution derrière les autres), et pourtant, c'est dans un seul fichier que vous avez tenté en vain de fusion entre les branches. Arrêter de faire ça. Branche le fichier de façon permanente, peut-être en le renommant dans chaque branche. Ce n'est pas "principale" de plus, c'est le "principal de configuration X". OK, donc vous perdez la possibilité d'appliquer la même modification à plusieurs branches par la fusion, mais c'est en tout cas la base de code où la fusion ne fonctionne pas très bien. Si vous êtes d'avoir à gérer manuellement les fusions de toute façon de traiter les conflits, alors il n'y a aucune perte d'appliquer manuellement indépendamment sur chaque branche.

Je pense que vous avez tort de dire que le genre de la CSC n'a pas d'importance, parce que par exemple git de la fusion de capacités sont sans doute mieux que la fusion de l'outil que vous utilisez. Ainsi, le cœur du problème, "la fusion est difficile de" se produit à des moments différents pour les différents Clusters. Cependant, vous avez peu de chances d'être en mesure de changer de Scc, de sorte que le problème est probablement pas pertinent.

67voto

Brian Rasmussen Points 68853

Il me semble que vous êtes confronté à un certain nombre d'odeurs de code ici. Tout d'abord la classe principale semble contrevenir à la ouvert/fermé principe. On dirait également que c'est de la manipulation de trop de responsabilités. Pour cette raison, je suppose que le code pour être plus fragile qu'elle ne doit l'être.

Même si je peux comprendre vos préoccupations en matière de traçabilité à la suite d'un remaniement, je m'attends à ce que cette classe est plutôt difficile à maintenir et à améliorer et que tout changement que vous faites sont susceptibles de causer des effets secondaires. Je suppose que le coût de ces emportent sur le coût de la refactorisation de la classe.

En tout cas, depuis les odeurs de code ne fera que s'aggraver avec le temps, au moins à un certain point, le coût de ces emportent sur les coûts de refactoring. À partir de votre description, je suppose que vous avez passé le point de basculement.

Refactoring cela devrait être fait par petites étapes. Si possible ajouter des tests automatisés pour vérifier le comportement actuel avant de refactoring quoi que ce soit. De choisir de petites zones isolées de la fonctionnalité et de l'extrait de ces types de afin d'en déléguer la responsabilité.

En tout cas, cela ressemble à un projet d'envergure, alors bonne chance :)

49voto

Benoît Points 10901

La seule solution que j'ai jamais imaginé de tels problèmes de la façon suivante. Le gain réel par la méthode décrite est progressivité des évolutions. Pas de révolutions ici, sinon vous aurez des ennuis très rapide.

Insérer un nouveau rpc classe au-dessus de l'original de la classe principale. Pour l'instant, il suffisait de rediriger tous les appels vers le courant principal de la classe, mais visent à rendre l'API de cette nouvelle classe aussi clair et concis que possible.

Une fois que cela a été fait, vous obtenez la possibilité d'ajouter de nouvelles fonctionnalités dans de nouvelles classes.

Comme pour les fonctionnalités existantes, vous devez les faire progresser dans de nouvelles classes comme ils deviennent assez stable. Vous perdrez de la CSC de l'aide pour ce morceau de code, mais il n'y a pas beaucoup qui peut être fait à ce sujet. Il suffit de choisir le bon timing.

Je sais que ce n'est pas parfait, mais j'espère que cela peut aider, et le processus doit être adapté à vos besoins!

Des informations supplémentaires

Notez que Git est un CSC qui peuvent suivre des morceaux de code à partir d'un fichier à l'autre. J'ai entendu de bonnes choses à ce sujet, de sorte qu'il pourrait aider pendant que vous êtes en train d'évoluer, de votre travail.

Git est construit autour de la notion de blobs qui, si je comprends bien, représentent des morceaux de fichiers de code. Placer ces morceaux dans les différents fichiers et Git va les trouver, même si vous les modifiez. En dehors de la vidéo à partir de Linus Torvalds mentionné dans les commentaires ci-dessous, je n'ai pas été en mesure de trouver quelque chose de clair à ce sujet.

30voto

fdasfasdfdas Points 51

Dire de Confucius : « première étape pour sortir du trou est d’arrêter de creuser le trou. »

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X