GitHub Copilot s’ancre-t-il avec le Craft ?

Copilot, développé par GitHub et OpenAI, est un outil d'assistance au codage basé sur l'IA Générative. Évoluant de Codex à plusieurs modèles (GPT-3.5 et GPT 4), ce système influence de manière significative le secteur du développement logiciel. Mais derrière la magie de cet outil, on se rend vite compte que ce n’est pas si évident de lui donner les bons éléments pour l’utiliser à son plein potentiel. Copilot doit être utilisé en respectant les bonnes pratiques de code qui sont issues du Craftsmanship afin de réduire la marge d’erreur conséquente que cet outil produit.

Cet article explore le fonctionnement de Copilot, ses utilisations pratiques dans le contexte de l'artisanat du logiciel (craft), les limitations inhérentes à son approche ainsi que quelques conseils pour une utilisation optimale.

Fonctionnalités et Applications de Copilot

Logo GitHub Copilot

Cet outil est directement disponible comme extension sur différents IDE tels que Visual Studio Code ou la suite JetBrains. Copilot offre des suggestions de code en temps réel basées sur une analyse contextuelle. Ce contexte est un élément essentiel à garder en tête en tant que développeur car c’est lui qui influence les suggestions que vous allez recevoir. Il est constitué d’un certain nombre d’éléments dont vous avez le contrôle.

  • Nom, chemin et contenu du fichier courant ;
  • Nom, chemin et contenu des fichiers ouverts.

Impact de l’architecture du code sur les suggestions

De ce fait, Copilot est directement influencé par l’architecture du projet. Imaginons que nous manipulions une seule API mais dans deux architectures distinctes. Plaçons nous en tant qu’utilisateur de Copilot afin de faire évoluer cette API dans le cadre des deux architectures suivantes :

  • Une première architecture en couche (controller, service, entity, repository) ;
  • La seconde avec un premier découpage vertical par notion métier puis un découpage hexagonal faisant apparaître les dépendances extérieures que ce soit dans le nom et la localisation des fichiers.

Exemple : Utilisation pour implémenter le pattern Repository

Voici un exemple de code partiellement généré par Copilot dans le cadre d’une architecture en couche qui ne reflète pas assez le contexte dans lequel on évolue.

Exemple d'implémentation d'une classe UserRepository avec Copilot

Dans cet exemple initial, Copilot a envisagé l'emploi d'une interface Database qui n'existe pas dans mon projet. En réalité, mon intention est d'utiliser l'interface PrismaClient.

Exemple d'implémentation d'une classe UserPrismaRepository avec Copilot

Dans cet exemple, l'outil a choisi d'utiliser l'interface PrismaClient pour mettre en œuvre la méthode findById. Cette décision s'appuie sur les informations contextuelles suffisantes que Copilot a pu interpréter, lui permettant de prédire un début de contenu.

Avec le choix de votre architecture, le contexte fourni à Copilot sera un peu plus ciblé dans la seconde architecture car le contenu de vos fichiers sera plus cohérent, les noms et chemins de fichiers seront plus précis. De plus, étant donné que les interdépendances sont réduites dans la seconde architecture, il sera plus facile à Copilot de proposer des suggestions qui ne nécessitent pas l’ensemble des dépendances de l’API. Par exemple, dans le cas où on souhaite créer un filet de sécurité (des tests) à l’aide de Copilot pour une portion de code qu’on souhaite refactorer et qui n’est pas testé.

Copilot Chat pour les cas de refactoring

En plus de l’extension Copilot, depuis quelques mois, GitHub a inclus Copilot Chat dans le même package que l’abonnement à Copilot. Cette fonctionnalité est également disponible sous forme d’extension seulement sur Visual Studio Code et la suite JetBrains en bêta mais elle permet déjà d’aller plus loin dans l’utilisation de l’IA dans le cadre de l’expérience développeur.

Exemple : Amélioration de la lisibilité

Voici un petit exemple d’utilisation de Copilot Chat sur une ancienne portion de code utilisant des magic numbers. Ici, nous essayons d’expliciter les différents cas d’un switch grâce à la logique existante.

0:00
/

Exemple : Création d’un filet de sécurité pour une portion de code à refactorer

Dans cet exemple, l'objectif est de créer un fichier de test pour du code ancien dans le but d'effectuer une refacto.

La fonction en question vise à calculer un intervalle avec une date de début et une date de fin. Copilot Chat parvient à produire une série de tests, mais ceux-ci ne sont pas entièrement exacts. En analysant avec attention, on remarque qu'il compare l'intervalle généré par la fonction à un intervalle établi dans le test lui-même.

Le problème est que Copilot Chat n'a pas identifié que la fonction dépend d'un élément externe via new Date(). De ce fait, il est impossible de déterminer avec exactitude la date dans le cadre du test.

Cependant, il est tout à fait possible d’itérer sur la suggestion en la modifiant ou bien en précisant d’autres éléments.

0:00
/

TDD et sa synergie avec Copilot : entre facilitation et frictions

Exemple : Ajout de validation du format d’un email

