Lorsqu'un système fonctionne et est adopté par beaucoup d'utilisateurs, il arrive toujours un moment où des voix s'élèvent pour dire que finalement, tout ça, c'est nul ! Nul est vaste et englobe le « n'est pas adapté à mon cas », le « j'étais fan mais en fait j'étais aveugle » ou encore le « c'est bien trop populaire pour être bien ».

En 2008, sur ce blog, j'avais écrit une suite d'articles qui mentionnaient des techniques tout en les précédents de « Ce n'est pas le Graal » qui mentionnait ces attitudes de rejets massifs d'outils et techniques. Ces derniers temps, c'est au tour de Git, le gestionnaire de versions, qui s'attire des critiques de ce style. Une attaque parfois violente à base de « puisque ça ne répond pas parfaitement à 100% de mes besoins, c'est que cela ne doit être intéressant pour personne. »

Passons.

L'une des critiques que j'ai pu relever est : « git incite à faire trop de branches, on s'y perd ! » Après l'étonnement amusé, cette phrase m'est revenu en tête lorsque je me suis retrouvé face à mes quatre branches créées dans les deux heures précédentes. Est-ce que Git m'avait incité à créer ces branches ? À planter une forêt complète ?

Souplesse

Git est souple, très souple en ce qu'il permet est de travailler de nombreuses façon différentes. C'est une des problématiques lorsque l'on apprend ou enseigne Git à quelqu'un. L'une des première question est de savoir comment s'organiser. Git n'impose rien, il permet. Ce n'est pas pratique à enseigner, mais c'est drôlement bien adapté aux personnes qui aiment les outils souples.

En regardant le contenu des quatre branches, ce que j'ai vu est que j'avais trois fonctionnalités et un nettoyage de code. Une des fonctionnalités était sur une voie de garage, une idée comme ça mais que allait dans une direction qui ne me plaisait pas trop. Une autre branche concernait la configuration du projet, que j'espérais bien finir rapidement. La troisième branche concernait une automatisation de tests, qui allait m'aider à la configuration du projet, mais qui en était indépendante.

La branche nettoyage était du à des choses que je voyais tout en configurant le projet.

Dans ma manière de travailler, je ne voulais pas que ces tâches collisionnent. Elles ne le devaient pas. Les faire se collisionner, c'est se retrouver avec le risque d'avoir des morceaux de fonctionnalités entremêlées qui s'influencent les unes les autres. Un bon moyen de se retrouver avec un état de la base de type à ne plus rien y comprendre et finalement tout jeter.

Git m'a facilité la tâche. Mais j'aurais fait de même avec Perforce, en utilisant les shelves. C'est un peu moins pratique et flexible.

Ce n'est pas le système qui m'a incité à travailler comme cela. J'ai plutôt choisi ce système car il convenait bien à cette manière de travailler. Ou plus exactement, l'intersection entre ma manière de travailler et les fonctionnalités offertes est plutôt grande, si ce n'est maximisée.

Oui mais trop, c'est trop !

Dans un second temps de la critique sur le nombre de branches vient celle de la difficulté à suivre l'état complet du système, et de la divergence de branche qui peut amener rapidement à des difficultés de « merge ».

Si l'on considère que le nombre de branches est induit par Git, alors Git induit de la complexité de projet. Comme ce n'est pas le cas, restons sur cette complexité du projet en elle-même, quel que soit le système.

Les alternatives à la multiplication des branches existent : programmer sur un dépôt commun, sur une branche commune ou encore travailler avec des shelves/stashes personnels. Dans tous les cas vient le moment du conflit entre un changement local et un changement déjà poussé sur la base.

La différence est probablement qu'un système moins souple va inciter à ne pas trop multiplier les points de divergence. Comme il est moins aisé (voire complexe) de sauter d'une branche à l'autre, le programmeur se concentre sur un nombre limité d'environnements, quitte à mélanger les fonctionnalités. Et tant pis pour les dépendances entre les changements.

Conflits en série

Ce qui peut faire peur, avec cette série de branches, c'est que les conflits potentiels lors des « merges » peuvent se retrouver multipliés. C'est exact. Plus la branche de développement a une longue durée de vie, plus elle a un risque de diverger.

Je distingue alors plusieurs cas :

  • les branches à courtes durées de vie : elles sont là pour développer une fonctionnalité simple. Elles permettent de soumettre les changements au système souvent, atomiquement, et permettent une sécurité du versioning, sans impacter le travail de quelqu'un d'autre. Au final, quelques heures après sa création, la branche est mise au propre (avec Git, son historique peut être réécrit), envoyé en review, testée, mergée et détruite.
  • les branches à longues durées de vie, actives : ces branches peuvent servir à maintenir un état (des branches de release, de patch,...) ou bien à développer seul ou à plusieurs une fonctionnalité complexe. Cette branche sera peut-être elle même branchée en petites branches pour faire des essais et revenir en arrière. Ce qui est primordiale ici, c'est qu'il s'agit d'une branche active. Elle est maintenue, dans le cadre d'un flow, en intégrant des changements venant d'une branche plus stable. Ainsi, les changements éventuels d'interface sont pris en compte assez tôt.
  • les branches mortes : ce sont des branches qui ne sont pas maintenues. Une idée, un début de dev, un test,... La branche est peut-être morte après une heure de travail, ou après plusieurs jours, mais elle n'est plus maintenu et probablement plus maintenable.

Les deux derniers cas sont ceux qui font le plus peur : dans les branches actives, on paye un coût de maintenance, dans les branches mortes, du travail a été mis de côté et ne peut plus être utilisé.

Est-ce un problème ? Je ne le pense pas.

L'art de refaire, et de faire petit

J'ai déjà évoqué je crois ici la méthode Mikado, présentée dans le livre du même nom. Elle propose une méthode itérative où l'on défait souvent ce que l'on vient de faire, dans le but de gagner en qualité et efficacité du programme.

Lorsqu'une branche meurt car elle a trop divergé, il y a deux cas : soit son contenu n'est pas intéressant (plus d'actualité, test non concluant,...) soit il l'est. S'il l'est, la branche sert alors de prototype. Elle a servi à former les développeurs qui y ont participé. Elle a servi à une première version de l'idée.

Fort de cette expérience et des idées toujours présentes dans la branche, il est maintenant possible de créer une nouvelle branche, en partant d'une branche stable et active et de s'appliquer à refaire au propre.

Les branches mortes sont des brouillons. Et les brouillons, c'est de l'investissement sur la qualité.

Afin de garder les branches actives, il est de même conseillé de travailler par petit morceaux livrables. C'est écrit dans toutes les méthodologies, et pourtant...

Au final, si les développeurs sont adeptes des développements itératifs et acceptent le concept de prototype/brouillon, alors le projet va avoir plusieurs branches. Git est là un facilitateur.

Mais pas un incitateur. Bon nombre de projets ont une branche master et tout le monde push/pull dedans.

Mais alors c'est génial ?

Git n'est pas sans défaut. Et il n'est pas adapté à toutes les utilisations, ni à tous les utilisateurs. C'est un outil qui n'est pas très facile d'accès, à la syntaxe qui semble être volontairement chaotique, qui mélange des outils de haut et de bas niveau, dont la souplesse est à double tranchant et peut causer des dégâts,... La liste est longue.

Elle est longue pour n'importe quel système de gestion de versions. Tout autant que la liste des avantages à utiliser un système.