Accueil / Articles / Lorsque l’IA écrit votre application React mais ignore les principes du code propre

Lorsque l’IA écrit votre application React mais ignore les principes du code propre

Apprenez sept habitudes de code propre — DRY, responsabilité unique, clauses de protection, etc. — que le code React généré par l’IA viole souvent et comment les corriger.

2427 mots

Un client m’a récemment confié un projet consistant à créer un site de commande de pizzas.

À première vue, l’étendue des travaux semblait gérable.

Une page d’accueil.

Une section de menu.

Differentes catégories de pizzas.

Des pages produits individuelles.

Un panier d’achat.

Un processus de paiement.

Außerdem un panneau d’administration pour gérer tout ce qui se passe en arrière-plan.

L’hypothèse naturelle était :

">Cela devrait être rapide."

Puis il a été décidé de faire appel à un assistant de codage basé sur l’IA.

C’est là que les choses sont devenues intéressantes.

Laisser l’IA s’occuper de la majeure partie du codage

Le projet a été développé avec React.

Au lieu de taper manuellement chaque ligne, des instructions ont été envoyées à l’IA pour générer chaque élément.

Une instruction comme :

">Créez le composant de la carte des pizzas."

a permis de générer le composant instantanément.

Ensuite :

"Créer le panier d’achat."

Géré.

Puis :

"Créer l’écran de paiement."

Géré également.

Puis :

"Créer un tableau de bord administratif affichant des statistiques, des commandes et des informations sur les clients."

Délivré.

La vitesse était vraiment impressionnante.

Un travail qui prendrait normalement des heures était terminé en quelques minutes.

Les résultats comprenaient :

  • Composants React
  • Formulaires
  • Tableaux de données
  • Widgets pour le tableau de bord
  • Intégration API
  • Indicateurs de chargement
  • Gestion des erreurs
  • Maquettes adaptées à la taille de l’écran

Et l’application fonctionnait réellement.

Tout semblait prometteur.

Il semblait que le flux de travail idéal avait été trouvé :

Idee → Prompt → Code → Lancement

Mais une étape cruciale manquait.

Examiner ce qui avait été développé.

Le client n’a jamais vu le code lui-même

Du point de vue du client, tout semblait parfait.

Le site fonctionnait sans problème.

Le tableau de bord était opérationnel.

Le menu s’affichait correctement.

Les commandes apparaissaient comme prévu.

Visuellement, l’interface était soignée.

Alors où se trouvait le problème ?

Le problème n’était pas visible de l’extérieur.

Dans les coulisses, la base de code se transformait progressivement en source d’ennuis pour la maintenance.

Cela n’était pas évident au début.

Mais à mesure que de nouvelles fonctionnalités étaient ajoutées, un schéma a commencé à apparaître.

"Attendez... n’a-t-on pas déjà développé quelque chose de presque identique ?"

C’est alors qu’une réalisation importante est apparue :

L’IA est véritablement douée pour générer du code fonctionnel.

Mais un code propre n’est pas quelque chose qu’elle produit automatiquement.

Problème n°1 : Une logique répétée partout

Une logique presque identique s’est avérée être dispersée dans toute l’application.

Par exemple, plusieurs fonctions distinctes calculaient les totaux de manière indépendante.

Une d’entre elles ressemblait à ceci :

const total = price * quantity;

Ailleurs, une version presque identique apparaissait :

const orderTotal = price * quantity;

Et dans un autre fichier encore :

const cartAmount = price * quantity;

Toutes les trois effectuaient essentiellement le même calcul.

Rien n’était techniquement défectueux.

Mais dès que les règles de tarification devaient être modifiées, il fallait retrouver et mettre à jour chaque copie.

C’est là que le premier principe du code propre est devenu clair.

1. DRY — Ne vous répétez pas

Lorsque la même logique apparaît à plusieurs reprises, la question à se poser est :

Peut-on la regrouper en une seule source ?

Par exemple :

const calculateItemTotal = (price, quantity) => {
  return price * quantity;
};

Dès lors, chaque partie de l’application peut appeler la même fonction partagée.

L’objectif n’est pas d’imposer l’utilisation réutilisable partout.

C’est simplement éliminer les duplications inutiles.

Problème n°2 : Un seul composant faisait tout

À un moment donné, l’un des fichiers React générés a été ouvert pour être examiné de plus près.

Il continuait à grandir.

Ligne après ligne.

Il ne cessait de s’agrandir.