Ci-dessous, on constate que Copilot nous aide à écrire notre premier test pour ajouter la validation de l’email d’un profil. D’autre part, il y a un petit écueil : il utilise la méthode toThrowError qui est dépréciée. Nous avons notre premier test pour la phase RED du TDD.

0:00
/

Essayons de faire passer le test ci-dessus. Dans le code généré en dessous, nous arrivons à l’aide de Copilot à créer une fonction de validation d’email faisant passer le test. On peut constater qu’à plusieurs reprises, l’outil m’a proposé des suggestions qui n’étaient pas forcément pertinentes, il a fallu par exemple que je lui précise que je souhaite utiliser une regex pour la validation. Par la suite, il a tout de même réussi à me proposer une première regex correcte et ajouter le throw comme indiqué dans notre test précédemment écrit.

0:00
/

Passons maintenant à la phase de refactoring. Ce qui est intéressant ici, c’est que Copilot a compris que je souhaitais extraire la logique de validation d’email dans un value object Email. Il a donc généré une classe avec la méthode que je souhaite extraire. J’ai dû tout de même repasser sur le code généré afin de l'ajuster.

0:00
/

Bien plus efficace sur la faible valeur ajoutée

Copilot peut être utile pour surmonter des défis techniques courants, permettant aux développeurs de se concentrer sur des aspects plus complexes du développement de logiciels tels que l’implémentation de la logique métier ou la réflexion sur l’architecture d’une fonctionnalité. Ces tâches rébarbatives se présentent sous différents aspects :

  • Amélioration de la productivité dans l’implémentation d'interfaces : Lorsqu’on entame l’implémentation d'une interface, Copilot peut aider à concevoir le contenu d’une méthode en se basant sur la signature de cette dernière ;

  • Utilisation des structures de données : Copilot est plutôt correct dans la manipulation de structures de données telles que les listes, les tableaux, les dictionnaires, et les arbres. Il génère des modèles de code qui respectent les bonnes pratiques de définition de ces structures et intègre des opérations courantes comme les insertions, suppressions, ou itérations ;

  • Découverte de bibliothèques et de frameworks : Lorsqu’on écrit un commentaire ou un fragment de code qui indique une intention d'utiliser une fonctionnalité spécifique d'une bibliothèque, Copilot peut détecter cette intention et fournir un modèle de code adapté qui montre la mise en œuvre standard ou recommandée de cette fonctionnalité. Cela peut inclure des exemples de configuration initiale, d'intégration de middlewares dans les frameworks, ou même des design patterns adaptés à la bibliothèque en question ;

  • Documentation et commentaires : Il peut générer des descriptions pour le code, aidant à la maintenance et à la collaboration. Néanmoins, dans le cadre des bonnes pratiques de code, il serait plus approprié que le code reste le plus possible explicite par lui-même et/ou par ses tests.

Puissant mais pas infaillible : décryptage des limites de Copilot

Malgré l’étendue des applications, il est crucial de reconnaître les limites inhérentes de cet outil, qui se manifestent sous plusieurs aspects :

  • Suggestion de code non optimisé ou erroné : Il est observé que la plupart du temps, cela engendre du code qui n'est pas complètement optimisé ou qui comporte des erreurs. Cette limitation souligne le risque que le code produit puisse manquer d'efficacité ou ne fonctionne pas correctement ;

  • Interprétation inexacte de l’intention du développeur : Copilot interprète mal les objectifs ou les besoins exprimés par le développeur, conduisant ainsi à des propositions de code qui ne reflètent pas fidèlement les intentions et/ou les exigences spécifiques du projet ;

  • Phénomènes d'hallucinations : Copilot est sujet à des 'hallucinations'. Cela se traduit par la génération de réponses ou de solutions inappropriées au contexte.

Seulement ⅓ des suggestions sont acceptées…

D’après les statistiques de GitHub dont on peut retrouver les recherches sur cet article par exemple, environ ⅓ des suggestions sont acceptées. Si vous voulez aller plus loin, voici une étude sur l’impact de GitHub Copilot sur plusieurs milliers de développeurs.

Ils apportent une nuance notamment en fonction de l'expérience des développeurs. Il s’est avéré que le taux d'acceptation est plus élevé pour les développeurs moins expérimentés. Ils traduisent cette donnée en supposant que cela apporte plus de productivité aux débutants mais finalement on ne mesure pas la qualité de ces suggestions dans le contexte où elles ont été acceptées.

Il y a eu également diverses expériences, comme celle réalisée sur une centaine de développeurs afin de réaliser un serveur HTTP en Javascript. Le constat reste assez similaire à l’étude réalisée plus haut. On constate un gain de productivité de plus de 55% entre un groupe utilisant Copilot et un second n'utilisant que les sources traditionnelles mais cela ne prend en compte que le fonctionnement du serveur et la validation des différents cas d’utilisation à l’aide de tests à faire passer pour valider l’exercice. La qualité du code et la complexité accidentelle n’a pas été mesurée. Effectivement une autre lecture de cette statistique pourrait être que les moins expérimentés ont le regard moins critique sur le code généré, et acceptent un code problématique plus aisément, remettant en question la productivité.

