Reformatage et contrôle de version

23

Le formatage du code est important. Même l' indentation compte . Et la cohérence est plus importante que les améliorations mineures. Mais les projets ne disposent généralement pas d'un guide de style clair, complet, vérifiable et appliqué dès le premier jour, et des améliorations majeures peuvent arriver n'importe quel jour. Peut-être que vous trouvez ça

SELECT id, name, address
FROM persons JOIN addresses ON persons.id = addresses.person_id;

pourrait être mieux écrit comme / est mieux écrit que

SELECT persons.id,
       persons.name,
       addresses.address
  FROM persons
  JOIN addresses ON persons.id = addresses.person_id;

tout en travaillant sur l'ajout de colonnes à la requête. Il s'agit peut-être de la plus complexe des quatre requêtes de votre code, ou d'une requête triviale parmi des milliers. Peu importe la difficulté de la transition, vous décidez que cela en vaut la peine. Mais comment suivez-vous les changements de code à travers les principaux changements de formatage? Vous pouvez simplement abandonner et dire "c'est le point où nous recommençons", ou vous pouvez reformater toutes les requêtes dans tout l'historique du référentiel.

Si vous utilisez un système de contrôle de version distribué comme Git, vous pouvez revenir au tout premier commit et reformater votre chemin de là à l'état actuel. Mais c'est beaucoup de travail, et tout le monde devrait suspendre le travail (ou être prêt pour la mère de toutes les fusions) pendant qu'il se déroule. Existe-t-il une meilleure façon de changer l'historique qui donne le meilleur de tous les résultats:

  • Même style dans toutes les commits
  • Travail de fusion minimal

?

Pour clarifier, il ne s'agit pas des meilleures pratiques lors du démarrage du projet, mais plutôt de ce qui devrait être fait lorsqu'une grande refactorisation a été considérée comme une bonne chose ™ mais que vous voulez toujours une histoire traçable? Ne jamais réécrire l'historique est génial si c'est le seul moyen de s'assurer que vos versions fonctionnent toujours de la même manière, mais qu'en est-il des avantages pour les développeurs d'une réécriture propre? Surtout si vous avez des moyens (tests, définitions de syntaxe ou binaire identique après compilation) pour vous assurer que la version réécrite fonctionne exactement de la même manière que l'original?

l0b0
la source
24
Pourquoi voudriez-vous réécrire l'histoire? Il va à l'encontre du but du contrôle de version. Vous voulez vous assurer que l'application que vous avez expédiée il y a 3 mois correspond sans aucun doute à la révision xxxxxx. Même un reformatage trivial est inacceptable.
Simon Bergot
5
J'aime commenter le fait que je le fais avec le tag "Reformater. Pas de changement fonctionnel"
Rig
3
Sur un sujet sans rapport, il semble que vous proposiez de réécrire l'historique Git en reformatant tout le code. Ne donnez pas d'idée aux gens, réécrire l'historique de Git est mauvais pour 99,9% des cas. Le reformatage n'est pas le cas de bord de 0,1%.
Andrew T Finnell
4
Dans certaines langues (je vous regarde, Python), le reformatage peut changer le fonctionnement logique du code. Vous devez être en mesure d'analyser toutes les langues stockées dans votre VCS pour suivre et ignorer les reformatages en toute sécurité.
Joris Timmermans
3
Les reformatages sont des modifications de code et doivent être validés en tant que tels.
David Cowden

Réponses:

26

Effectuez le reformatage en tant que validations distinctes. Cela n'interférera que très peu avec l'historique, et vous devriez pouvoir voir en un coup d'œil quels commits sont juste en train de reformater et qui changent réellement le code. Il pourrait être asymétrique git blameet similaire, mais s'il pointe vers un commit de reformatage uniquement, il est assez simple de rechercher le changement précédent avant cela.

