tl;dr

Le langage naturel, le pseudocode et le code ne sont pas des outils concurrents. Ils sont des langues différentes pour des niveaux de précision différents.

À l’ère de la programmation assistée par l’IA, apprendre à programmer ne consiste pas seulement d'écrire chaque ligne de code à la main. Il s’agit aussi de savoir quand une idée doit devenir plus précise, comment contrôler cette traduction, et comment distinguer les décisions prises par un humain des décisions remplies par un système d'IA.

Une citation de Richard Feynman

Pour comprendre pourquoi la programmation ne disparaît pas simplement avec l'IA, il est utile de commencer par une distinction plus générale : la différence entre clarté et précision.

Richard Feynman a expliqué cette idée lorsqu'il parlait de mathématiques :

Le problème réel dans la parole n'est pas un langage précis. Le problème est un langage clair. Le désir est de faire comprendre l'idée à l'autre personne. Il est seulement nécessaire d'être précis lorsqu'il y a du doute concernant le sens d'une phrase, et alors la précision doit être placée là où se trouve le doute.

Il est vraiment impossible de dire quelque chose avec une précision absolue, à moins que cette chose ne soit si abstraite du monde réel qu'elle ne représente aucun objet réel. La mathématique pure est exactement une abstraction du monde réel, et la mathématique pure a un langage spécial et précis pour traiter de ses sujets spéciaux et techniques.

Mais ce langage précis n'est pas précis dans aucun sens si vous travaillez avec des objets du monde réel, et son emploi est seulement pédant et source de confusion sauf s'il y a certaines subtilités spéciales qui doivent être distinguées avec soin.

La partie intéressante est que Feynman ne critique pas les mathématiques. Il critique l'idée que plus de formalisme signifie plus d'entendement.

Son point est simple :

  • la clarté est plus importante que la précision;
  • la précision doit être introduite uniquement là où il y a une ambiguïté réelle;
  • la mathématique pure peut être parfaitement précise car elle traite d'abstractions définies par les mathématiques elles-mêmes;
  • lorsqu'on parle du monde réel, il y a toujours des approximations, des hypothèses et des définitions imparfaites.

Bien que Feynman ait parlé de mathématiques, cette distinction est utile pour penser à la programmation aussi. Pas parce que la programmation est la même que la mathématique pure, mais parce que la programmation introduit également une précision formelle là où la langue naturelle est trop ambiguë.

L'idée centrale de cet article est la suivante:

Apprendre à programmer reste important car le problème difficile n'est pas seulement la production de code. Le problème difficile est de contrôler la traduction entre une intention humaine ambiguë et un système formel qui exécute des instructions sans bon sens.

La langue des gens et la langue des ordinateurs

La programmation est un moyen de communiquer un procédé. C'est un moyen de dire à une machine ce qu'on veut qu'elle fasse.

Un CPU, ou Unité centrale de traitement, ne comprend pas l'anglais, l'espagnol, le Python ou le C++ de la même manière qu'une personne le fait. Au niveau le plus bas, il exécute des instructions très simples : lire des nombres, les comparer, les additionner, copier des données d'un endroit de la mémoire à un autre, et passer d'une instruction à une autre.

Les langages de programmation sont une couche beaucoup plus accessible aux humains pour décrire des procédures qui seront plus tard interprétées ou compilées en instructions que la machine peut exécuter.

Dans la langue naturelle, une phrase comme:

Trie cette pile de cartes.

laisse beaucoup de place à l’interprétation.

Elle suppose que la personne qui reçoit l'instruction sait ce qu'est une carte, ce que signifie le tri, quel critère d'ordre utiliser, quelles cartes sont supérieures aux autres, si les couleurs comptent, et combien de temps ou d'effort est acceptable.

En programmation, ces décisions doivent être définies quelque part dans le système.

Nous ne nous contentons pas toujours d'écrire chaque détail à la main, car nous utilisons des langages de programmation, des bibliothèques, des frameworks et des abstractions qui encapsulent déjà de nombreuses décisions. Mais quelqu'un, à un certain niveau, avait dû définir ces décisions avec précision.

Le langage naturel et les langages de programmation ne sont pas des versions meilleures ou pires de la même chose. Ils sont des outils différents. Demander si l'intelligence artificielle signifie que nous n'avons plus besoin d’apprendre à programmer est un peu comme demander si, parce que nous savons utiliser une loupe, nous n'avons plus besoin de comprendre à quoi sert un microscope.

Comment le logiciel est créé dans une entreprise de logiciel

Dans une entreprise de logiciel, presque tout commence par un langage naturel.

Un client explique ce qu'il veut:

J’ai besoin d’une application pour gérer les commandes.

Ou:

J’ai besoin d’un site web pour vendre des produits.

Ou:

J’ai besoin d’un système pour gérer les rendez-vous.

Cette première description est rarement précise. Pas parce que le client exprime mal ce qu'il veut, mais parce qu'il tente de compresser une grande quantité de connaissances du domaine dans quelques phrases.

Cette connaissance peut inclure des habitudes, des exceptions, des règles d'affaires, des préférences, des cas limites, des problèmes antérieurs et des décisions implicites.

C'est pourquoi des couches intermédiaires existent.

Un responsable produit, un analyste métier, ou un analyste fonctionnel parle avec le client, pose des questions, détecte les ambiguïtés, et transforme la demande initiale en exigences plus claires.

Puis un responsable technique, un architecte, ou un programmeur traduit ces exigences en décisions techniques de plus en plus précises, jusqu'à ce qu'il y ait du code.

Chaque couche peut découvrir des problèmes ou proposer des modifications. Mais aucune couche ne devrait silencieusement remplacer une décision prise à un niveau supérieur.

Si un programmeur découvre une contradiction, il devrait le signaler. Si un responsable produit reformule une exigence, cette reformulation devrait rester rattachée à la demande initiale du client.

Trois façons de traduire une idée en code

Le diagramme suivant compare trois workflows : le développement logiciel traditionnel, la génération directe de code basée sur un LLM, et un workflow proposé avec une couche intermédiaire explicite.

Processus traditionnel

Client
↓
Analyste / PM
↓
Chef de projet technique
↓
Programmeur
↓
Code

LLM sans méthodologie

Utilisateur
↓
Prompt
↓
LLM
↓
Code

Approche en boîte noire

Utilisateur
↓
Langage naturel
↓
Pseudocode + boîtes
↓
LLM guidé par des compétences
↓
Code traceable

Que se passe-t-il lorsqu’une personne utilise un LLM pour générer du code

Lorsqu'une personne interagit directement avec un LLM pour générer du code, la couche intermédiaire ne disparaît pas complètement. Elle devient implicite.

Le modèle interprète la demande, remplit les détails manquants, priorise les instructions et prend des décisions d’implémentation. Cependant, beaucoup de ces décisions ne sont enregistrées durablement nulle part.

C'est pourquoi de nombreux outils de programmation fondés sur l'IA ont quelque chose comme un "mode Plan". L'idée est de demander au modèle de penser avant d'implémenter.

Le problème est que le plan est souvent temporaire. Il peut rester coincé dans une conversation, déconnecté du code final, ou être ignoré par l'utilisateur.

Lorsque l'utilisateur est un programmeur, il passe souvent beaucoup de temps à écrire des spécifications, des documents de besoins, des notes d'architecture et des fichiers de contexte pour guider le modèle LLM. Cela crée un autre problème : des dizaines de fichiers dispersés, chacun ayant un niveau d'autorité, de priorité et de fraîcheur différent.

Même lorsque les spécifications sont soigneusement rédigées, le problème ne disparait pas.

Le modèle LLM peut rencontrer des contradictions, combler des lacunes ou prendre des décisions qui ne correspondent pas exactement aux besoins. Parfois, cela se produit parce que le langage naturel est ambigu. Parfois, cela se produit à cause de l’ordre dans lequel le modèle lit les fichiers. Parfois, cela se produit parce que les instructions sont en conflit. Et parfois, cela se produit parce que les modèles LLM sont des systèmes probabilistes.

Le problème n’est pas que le modèle LLM prenne des décisions.

Le problème est de ne pas savoir quelles décisions il a prises, pourquoi il les a prises, ou s'il y a des contradictions avec quelque chose qu'un humain avait déjà déterminé.

Pseudocode comme couche intermédiaire

Le pseudocode peut jouer le rôle qui, dans le développement logiciel traditionnel, est souvent réparti entre les clients, les managers, les architectes et les programmeurs.

Il n'est pas un langage naturel pur, car il a une structure.

Mais il n'est pas non plus du code exécutable, car il permet encore de parler en termes d'intention, de modules et de responsabilités.

Cette couche intermédiaire est particulièrement utile avec les modèles LLM, car elle sépare deux moments qui sont souvent trop rapidement fusionnés :

  1. décider ce que le système doit faire;
  2. décider comment l'implémenter.

Par exemple :

IF user selects a subscription plan
  CALL create_checkout_session

IF payment succeeds
  CALL activate_subscription
  CALL send_confirmation_email
ELSE
  CALL show_payment_error

Ce pseudocode ne décide pas encore si nous utiliserons Stripe, Paddle, Mercado Pago, une API personnalisée, ou une bibliothèque spécifique.

Mais il définit une structure :

  • il y a un plan ;
  • il y a une session de paiement ;
  • il y a une étape d'activation de l’abonnement ;
  • il y a un chemin de paiement réussi ;
  • il y a un chemin d'erreur.

Cela est déjà beaucoup plus précis qu'une demande vague comme :

Ajouter des paiements à l'application.

Mais il n'est toujours pas aussi rigide que du code d'implémentation final.

La proposition : l'approche de la boîte noire

La méthode proposée est simple :

Traiter chaque partie du système comme une boîte noire que l’on peut affiner, avec des limites claires, du pseudocode intermédiaire et une provenance explicite.

Chaque projet d'application obtient un dossier blackboxes/ contenant :

  • des boîtes en YAML ;
  • des structures de données partagées ;
  • un fichier de compétence que le modèle doit suivre lorsqu'il est explicitement invoqué ;
  • un journal de provenance ;
  • optionnellement, un visualiseur qui montre l'arbre de boîtes.

L'objectif n'est pas de remplacer le code.

L'objectif est de rendre visible, éditable et auditable la traduction de l'intention humaine en code.

Ce qu'elle essaie de résoudre

1. Décisions humaines vs décisions d'IA

Chaque boîte et chaque champ de données suit une provenance :

  • human_defined
  • ai_defined
  • mixed

Une fois que quelqu'un confirme quelque chose, l'IA ne peut pas le dégrader en silence en une simple hypothèse.

Par exemple, si le modèle décide d'utiliser Stripe, cette décision peut être initialement marquée comme ai_defined.

Si une personne confirme cette décision, elle devient approuvée par l'humain. À partir de ce moment, le modèle ne devrait pas remplacer Stripe par un autre fournisseur à moins qu'il ne soulève explicitement ce changement.

2. Le pseudocode comme couche intermédiaire

Les boîtes utilisent un pseudocode hybride :

CALL create_checkout_session
IF payment succeeds
WHILE there are pending invoices

Cela fournit suffisamment de structure pour décomposer un système, mais pas assez de structure pour que nous nous noyions dans les détails d'implémentation avant d'être prêts.

3. Limites modulaires

Le système est affiné une boîte noire à la fois.

Les ancêtres sont un contexte uniquement en lecture. Seule la sous-arborescence sélectionnée peut changer.

Cela importe car une demande comme :

Réparer le flux de paiement.

ne doit pas permettre au LLM de réécrire la couche d'authentification, la structure de la base de données et le système de notifications à moins que ces changements ne soient explicitement connectés et approuvés.

4. Une vue lisible par un humain

Un visualiseur peut montrer l'arborescence de boîtes noires de manière beaucoup plus simple que des dizaines de fichiers de spécifications dispersés.

L'objectif n'est pas seulement la documentation. L'objectif est de préserver les limites de décision.

Exemple minimal

Voici un exemple simplifié d'une boîte noire pour un flux de paiement :

box: payment_flow
goal: allow the user to pay for a subscription
provenance: human_defined

inputs:
  - selected_plan
  - user_id

pseudocode:
  - IF user selects plan
  - CALL create_checkout_session
  - IF payment succeeds
  - CALL activate_subscription
  - ELSE show_error_message

decisions:
  payment_provider:
    value: Stripe
    provenance: ai_defined
    status: needs_human_confirmation

constraints:
  - Do not modify auth_flow without human approval
  - Do not store sensitive card data

La partie intéressante n'est pas le YAML lui-même.

La partie intéressante est que chaque décision a un endroit. Le système sait ce qui a été spécifié par un humain, ce qui a été inféré par l'IA, et ce qui a encore besoin de confirmation.

La couche intermédiaire n’est pas de la bureaucratie. Elle empêche l’IA de transformer l’ambiguïté en décisions invisibles.

Alors, qu'entend-on par apprendre à programmer maintenant ?

Peut-être qu’apprendre à programmer n'implique plus de mémoriser la syntaxe ou d'écrire chaque fonction depuis zéro.

Peut-être qu'il s'agit d'apprendre à penser en niveaux de précision.

Cela signifie savoir quand la langue naturelle est suffisante, quand le pseudocode est nécessaire, quand du code exécutable est nécessaire, et quand une décision doit être enregistrée car elle affectera tout le système.

Apprendre à programmer enseigne également :

  • comment décomposer les problèmes;
  • comment identifier les cas limites;
  • comment modéliser les données;
  • comment lire avec un regard critique du code généré;
  • comment déboguer;
  • comment évaluer les compromis;
  • comment raisonner sur des contraintes comme la mémoire, la latence, la sécurité, la concurrence, les permissions et le coût.

L'IA peut accélérer significativement la génération de code.

Mais plus l’IA génère de code, plus il devient important de le lire, de le questionner et de le relier aux décisions humaines qu'il est censé mettre en œuvre.

Conclusion

La question « Avons-nous encore besoin d’apprendre à programmer ? » peut être mal formulée.

Si apprendre à programmer signifie mémoriser la syntaxe et écrire manuellement chaque ligne de code, alors nous aurons probablement besoin de moins de cela au fil du temps.

Mais si apprendre à programmer signifie comprendre comment une intention floue devient un système formel qui prend des décisions et exécute des actions, alors la réponse est clairement oui.

L'IA peut écrire du code.

Mais quelqu'un doit encore contrôler la traduction.

Et pour contrôler une traduction, il faut comprendre au moins une partie des deux langues.


La méthode de boîte noire décrite dans cet article est une expérience de preuve de concept. github.com/amiune/theblackboxapproach