Face à ces défis, il est impératif d'adopter une approche de vérification humaine rigoureuse. En définitive, bien que Copilot se positionne comme un outil assistant performant, la supervision humaine et une intervention ciblée restent indispensables pour garantir l'exactitude et la pertinence du code produit.

De mon point de vue, en tant que développeur, j’ai dû sans cesse itérer sur les suggestions proposées par Copilot afin de les corriger ou d’apporter des précisions avec un commentaire plus fourni.

Conseils pour maximiser l'efficacité de Copilot

  • Clarté et simplicité : L'utilisation de noms de variables descriptifs et de fonctions atomiques améliore la précision des suggestions de Copilot.

  • Utilisation de commentaires pertinents : Des commentaires significatifs dans le code aident Copilot à fournir des suggestions plus pertinentes.

  • Une conception logicielle testable et évolutive : Une architecture minimisant les dépendances facilite l'intégration du code généré à un existant. Par exemple, l'adoption d'une architecture hexagonale, complétée par une convention de nommage descriptive pour les fichiers et les dossiers, contribue à cette efficacité.

  • S’adapte facilement à la pratique du TDD : Copilot se marie bien avec la méthodologie TDD (Test-Driven Development) en raison de son approche itérative, qui est au cœur même de TDD. Copilot soutient ce processus en générant des suggestions de code et de tests qui évoluent en tandem avec les itérations de développement.

  • Interaction et personnalisation des suggestions : Vous pouvez affiner et personnaliser les suggestions de Copilot en ajustant le nommage et les commentaires d'un bloc de code spécifique de manière itérative afin de générer de nouvelles suggestions à partir de la précédente. Cette approche permet de raffiner le contexte actuel pour obtenir des résultats plus adaptés à vos besoins.

  • Réinitialisation du contexte : Dans le cas où le contexte actuel serait trop influencé par des éléments précédemment acceptés, il est possible de rafraîchir votre IDE. Cette action réinitialise le contexte pour repartir sur une base neuve, permettant à Copilot de générer des suggestions moins biaisées.

  • Utilisation de Copilot Chat dans les IDEs (en beta actuellement) : Si vous utilisez un IDE tel que Visual Studio Code ou la suite JetBrains, l'option Copilot Chat est également disponible. Elle offre une interface interactive où vous pouvez formuler directement vos requêtes à Copilot, facilitant ainsi une communication plus précise avec l'outil.

Copilot comme outil, pas comme remplacement d’un développeur

Copilot marque un progrès significatif dans la collaboration entre l'intelligence artificielle et les développeurs, visant à améliorer l'efficacité du développement de logiciels. Toutefois, son utilisation exige discernement et expertise humaine pour produire un code de qualité.

Un aspect crucial de son utilisation est l'itération continue sur le contexte : les développeurs doivent régulièrement ajuster et préciser le contexte pour affiner les suggestions de Copilot. Cette itération est essentielle pour obtenir des résultats pertinents. Cette dynamique ne remplace pas le savoir-faire artisanal, mais le valorise, nécessitant une compréhension technique nuancée envers le code. Ainsi, Copilot rappelle que l'art de coder allie la puissance de l'automatisation à la finesse de l'ingéniosité humaine.

Suite à mon utilisation sur plusieurs mois, je trouve que Copilot n’est pas suffisamment précis dans ces suggestions pour l’instant, il faut souvent corriger ses erreurs.

Cependant, mon expérience en tant que développeur est tout de même améliorée car il me permet de réduire le temps passé sur des écritures de codes fastidieux ou de tester des technologies que je connais pas plus facilement. Aussi, il permet de réduire le besoin en configuration de l’IDE (je pense en particulier à l’ensemble des raccourcis et des plugins qu’on doit installer pour gagner en productivité). J’ai beaucoup entendu l’argument que l’IDE offre de nombreuses possibilités similaires à Copilot mais l’avantage ici, c’est qu'on n'a pas besoin de configurer quoique ce soit sur un poste ou pour un langage de programmation en particulier (mise à part installer l’extension et se connecter). Attention toutefois au fait qu’il n’est pas forcément à jour car il se base sur des données datées dans le passé.

A noter, qu’il existe d’autres alternatives telles que CodeWhisperer d’AWS ou encore Duet AI de Google ainsi que des alternatives gratuites comme CodiumAI, Tabnine ou encore TabbyML qui permet même de créer son propre modèle d'assistant de codage.

Sources

Voici quelques liens pour vous aider à la prise en main de Copilot.

Démarrage rapide pour GitHub Copilot

Universe 2023: Copilot transforms GitHub into the AI-powered developer platform

Liens vers des recherches autour de GitHub Copilot.

Research on impact of GitHub Copilot on a large sample of Copilot users
The economic impact of the AI-powered developer lifecycle and lessons from GitHub Copilot

Research: quantifying GitHub Copilot’s impact on developer productivity and happiness

The Impact of AI on Developer Productivity: Evidence from GitHub Copilot

Productivity Assessment of Neural Code Completion

Generative AI at work -  Working Papers | National Bureau of Economic Research