Choisir un modèle de repo est stratégique pour des organisations dont le code source est l’un des principaux actifs.
Google a fait des choix structurants en relation à l’organisation de ses repository dès 1999. Des choix qui se sont avérés être payants au regard de leur performance.
Quels choix ont été pris par Google ? Pour quelles motivations ? Quelle organisation a dû être mise en place pour supporter de tels choix ?
Nous abordons ces questions pour comprendre et pouvoir faire de possibles parallèles pertinents pour nos organisations.
En guise d’introduction aux repos, vous pouvez consulter cet article Les principaux modèles de Monorepo et Multirepo à connaître.
Suivez la QE Unit pour plus de contenu exclusif de Quality Engineering.
Le contexte de repository chez Google
Comme toute entreprise, Google a bien démarré avec quelques lignes de code.
Google utilise le modèle de vérité unique en monorepo pour 95% de sa base de code, laissant sur des repos spécifiques pour Google Chrome et Android.
Historiquement sous CVS, le code source a rapidement été migré vers Perforce.
Les premiers ingénieurs défendaient ardemment un modèle de monorepo centralisé sur une architecture monolithique, un choix qui était encore traditionnel à l’époque.
Les équipes de Google n’avaient pas forcément prévu de créer l’un des repository le plus large et valorisé du monde.
Le patrimoine de Google est d’une dimension considérable :
- 2 millards de ligne de code représentant 86 Tb de stockage
- 40,000 commits par jour par plus de 10.000 ingénieurs (et pas que)
- Plus de 35 millions de commits historisés depuis les années 2000
Voici le détail des statistiques impressionnantes de leur repository en 2015, dont il est difficile d’obtenir des données plus récentes.
Le nombre de fichiers comptabilise ceux de configuration, de documentation, ainsi que ceux supprimées, expliquant ce volume élevé.
À titre de comparaison, le noyau Linux open-source est de l’ordre de 15 millions de lignes de code avec 40,000 fichiers.
Le développement et la croissance de Google s’est largement traduit par une activité soutenue de changements de son repo.
Le scaling du monorepo de Google
À l’instar de New York, le monorepo de Google ne dort jamais.
Centralisé et partagé avec aujourd’hui plus de 25,000 développeurs, Google a itéré pour améliorer sa capacité à faire évoluer leur base de code à l’échelle.
Sur une semaine typique en 2015, environ 15 millions de lignes et 250,000 fichiers faisaient l’objet de changements.
Ce volume de changement est impressionnant par sa valeur absolue et sa croissance constante.
Gardons en tête que chacun de ces changements est réalisé par des ingénieurs en développements sur une architecture monolithique.
Un monorepo sur ce type d’architecture pose de réelles questions organisationnelles par exemple de conflits, que nous aborderons dans la seconde partie.
Néanmoins, cette performance impressionnante n’était pas suffisante pour supporter les cycles d’innovations ciblés.
Google a poussé la barre encore plus haut en dépassant les 35 millions de changements.
Nous observons d’ailleurs un pic sur la période précédant 2015, suivie d’une accélération continue.
L’expression “(et pas que)” prend ici toute son importance.
La croissance quasi exponentielle de l’activité de code n’est pas d’origine humaine, mais issue d’automatisation.
Plus de 24,000 changements sont réalisés quotidiennement par des systèmes automatisés, réalisant en moyenne 500,000 requêtes par seconde.
Pourquoi avoir recours à des commits automatisés?
Je vous rassure nous ne parlons pas (encore) de code fonctionnel généré automatiquement.
Google s’est construit au fur et à mesure des années un écosystème de solutions pour répondre à ces enjeux de croissance de leur monorepo.
Quel système supporte le repository de Google ?
Google a construit un véritable système pour répondre aux différents enjeux de son monorepo.
Les difficultés traditionnelles d’un monorepo sont les suivantes :
- Un temps élevé de téléchargement du repository
- Lenteur et frustration pour rechercher des fichiers
- Moins d’emphase sur une bonne modularisation du code
- Une gestion des dépendances qui peut devenir cyclique
- La difficulté à orchestrer le processus de build
- Des cycles de tests complexifiés par ces autres facteurs
Parcourons donc comment Google répond à ces différentes problématiques, dans leur ordre d’utilisation.
Premièrement, gardons en tête que l’organisation, la culture et la communication chez Google a toujours supporté un modèle monorepo : single codebase, partage, visibilité transverse.
L’alignement se traduit par des commits fréquents sur une codebase, oú la taille du repository est un premier défi.
Le stockage de leur 86 Tb de code source est supporté par Piper, une solution de stockage distribuée à l’échelle supportant les volumes de requêtes plus que soutenus.
L’accès est par défaut ouvert à l’ensemble des développeurs avec une traçabilité intégrée, certains fichiers sont par exception restreints.
Parcourir l’énorme codebase de Google tout en pouvant y contribuer est supporté par CitC (“Client in the Cloud”), un stockage Cloud fournissant une interface légère.
La solution agit comme un proxy oú seuls les fichiers modifiés sont localement téléchargés.
Le cas de recherche dans ce repository massif est supporté par CodeSearch, facilitant la recherche entre les différents workspaces et une édition simplifiée.
Des plugins pour Eclipse et eMacs ont également été développés pour centraliser l’expérience de développement au sein d’un IDE.
Ces trois éléments permettent la collaboration à l’échelle sur un monorepo, oú l’architecture et les processus de livraisons sont coeurs.
Quelle organisation du repository de Google ?
L’architecture et l’organisation du repository n’est pas lié au choix de mono ou multi-repos, mais restent néanmoins structurants.
Consultez si nécessaire cet article pour un rappel des mythes de repo.
Google organise son monolithe en différents répertoires en workspaces ayant chacun une équipe et un ingénieur en responsabilité.
La communication entre les différents composants est réalisée par de la modularisation, des standards d’interfaces et de services. Ils sécurisent le nommage, versioning, protocoles par cas d’usages, gestion des erreurs et j’en passe.
La gestion des dépendances est pro-activement supportée par des pratiques de documentation des APIs et les outils d’analyses statiques que nous verrons plus loin.
En aval, l’outillage du repository fournit une analyse des dépendances, permettant d’évaluer et de traiter les impacts transverses. Le monorepo facilite d’ailleurs une analyse complète du repo en évitant le problème des dépendances cycliques ou de “diamond-dependency”.
Les processus de développement sont ensuite supportés via un modèle de branching.
Quel modèle de branching supporte le repo de Google ?
Google est également connu pour utiliser un modèle de trunk-based development à l’échelle avec succès.
Ce modèle rime avec une culture de commits et de livraisons réguliers, permettant d’intégrer au plus tôt pour réduire les risques d’intégration.
En termes de branches, les changements sont poussés sur la branche principale est soumis à une série de revues que nous partageons ensuite.
Le modèle de monorepo animé en trunk-based supprime les cauchemars de merge depuis des branches de développement.
Une branche de release est ensuite utilisée pour supporter des déploiements souvent gérés en A/B testing, avec des feature-flags, tant pour gérer le risque de déploiement que ne pas bloquer la mainline.
Aligné avec modèle de branches, Google a largement investi dans l’analyse statique, le nettoyage de code et les processus de revues.
Chaque changement est proposé avec un détail des changements effectués avant d’être soumis à plusieurs étapes de validations.
Quels processus de validation et de revue sont utilisés ?
Des premières vérifications automatiques sont réalisées par leur système de presubmit , Tri-corder10.
Des contrôles standards et spécifiques à chaque repo fournissent un premier feedback automatique et rapide au développeur, peu importe sa localisation et son fuseau horaire.
Ces vérifications sont le fruit de plusieurs années d’itérations, incorporant des mécanismes similaires à des branches de développement pour effectuer des tests localisés sur les composants impactés.
Les divers contrôles sont d’ailleurs effectués périodiquement en plus de chaque proposition de changement.
Une fois cette première étape passée, le code sera revu, commenté et éventuellement retravaillé, avant d’être accepté via un “commit approval” par l’un des responsables du workspace.
Ces étapes sont réalisées avec la solution Critique, un outil de Google supportant le processus de code reviews (soumission, commentaires, validation).
L’étape de validation est suivie de l’exécution de série de tests qui déclencheront le commit sur le repository de manière automatique.
Arrivons-nous enfin au build de notre code ?
C’est devient possible en obtenant une approbation de l’outil de build et test à l’échelle de Google, Pipe.
Si le changement est jugé trop risqué, le commit est automatiquement retiré pour ne pas impacter le build global.
Le processus décrit est à imaginer à l’échelle avec des centaines de commits par heures qui sont régulièrement évalués.
Effectuer du refactoring sur une telle base de code peut être comme dans une capitale, où les travaux sont un véritable cauchemar.
Comment Google effectue du refactoring sur un monorepo à l’échelle ?
C’est ici qu’entre en jeu Rosie, une solution de Google permettant de réaliser des refactorings, optimisations et ménage de code massifs.
Rosie est au service des ingénieurs qui peuvent réaliser des patchs structurants sur l’entièreté du repository.
La solution va sécuriser les actions les plus risquées, plus consommatrices de temps et les moins intéressantes par l’automatisation.
Les patchs structurants sont par exemple divisés en plus petits changements qui seront revus par chaque owner, avant d’être construits et testés indépendamment.
Il est intéressant de noter que les propositions de changements sont revues par un comité balançant l’effort de revue nécessaire, les impacts sur le repository et la valeur créée.
Ce processus de revue à l’échelle a été mis en place en 2013, stabilisant le volume de revues gérés par Rosie.
En complément, une équipe est chargée de maintenir une chaîne d’intégration à jour, utilisable et performante du compilateur.
Google a donc structurellement investi dans un système holistique de gestion de son code pour répondre aux enjeux d’un monorepo à l’échelle.
Prenons donc du recul pour faire la balance d’un tel système.
Quels avantages captés par un monorepo à l’échelle ?
Identifions donc les avantages et inconvénients afin d’avoir une perspective transversale du sujet.
Google bénéfice de plusieurs avantages structurels de son repo :
- Une visibilité globale de son actif de code
- Un versioning centralisé et intégré au plus tôt
- Le support au partage et réutilisation de code
- Une gestion des dépendances simplifiée
- Des changements atomiques qui restent maîtrisés
- Une capacité à effectuer des changements structurels
Leur capacité à fournir une expérience de développement satisfaisante est clef. Les temps de chargement sans fin, les analyses d’impacts ardues et peur d’un refactoring transverse sont sous contrôle.
Leur écosystème permet une vélocité sans précédent d’actualisation de leur code, supportant une collaboration massivement étendue.
L’utilisation du static linking résout également les problèmes de binaire, laissant place à des changements simples et rapidement intégrés au main, s’ils passent les différentes étapes de revue.
Comment gérer les inconvénients d’un modèle de monorepo ?
Leur succès est également lié à avoir adressé les principaux désavantages d’un modèle en monorepo.
Google classe ces pain-points en 3 catégories :
- La complexité et taille de la codebase, qui en rend difficile sa compréhension, recherche, évolutivité et maintenabilité
- L’investissement en outillage sur toute la chaîne, du repository au système de build, test et de déploiement
- La gestion de la qualité du repository, du code, documentation à la gestion des refactoring
Les divers éléments partagés sont venus améliorer les problématiques normalement rencontrées.
Deux difficultés principales restent à accepter sur ce modèle.
La première est que les équipes ont tendance à consulter les détails d’implémentation des diverses APIs, qui sont facilement visibles dans le repository.
C’est une particularité à accepter, à travailler en culture et pratiques sans pour autant restreindre les accès, la visibilité étant un point fort d’un monorepo.
La seconde difficulté est le développement et intégration de composants open-source. Google y arrive en gardant un espace spécifique de son repo pour ses usages. Il requiert une attention particulière dans le cadre du monorepo.
Google va t-il basculer sur un modèle de multi-repo ?
Les ingénieurs de Google se sont régulièrement posé la questions des multi-repos et de l’utilisation de Git.
Les multi-repos sont utilisés pour ses autres projets, tels que Android, Chrome et les principales initiatives open-source.
C’est ce qui leur permet de capter également la communauté par l’utilisation largement répandue de Git.
Pourquoi ne pas remplacer Piper par Git pour leur monorepo?
Git a été construit pour supporter un modèle de développement distribué, principalement en multi-repo.
Vouloir utiliser Git reviendrait donc à basculer le monorepo en en multitude de repos, objectif contraire de l’organisation de code de Google.
Au fur et à mesure des années, malgré s’être posé plusieurs fois la question, le monorepo de Google est resté l’option retenue.
Depuis 2015, Google travaille néanmoins avec la communauté de Mercurial pour faciliter les workflows des équipes.
Que retenir et appliquer du modèle de repo de Google ?
La stratégie de monorepo et d’une architecture monolithique a clairement supporté la performance de Google.
Un point structurant est l’alignement de cette stratégie avec l’organisation, la culture et les processus de l’organisation.
L’identification, la gestion et l’amélioration des trade-offs est également clef pour limiter les contraintes et limites du modèle retenu.
Cette perspective globale est ce qui permet de faire de réels choix et d’aligner les investissements stratégiques.
Gardons en tête qu’adopter un monorepo ou une architecture monolithique ne fera pas de nous le prochain Google.
En fonction du contexte, un monorepo peut d’ailleurs évoluer vers un multi-repo, tant qu’ils sont alignés et pertinents dans l’entreprise.
C’est bien l’ensemble du système mis en place qui permet une orchestration réussie de son organisation, au service du business.
Références
References 1. Bloch, D. Still All on One Server: Perforce at Scale. Google White Paper, 2011; http://info.perforce.com/rs/perforce/images/GoogleWhitePaper-StillAllonOneServer-PerforceatScale.pdf
Build in the Cloud: How the Build System works. Google Engineering Tools blog post, 2011; http://google-engtools.blogspot.com/2011/08/build-in-cloud-how-build-system-works.html
Wright, H.K., Jasper, D., Klimek, M., Carruth, C., and Wan, Z. Large-scale automated refactoring using ClangMR. In Proceedings of the IEEE International Conference on Software Maintenance (Eindhoven, The Netherlands, Sept. 22–28). IEEE Press, 2013, 548–551
Why Google Stores Billions of Lines of Code in a Single Repository https://research.google/pubs/pub45424/