Ce seul composant était responsable de :

  • Les requêtes API
  • Gestion de l’état du formulaire
  • Logique de validation
  • Visibilité du modal
  • Rendu d’un tableau
  • Filtrage des résultats
  • Pagination
  • Notifications
  • En bref, un seul fichier gérait essentiellement la moitié de l’application tout seul.

    La conclusion évidente était :

    « Entretenir cela va être difficile. »

    Ainsi, ce composant a été décomposé en parties plus petites.

    Au lieu de conserver cette structure :

    Orders.jsx
       ↓
    800+ lines
    

    il a été restructuré pour ressembler à ceci :

    Orders
     ├── OrderFilters
     ├── OrderTable
     ├── OrderRow
     ├── OrderModal
     └── useOrders
    

    Ce changement a directement mené au principe suivant.

    2. Responsabilité unique

    Si vous ne pouvez pas décrire ce qu’un composant fait en une seule phrase, il est fort probable qu’il assume trop de responsabilités.

    Par exemple :

    OrderTable affiche une liste de commandes.

    C’est une description claire et ciblée.

    Comparez-la à ceci :

    OrderTable retrieve les commandes, vérifie les permissions de l’utilisateur, calcule les totaux, déclenche des notifications et affiche tout dans un tableau.

    Ce type de description est un signal d’alerte.

    Problème n°3 : Les instructions If imbriquées ont pris le dessus sur le code

    À un moment donné, une partie de la logique du projet ressemblait à ceci :

    if (user) {
      if (user.isActive) {
        if (user.isVerified) {
          // create order
        }
      }
    }
    

    Elle fonctionnait correctement.

    Mais la lire était fastidieuse.

    Ainsi, elle a été réécrite comme suit :

    if (!user) return;
    if (!user.isActive) return;
    if (!user.isVerified) return;
    
    // create order
    

    Cette version était bien plus facile à comprendre d’un coup d’œil.

    C’est là que l’autre habitude entre en jeu :

    3. Retours anticipés / clauses de protection

    Au lieu de cacher la logique principale derrière plusieurs niveaux d’conditions imbriquées, il est utile de gérer les cas invalides dès le début et de quitter rapidement le programme.

    Invalid?
       ↓
    Return
    
    Invalid?
       ↓
    ReturnEverything okay?
       ↓
    Do the actual work
    

    Le résultat est que la logique principale reste simple, lisible et sans retraits inutiles.

    Problème n°4 : L’IA a suggéré de nouveaux composants pour des éléments déjà existants

    Cette erreur a été un peu gênante.

    La demande faite à l’IA était la suivante :

    "Créez un modal de confirmation pour supprimer une commande."

    L’IA a répondu en générant un composant entièrement nouveau.

    Il a failli être accepté sans question.

    Puis une recherche rapide dans le projet a révélé quelque chose d’important.

    Un composant modal existait déjà.

    Il aurait simplement pu être réutilisé.

    Cet instant a clarifié un point :

    L’IA ne sait pas automatiquement ce qui existe déjà dans une base de code donnée.

    Même lorsqu’il le sait, il peut encore choisir de créer quelque chose de nouveau plutôt que de réutiliser ce qui existe déjà.

    Une approche plus efficace consiste à donner des indications du type suivant :

    « Avant de créer un nouveau composant, vérifiez la base de code existante pour voir s’il y a des éléments qui peuvent être réutilisés. »

    Cette expérience souligne une autre règle :

    4. Réutiliser avant de créer

    Au moment d’ajouter :

    • un nouveau composant
    • une nouvelle fonction utilitaire
    • un nouveau hook personnalisé
    • un nouvel outil API

    demandez-vous :

    « Est-ce que cela existe déjà dans le projet ? »

    Elle est définie par des développeurs qui réutilisent ce qui est déjà disponible plutôt que de le dupliquer en secret.

    Problème n°5 : Les noms de variables étaient parfois terribles

    Le code généré par l’IA arrive rapidement.

    Et il est facile d’accepter des noms de variables tels que :

    const data = ...
    const result = ...
    const x = ...
    const temp = ...
    

    Ces noms se compilent sans problème et ne causent aucune erreur.

    Mais des mois plus tard, à quoi fait réellement référence data ?

    S’agit-il de données liées à la pizza ?

    D’informations sur une commande ?

    De fiches clients ?

    De quelque chose lié à un tableau de bord ?

    Ainsi, la nomination doit devenir plus réfléchie à mesure que le projet progresse.

    Au lieu d’écrire :

    const data = await getOrders();
    

    une version plus claire est préférable :

    const orders = await getOrders();
    

    Et au lieu de :

    const x = users.filter(...);
    

    cela se lit beaucoup mieux :

    const activeUsers = users.filter(...);
    

    Cela donne une autre règle simple :

    5. Utilisez des noms qui expliquent le code

    Une nomination descriptive peut souvent éliminer complètement la nécessité de commentaires.

    Lorsqu’on lit quelque chose comme :

    const activeUsers = users.filter(
      (user) => user.isActive
    );
    

    Cela vous indique déjà exactement ce qui se passe.

    Il n’est pas nécessaire d’ajouter :

    // Filter users who are currently active
    

    Le code parle de lui-même.

    Problème n°6 : Optimiser ce qui n’avait pas besoin d’être optimisé

    À un moment donné dans un projet de ce type, il est facile de commencer à penser :

    « Ce code doit être davantage optimisé. »

    Cela mène souvent à s’attarder sur des choses comme :

    useMemo()
    useCallback()
    

    et quelques autres astuces de performance.

    Mais il vaut la peine de s’arrêter ici.

    L’optimisation n’est pas automatiquement une bonne chose.

    Prenons un calcul trivial comme :

    const total = price * quantity;
    

    Il n’y a aucune raison d’envelopper cela dans un schéma d’optimisation élaboré simplement parce que les outils existent.

    Faire cela ne ferait qu’ rendre le code plus difficile à suivre.

    Cela nous amène à une autre leçon :

    6. Optimisez uniquement lorsqu’il y a un vrai problème

    Ne vous lancez pas dans l’optimisation simplement parce que :

    « Quelqu’un en ligne a dit que cette technique était plus rapide. »

    Identifiez d’abord le véritable goulot d’étranglement.

    Un composant est-il réaffiché trop souvent ?

    Une appel API est-il lent ?

    Un calcul est-il réellement coûteux en ressources ?

    La taille du bundle est-elle trop importante ?

    Une requête de base de données est-elle inefficace ?

    Déterminez le problème réel avant de modifier quoi que ce soit.

    C’est seulement alors qu’il convient d’optimiser.

    Un code propre associé à des optimisations inutiles entraîne une complexité superflue.

    Problème n°7 : Ne demander plus à l’IA de « tout résoudre »

    Ce pourrait être la leçon la plus importante tirée d’un projet de ce type.

    À un moment donné, on a tendance à dire simplement :

    « Veuillez simplement nettoyer tout le projet pour moi. »

    Mais il vaut mieux s’abstenir de le faire pour l’instant.

    Que signifie même « nettoyer » dans ce contexte ?

    L’IA pourrait répondre en :

    • renommer les variables et les fichiers
    • restructurer l’organisation des dossiers
    • introduire de nouvelles abstractions
    • fusionner des fonctions entre elles
    • supprimer du code qu’elle juge inutile
    • restructurer l’architecture

    D’autres pourraient être inutiles.

    Et certaines pourraient introduire discrètement des bugs.

    Une approche plus lente et progressive est préférable.

    Commencez par demander :

    « Examinez ce projet, mais ne changez rien pour l’instant. »

    Puis :

    « Indiquez toute logique redondante. »

    Puis :

    « Dites-moi quels de ces doublons méritent vraiment d’être corrigés. »

    C’est seulement après cela que les suggestions doivent être examinées.

    Puis une modification est appliquée.

    Ensuite, elle est testée.

    Cela devient la règle numéro sept :

    7. Comprendre avant de refactoriser

    N’appelez jamais l’intelligence artificielle à modifier du code qui n’a pas été pleinement compris au préalable.

    Commencez par analyser.

    Vérifiez ensuite que la logique est bien comprise.

    Décidez ensuite de ce qu’il convient de faire.

    Apportez alors la modification.

    Vérifiez-la en effectuant un test.

    Ce que montre un site de pizzas

    Curieusement, un client demande rarement :

    « Votre code est-il propre ? »

    La question est généralement plus simple :

    « Le site fonctionne-t-il ? »

    Et souvent, il fonctionne bien.

    Néanmoins, les développeurs ont une responsabilité qui dépasse cette première version fonctionnelle.

    Le logiciel reste rarement statique une fois mis en production.

    Finalement, un client revient avec :

    ">Pouvons-nous ajouter un suivi de livraison ?"

    Puis :

    ">Admettons-nous des codes de réduction."

    Puis :

    ">Nous avons besoin de prise en charge de plusieurs branches."

    Puis :

    ">Ajoutons des comptes pour le personnel du restaurant."

    Puis :

    ">Nous aimerions avoir des rapports."

    En peu de temps, ce petit site de pizzas est devenu un système complet.

    C’est précisément à ce stade que le code propre commence à justifier les efforts déployés.

    L’IA n’était pas la coupable

    Il est utile d’être juste ici.

    L’IA n’est pas responsable.

    C’est véritablement précieux tout au long d’un tel processus de développement.

    Cela aide à :

    • travailler plus rapidement
    • tester différentes approches
    • gérer des tâches de codage répétitives
    • débusquer les erreurs
    • structurer les composants
    • réfléchir aux solutions

    Le véritable problème n’est jamais le fait que l’IA génère du code.

    C’est plutôt que le code généré est parfois accepté sans une analyse suffisamment approfondie.

    Ce sont deux problèmes très différents.

    Un flux de travail révisé pour coder avec l’IA

    Après un projet de ce type, il est logique d’adopter une nouvelle approche.

    Le processus peut ressembler à peu près à ceci :

    Understand the requirement
              ↓
    Explore existing code
              ↓
    Plan the solution
              ↓
    Ask AI for implementation
              ↓
    Review the generated code
              ↓
    Simplify
              ↓
    Test
              ↓
    Refactor if necessary
    

    L’IA continue de gérer une grande partie de la saisie réelle.

    Mais davantage de la réflexion revient au développeur.

    Cet équilibre semble être la direction vers laquelle évolue le développement logiciel dans son ensemble.

    L’IA écrit du code, mais la base de code reste à vous

    C’est le principal enseignement de toute cette expérience.

    Lorsque l’IA commence à générer votre code, il est tentant de penser :

    "C’est l’IA qui a écrit ça, donc elle doit comprendre ce qu’elle fait."

    Cette supposition est fausse.

    La propriété de la base de code vous appartient toujours.

    C’est vous qui en assurerez la maintenance à l’avenir.

    C’est vous qui devrez détecter les bugs lorsqu’ils apparaissent.

    C’est vous qui devrez expliquer son fonctionnement à quelqu’un d’autre.

    C’est vous qui y reviendrez des mois plus tard et devrez en comprendre à nouveau le fonctionnement.

    À un moment donné, un autre développeur pourrait ouvrir le projet et se demander :

    ">Quelle était la logique derrière cette approche ?"

    Sept habitudes de code propre à retenir

    En résumant toute cette expérience, voici ce qui m’a marqué :

    1. DRY

    Évitez de dupliquer la même logique en plusieurs endroits sans raison valable.

    2. Une seule responsabilité

    Vérifiez que chaque fonction ou composant a un but bien défini.

    3. Retours précoce

    Réduisez le niveau de nesting afin que la logique principale reste facile à suivre.

    4. Réutiliser avant de créer

    Recherchez des solutions existantes dans le codebase avant de développer quelque chose de nouveau.

    5. Bonnes noms

    Choisissez des noms qui indiquent clairement ce qu’une variable ou une fonction représente.

    6. Optimiser avec des preuves

    Attendez avant d’ajouter de la complexité, sauf s’il existe un problème de performance mesurable qui le justifie.

    7. Comprendre avant de refactoriser

    L’IA peut proposer des modifications, mais c’est à vous de décider lesquelles méritent d’être mises en œuvre.

    Pensées finales

    Lorsque j’ai commencé le projet du site de pizzas, je pensais que l’avantage principal de l’aide de l’IA serait :

    une vitesse brute.

    Aujourd’hui, je crois qu’il existe un avantage encore plus important.

    L’IA libère de la capacité mentale pour les aspects du développement qui exigent réellement un jugement.

    Au lieu de consacrer des efforts à du code générique, nous pouvons rediriger cette énergie vers de meilleures questions :

    Est-ce vraiment l’approche appropriée ?

    Peut-on le simplifier ?

    Existe-t-il déjà quelque chose de similaire dans le projet ?

    Ce design résistera-t-il à l’arrivée de la prochaine fonctionnalité ?

    Un autre développeur serait-il capable de suivre ce processus ?

    C’est là la véritable difficulté lorsqu’on travaille avec le développement assisté par l’IA.

    L’IA est capable de générer des centaines de lignes de code presque instantanément.

    C’est encore à nous de confirmer que ces lignes méritent réellement leur place dans la base de code.

    Peut-être est-ce là la définition mise à jour du code propre, maintenant que l’IA fait partie du processus :

    Faire en sorte que le code fonctionne n’est pas la ligne d’arrivée ; ce qui compte, c’est pouvoir le maintenir par la suite.

    Lectures complémentaires

  • Trois patterns TypeScript qui améliorent l’architecture des applications React — Découvrez comment les patterns Repository, Observer et Builder utilisent le système de types de TypeScript pour créer des bases de code React et Next.js plus propres et plus faciles à maintenir.