Des bons commits

Le problème exposé dans ce sujet a été résolu.

Salut !

Utilisant git assez régulièrement, je me demandais quels étaient les critères pour faire des commits corrects. Pour illustrer mes propos, je pensais à l'origine qu'il fallait que le code intégré au commit soit achevé : complet, documenté et testé. Mais l'intégration continue semble entrer en contradiction avec cela. Du coup :

  • Puis-je ajouter à un commit du code non terminé ? Par exemple, si j'ai commencé à coder une fonctionnalité (ou que je n'ai pas encore documenté ou écrit mes TU) et que je souhaite qu'on puisse poursuivre sur une autre machine.
  • Si je me rends compte que la code de mon dernier commit comporte un bug, faut-il jouer avec rebase ou effectuer un autre commit ?
  • Que faire si les dernières modifications non commitées portent sur plusieurs fonctionnalités (commit non atomique) ?

Merci !

+1 -0

Je ne vois pas très bien en quoi l'intégration continue entre en opposition avec les commits "achevé" ?

Par "achevé", tu veux dire avoir implémenté l'ensemble des fonctionnalités (plusieurs classes, plusieurs fonctions), l'ensemble des tests, la documentation, etc. ? C'est généralement difficile de travailler comme cela (et un peu risqué) si tu travailles plusieurs jours sur une même fonctionnalité. Et tu perds l'intérêt de l'intégration continue. L'IC demande juste que chaque commit soit "valide" (si tu dois écrire 100 fonctions et TU pour implémenter une fonctionnalité, tu n'attend pas d'avoir écrit les 100 fonctions, tu commites à chaque fois).

D'ailleurs, tu es libre de créer plusieurs validations, chacune ayant ses propres critères. Par exemple, une validation à chaque commit pour vérifier que cela compile, une chaque nuit pour vérifier les tests (unitaires, intégration, analyses statique et dynamique, etc), une pour la version finale (doc, création des paquets, génération d'un DVD d'install, envoi du programme sur les App Stores, etc).

D'ailleurs, il est intéressant dans ce sens de travailler sur plusieurs branche. Par exemple, une branche pour le dev (instable, validation minimale - cela correspond à ton 1er point), une branche stable (fonctionnalités terminées, avec l'ensemble des tests), une branche release (fonctionnalité testées et approuvé comme étant acceptable pour entrer dans le logiciel qui sera distribué, ajouts des fonctionnalités pour la version suivante et la correction de bugs), des tags pour les différentes versions du logicielles, etc. (bien sur, la complexité de la structure git va dépendre du projet).

  • donc dev branch + cherry pick pour importer uniquement les commits qui t'intéresse
  • pas sur que rebaser soit une bonne chose pour "annuler" une erreur. (d'ailleurs, d'expérience récente, "annuler" est toujours très dangereux…). Corrige le bug et refais un commit
  • fait plusieurs commits (fichier par fichier). Et arrête de dev plusieurs fonctionnalités en même temps qui concernent le même fichier (au pire, si tu dois faire une correction urgente, par exemple un bug, et qui te prend pas longtemps, tu fais un stash, tu corriges le bug, tu le commit et tu récupères ton stash)
+2 -0

Je ne vois pas très bien en quoi l'intégration continue entre en opposition avec les commits "achevé" ?

Peut-être ai-je mal compris le principe de l'intégration continue mais, pour moi, cela consiste (avec TravisCI) à exécuter des TU une fois le code poussé. Mais du coup, je me rends compte des erreurs après avoir commité, non ?

Par "achevé", tu veux dire avoir implémenté l'ensemble des fonctionnalités (plusieurs classes, plusieurs fonctions), l'ensemble des tests, la documentation, etc. ? C'est généralement difficile de travailler comme cela (et un peu risqué) si tu travailles plusieurs jours sur une même fonctionnalité. Et tu perds l'intérêt de l'intégration continue. L'IC demande juste que chaque commit soit "valide" (si tu dois écrire 100 fonctions et TU pour implémenter une fonctionnalité, tu n'attend pas d'avoir écrit les 100 fonctions, tu commites à chaque fois).

Peux-tu préciser le "à chaque fois", puisque c'est justement là, je crois, qu'est ma question ? Si, par exemple, je n'ai implémenté que la moitié d'une fonction, qui n'est alors pas du tout fonctionnelle, est-ce un crime de commiter (pour stocker mon code sur GitHub par exemple et pouvoir le reprendre n'importe où) ?

D'ailleurs, tu es libre de créer plusieurs validations, chacune ayant ses propres critères. Par exemple, une validation à chaque commit pour vérifier que cela compile, une chaque nuit pour vérifier les tests (unitaires, intégration, analyses statique et dynamique, etc), une pour la version finale (doc, création des paquets, génération d'un DVD d'install, envoi du programme sur les App Stores, etc).

La validation se fait donc après le commit ?

Merci !

+0 -0

Si tu implémentes une nouvelle fonctionnalité et que cela te prend 3 semaines pour le faire, tu compiles ou lances ton programme au bout des 3 semaines ?

Je suppose que non.

L'idée est la même pour l'IC.

Je ne vois pas très bien en quoi l'intégration continue entre en opposition avec les commits "achevé" ?

Peut-être ai-je mal compris le principe de l'intégration continue mais, pour moi, cela consiste (avec TravisCI) à exécuter des TU une fois le code poussé. Mais du coup, je me rends compte des erreurs après avoir commité, non ?