harald
la source
J'ai vu des projets dérailler pendant des semaines parce que l'un des développeurs pensait que c'était une bonne idée. Si vous allez faire cela, comprenez les risques à l'avance et décidez exactement jusqu'où vous allez aller avec le formatage. Je pense que mjfgates a la bonne réponse.
Johntron
1
On dirait que l'équipe en question a de plus gros problèmes que le formatage du code. Mais oui, je ne recommande pas de faire ça à moins que vous ne le pensiez. Si vous souhaitez effectuer des modifications de reformatage, je dirais toujours qu'il vaut mieux les faire en tant que validations distinctes que mélangées avec des modifications fonctionnelles.
harald
Oui, beaucoup de problèmes: PI veut juste avertir les nouveaux développeurs que ce n'est pas aussi simple que cela puisse paraître. Les outils de reformatage en masse sont risqués (surtout si vous le construisez vous-même avec regex - au moins utilisez AST), et si vous vous souciez de la révision du code et du suivi des bogues, cela peut vraiment gâcher votre processus. Personnellement, j'écris mon code pour être cohérent avec le style de chaque fichier, bien que cela ne me dérange pas de revoir le code lorsque quelques fonctions sont reformatées. De nombreux développeurs se bloquent sur le style de code et négligent les problèmes plus importants tels que l'architecture, les processus, les outils, etc.
Johntron
En programmation, rien n'est aussi simple qu'il y paraît :)
harald
13

Ne réécrivez pas l'historique VCS: c'est contraire aux principes VCS.

N'essayez pas d'automatiser la correction du formatage: il traite les symptômes, pas le vrai problème (= les développeurs ne suivent pas les normes de codage).

Définissez la norme de codage et les meilleures pratiques de formatage dans un document commun et obtenez l'accord de tous les développeurs.

Vous mentionnez Git, ce qui est génial, car il est distribué. Avec un DVCS, il est très facile d'appliquer les meilleures pratiques via le flux de travail du contrôleur d'accès . Les gatekeepers rejettent les propositions de fusion (= pull request dans Git) qui ne sont pas conformes aux directives communes. Et je veux dire rejeter , en caractères gras, sinon le codeur en infraction ne prendra pas la peine de suivre les règles et continuera de répéter les mêmes erreurs.

Cette technique fonctionne bien pour moi. Les codeurs veulent que leur travail soit fusionné, donc après quelques erreurs au début, ils commencent à suivre les règles.

Selon la fixation de la base de code existante ... Je recommande de le faire progressivement, peut-être module par module, ou comme cela a du sens pour votre projet. Testez soigneusement à chaque étape. Cela peut sembler stupide, mais des erreurs se produisent même avec des changements insignifiants comme le formatage, alors soyez prêt pour quelques petites bosses sur la route.

janos
la source
1
Voté, car l'auteur indique clairement que cela se situe dans le contexte de projets qui ne commencent pas par "... un guide de style clair, complet, vérifiable et appliqué dès le premier jour". Il ne peut pas traiter le vrai problème, car c'est déjà arrivé. Je suis cependant d'accord avec vous :)
Johntron
2
rejeter signifie qu'il y aura un combat entre les humains et le robot. Été là. Tôt ou tard, le robot aura besoin d'un morceau de code vraiment complexe pour être formaté de manière illisible. Exemples: une chaîne Java est en fait une instruction SQL, mais le robot ne le sait pas; les espaces avant la fermeture des parens peuvent contenir des informations sur la structure du code pour les humains, mais pas pour le robot; les paramètres de fonction sont répartis sur plusieurs lignes de la manière la plus insignifiante ...
18446744073709551615
9

La réponse à votre question est: "Vous ne le faites pas." Je ne connais aucun outil SCM actuel qui puisse suivre les changements de logique à partir du code formaté d'une manière, par le biais d'un changement de formatage majeur et par le biais de modifications supplémentaires après que le code est formaté de la nouvelle manière. Et, vous le savez, perdre l'historique sur un morceau de code n'est pas bon.

Par conséquent, je vais contredire un peu votre première phrase. Formatage du code n'a pas d' importance que beaucoup. C'est joli, mais ce n'est pas pour ça que nous sommes ici. Je comprends aussi bien que quiconque que le dumping dans le vieux code de variante K&R étrange et infernal de quelqu'un avec les retraits à deux espaces est nul (1), mais ... le formatage n'est en fait pas un obstacle à la compréhension de ce qui se passe, sauf si c'est quelque chose d' exceptionnellement pathologique. Et dans ce cas, vous allez quand même avoir des problèmes pour changer le code et ne devriez pas le déranger.

Par conséquent, cela ne vaut pas la peine d'apporter des modifications au code établi STRICTEMENT pour le reformater. Changer les noms des variables, rompre les longues fonctions, tout ce bon truc de refactoring qui change le contenu, oui, mais pas juste un reformatage.

1) - J'ai déjà possédé la visionneuse du presse-papiers de Windows pendant un certain temps. Le tout était un, 150k, module C. J'ai trouvé un endroit où différentes personnes avaient utilisé, je pense, cinq styles d'accolades différents à moins de trente lignes les uns des autres. Mais cette partie des choses a fonctionné. J'ai transporté une impression de ce morceau de code pendant dix ans, mais je ne l'ai pas poussé parce que cette histoire importait, et que le code était dans au moins trois arbres sources (Windows 3.x, NT, future 95) qui vivaient tous dans différents bâtiments.

mjfgates
la source
Dans le passé, en utilisant hg, j'ai trouvé que la fusion par pièces est un outil inestimable pour faire face aux grosses fusions de re-facteur difficiles . Généralement, ce que je ferais, c'est fusionner les commits avant le grand re-facteur, puis fusionner le grand re-facteur lui-même et enfin fusionner les commits depuis le re-facteur. Chacune de ces trois fusions par elles-mêmes est beaucoup plus facile que d'essayer de démêler le désordre qui résulte de toutes les fusions en une seule fois.
Mark Booth
Je suis tout à fait d'accord! De plus, j'ai vu de nombreux développeurs aller trop loin (une version plus récente de moi-même incluse) sur le reformatage et le style de code, et ils finissent par introduire des défauts. Une virgule / point-virgule manquant ici, les déclarations de variables déplacées en haut des fonctions, les boucles for changées en for-each - elles peuvent toutes introduire des bogues subtils. Il faut une habileté trompeuse pour effectuer ces changements en toute sécurité.
Johntron
4

Mais comment suivez-vous les changements de code à travers les principaux changements de formatage?

Les modifications de formatage sont des modifications de code; traitez-les comme vous le feriez pour toute autre modification de votre code. Quiconque a travaillé sur un projet important aura probablement vu des bogues et d'autres problèmes qui ont été créés lorsque quelqu'un a décidé de "simplement" reformater du code.

Mais c'est beaucoup de travail, et tout le monde devrait suspendre le travail (ou être prêt pour la mère de toutes les fusions) pendant qu'il se déroule.

Pourquoi devez-vous tout reformater en même temps? Surtout si le reformatage ne change pas la signification du code, vous devriez pouvoir reformater les fichiers individuellement et les archiver au fur et à mesure. Mieux, faites en sorte que tout le monde dans votre équipe se mette d'accord sur un style (sinon ça ne sert à rien de reformater de toute façon) et demandez-leur de s'occuper du reformatage dans le cadre de leur autre travail. Après un certain temps, vous aurez couvert la majeure partie du code sans perturber le reste du projet.

Caleb
la source
1

Il y a deux approches viables que j'ai vues pour cela.

1. Reformater le code sur commit-hook

Bien qu'il soit initialement épuisant de modifier le code après l'avoir soumis, si votre procédure de reformatage (par exemple astyle ) ne blesse pas le code, c'est une opération sûre. Au fil du temps, toute l'équipe appréciera que tout le code finira par se ressembler. De toute évidence, le fait d'avoir des tests unitaires / automatisés complets garantira que rien ne s'est cassé.

2. Reformatage unique de tout le code

D'après mon expérience, cela est plus dangereux et rend le suivi des problèmes à travers le big-bang difficile, mais c'est possible. L'exécution de tous les tests par la suite est essentielle. Pour le style de codage, la majorité des différences tournent autour de l'utilisation des espaces blancs - indentation ou sauts de ligne. On devrait pouvoir dire à un outil de fusion décent d'ignorer toutes les différences d'espaces, donc cela vous aidera avec les fusions.

JBRWilkinson
la source
1
L'option 1 ne serait-elle pas activée lorsqu'elle se répercuterait sur la majorité de la base de code, ce qui entraînerait le même big bang pour que chaque fichier change?
Signe le
@Sign: Exactement mon point - Lorsque le crochet de validation change, votre historique pourrait se détériorer en quelque chose de presque inutile. Le formatage qui ne change pas la fonctionnalité ne doit pas être un commit, il doit être transplanté tout au long de l'historique du code.
l0b0
1
Si l'IDE le prend en charge, il y a aussi 3) avoir le formatage automatique IDE à la sauvegarde. Ensuite, utilisez simplement les mêmes paramètres partout - c'est plus facile si vous utilisez la valeur par défaut avec l'IDE.
J'ai fait ces deux approches. La première approche est très intrusive car il y aura une tonne de changements chaque fois qu'un nouveau fichier est validé pour la première fois. La deuxième approche est meilleure pour l'équipe, comme arracher un rapide pansement.
Druska