Je ne suis pas du tout théoricien de l'IC, donc c'est une vision personnelle de la chose. Ton but est de fournir à tes clients un logiciel qui fonctionne (pas d'erreur, donne le résultat attendu, etc). Les erreurs vont s'accumuler jusqu'à ce qu'elles soient corrigées. Plus les erreurs sont corrigées tard (ie au plus proche du client dans le cycle de développement), plus tu auras d'erreurs qui se sont accumulées. La correction va être longue et pénible.

L'IC, c'est juste trouver et corriger les erreurs le plus rapidement possible.

Lorsque tu utilises un IDE qui souligne les noms de fonctions incorrectes ou une erreur dans les arguments d'une fonction, c'est de l'intégration continue pour moi (erreur de syntaxe).

Lorsque tu compiles ou exécutes ton code en cours de développement, pour voir s'il n'y a pas d'erreur et s'il fait bien ce que tu attends, c'est de l'intégration continue. (Tu peux remarquer que pour le moment, je n'ai pas parlé de commit. Donc l'IC n'est pas lié au commit pour moi, cela commence bien avant).

On peut avoir beaucoup d'autres erreurs : code qui ne donne pas des résultats correctes dans certaines conditions, création des paquets qui échouent, fichiers pas créés/copiés/nommés correctement, etc. Tellement d'erreur possibles qu'il est difficile de toutes les vérifier manuellement. Si on ajoute en plus l'idée de tester le plus souvent possible, on est dans la … (imagine si pour chaque journée de développement, on faisait 3 semaines de tests de validation ?)

Dans un monde parfait, dès que tu appuies sur une touche du clavier, toute la validation serait faite et tu aurais un message d'erreur t'avertissant que la ligne que tu viens d'écrire va produire dans 3 mois une erreur de calcul chez ton client Dupont, Dupond et Cie.

En pratique, ce n'est pas possible. On va écrire un maximum de validation automatiques pour gagner du temps, mais ces validations automatiques prennent du temps (et ne dispensent pas d'une validation manuelle à un moment donné). Par exemple, la création du DVD pour chaque plateforme peut prendre des heures. Pas question de vérifier cela à chaque commit. Par contre, on peut sans problème relancer les TU de la fonctionnalité sur laquelle on travail assez régulièrement (et donc lancer les TU pour cette fonctionnalité plusieurs fois pour un seul commit).

Bref, tout cela pour dire qu'il n'y a pas de règle absolue. Cela va dépendre de tes critères de qualités (on va pas faire la même validation pour un freeware utilisé par quelques personnes et un soft intégré dans le système de pilotage d'une centaine d'avions de ligne), de tes moyens (si tu lances tous les tests sur ton ordi de dev, tu ne codes plus en attendant que cela finisse. Si utilise un serveur dédié, tu continues de travailler), de la branche sur laquelle tu fais tes commit (sur une branche de dev, on va accepter que les TU échouent temporairement ou que la doc ne soit pas générée. Par contre, sur la branche de la release stable, on veux que tout les tests passent).

Donc a adapter selon tes besoins. On peut par exemple avoir :

  • IDE pour vérifier les erreurs de syntaxes
  • compilateur pour vérifier les erreurs de build
  • lancer les tests unitaires en local
  • <-------- on fait le commit ici si on a des serveurs d'IC
  • lancer tous les tests à chaque commit (unitaires, intégration, analyse statique et dynamique)
  • lancer la validation du toute la chaîne de production toutes les nuits (nightly build)
  • A chaque release (donc après code freeze et correction de tous les bugs, sur une branche dédiée), validation manuelle (équipe dédiée, utilisation en interne du logiciel, parfois pré-version chez certains clients hors prod pour des tests sur zone)

Donc, au final, la fréquence des commits et de la validation va dépendre du contexte. Si tu es tout seul et que tu fais tourner ta validation sur ta machine de dev, tu feras des commit réguliers pour pouvoir revenir en arrière (peut importe si un commit empêche de compiler), mais l'IC ne sera lancée qu'une fois par jour. Si tu as plus de moyens (équipe, serveur dédié), tu pourras lancer la validation à chaque commit (et donc demander que les commit sur la branche de dev passent la compilation, ceux sur la branche stable passent tous les tests et interdire les commit sur la branche release)

Par "achevé", tu veux dire avoir implémenté l'ensemble des fonctionnalités (plusieurs classes, plusieurs fonctions), l'ensemble des tests, la documentation, etc. ? C'est généralement difficile de travailler comme cela (et un peu risqué) si tu travailles plusieurs jours sur une même fonctionnalité. Et tu perds l'intérêt de l'intégration continue. L'IC demande juste que chaque commit soit "valide" (si tu dois écrire 100 fonctions et TU pour implémenter une fonctionnalité, tu n'attend pas d'avoir écrit les 100 fonctions, tu commites à chaque fois).

Peux-tu préciser le "à chaque fois", puisque c'est justement là, je crois, qu'est ma question ? Si, par exemple, je n'ai implémenté que la moitié d'une fonction, qui n'est alors pas du tout fonctionnelle, est-ce un crime de commiter (pour stocker mon code sur GitHub par exemple et pouvoir le reprendre n'importe où) ?

Branch de dev

D'ailleurs, tu es libre de créer plusieurs validations, chacune ayant ses propres critères. Par exemple, une validation à chaque commit pour vérifier que cela compile, une chaque nuit pour vérifier les tests (unitaires, intégration, analyses statique et dynamique, etc), une pour la version finale (doc, création des paquets, génération d'un DVD d'install, envoi du programme sur les App Stores, etc).

La validation se fait donc après le commit ?

Cela dépend de quelle validation. Mais toutes les validations ne se font pas après le commit (on essaie généralement que chaque commit de casse pas le build, pour éviter que le reste de l'équipe ne puisse plus développer)

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte