NSI · Première

Histoire de l’informatique : comprendre les inventions et mener un projet

Une machine qui calcule, une machine programmable et une machine à programme enregistré ne désignent pas la même propriété. Ce cours relie des repères historiques à des mécanismes que tu peux suivre : cartes de commande, logique booléenne, mémoire adressable, traduction de langages et échange de messages.

Explications et exemples en accès libre. Ateliers, quiz et cartes avec l’abonnement.

Étude en accès libre
Environ 50 min à 1 h 30
Progression
6 étapes guidées
Vérification
10 questions
Rappel actif
12 cartes
Prévoir mon tempsExplications et exemples en accès libre

Une première étude des explications, schémas, exemples résolus et erreurs expliquées. Les activités, productions, quiz et cartes réservés à l’abonnement ne sont pas comptés ici.

Comprendre2469 mots d’explication et 4 schémas
15 à 24 min
Étudier les exemples et les erreurs18 cas, exemples et activités guidés
36 à 66 min

Étude du cours en accès libre, environ50 min à 1 h 30

Voir le calcul et le temps par étape

Le calcul suit automatiquement les explications et les tâches présentes dans le cours. Ses coefficients sont des repères de planification, pas des temps mesurés auprès d’élèves.

  • Lecture active : 2469 mots, à raison de 160 à 220 mots par minute.
  • Schémas : 4, avec 1 à 2 min pour lire chacun.
  • Exemple guidé : 6 × 2 à 4 min.
  • Suivre le code résolu et ses tests : 6 × 3 à 5 min.
  • Comprendre une erreur expliquée : 6 × 1 à 2 min.
  1. Calculer et programmer : ce que changent les cartes8 à 16 min
  2. Logique et modèles de calcul : trois questions différentes7 à 14 min
  3. Programme enregistré et composants : deux transformations8 à 16 min
  4. Langages et systèmes : changer d’écriture sans perdre le sens7 à 14 min
  5. Internet et Web : des réseaux, puis des ressources reliées9 à 16 min
  6. Enquêter et réaliser : relier une décision à sa preuve9 à 16 min

Les sous-totaux sont arrondis à la minute, puis additionnés. La fourchette totale est élargie aux cinq minutes voisines. Les étapes ci-dessus comprennent leurs explications et exemples ; elles ne s’ajoutent pas une seconde fois au total.

Adapte ce repère à tes acquis et au soin apporté aux exercices. Les pauses, les reprises, la consultation des sources externes et les révisions suivantes s’ajoutent selon tes besoins.

Avec les ateliers, le projet, le quiz et les cartes : environ 4 h 30 à 7 h 55, à répartir sur plusieurs séances.

Objectifs du cours

Ce que tu vas savoir faire

  • Situer Pascal, Jacquard, Babbage, Lovelace, Boole et Turing en reliant chaque repère à une contribution précise.
  • Distinguer automatisation, programmabilité, programme enregistré et miniaturisation des composants.
  • Suivre une table logique, une instruction en mémoire et la traduction de deux syntaxes.
  • Situer ARPANET, le passage à TCP/IP et le projet Web, puis distinguer leurs fonctions.
  • Vérifier une date et une attribution dans un document en séparant proposition, prototype et diffusion.
  • Construire en groupe un prototype documenté, testé et présentable, avec des rôles tournants et des versions identifiables.
01

Étape du cours · 8 à 16 min

Calculer et programmer : ce que changent les cartes

Pour comprendre une invention, pars du geste qu’elle rend possible. Une machine arithmétique de Pascal, au XVIIe siècle, mécanise des calculs, notamment le passage des retenues entre roues. Cela ne lui donne pas un programme général modifiable. L’automatisation concerne l’exécution d’une tâche ; la programmabilité permet de changer la suite d’actions commandées à un dispositif.

Au début du XIXe siècle, le mécanisme Jacquard utilise des cartes perforées pour commander le motif du tissage. Changer les cartes change la commande, sans reconstruire tout le métier. La machine analytique conçue par Charles Babbage à partir de 1834 reprend ce principe de commande pour le calcul, en distinguant un magasin de nombres et un organe de calcul. Elle reste un projet dont seules des parties sont réalisées à son époque.

En 1843, Ada Lovelace publie une traduction commentée du texte de Menabrea sur cette machine. Ses notes exposent ses possibilités de programmation et envisagent d’autres objets que de simples nombres. Écris donc « notes publiées en 1843 », et non « ordinateur construit en 1843 ». Un plan, un texte, une pièce expérimentale et une machine complète sont des traces différentes. Le dossier du Science Museum aide à les reconnaître.

Notre jeu de cartes est fictif : COPIER C A signifie remplacer C par la valeur de A ; AJOUTER C B signifie ajouter B à C ; MULTIPLIER C B signifie multiplier C par B. Les registres sont un dictionnaire de noms non vides et d’entiers Python, sans booléens. Toutes les cartes doivent nommer des registres existants. La liste de cartes est finie, sans branchement : une carte est exécutée exactement une fois.

La fonction copie l’état initial et rend l’état final avec une trace avant/après chaque carte. Elle ne modifie ni le dictionnaire fourni ni les cartes. Changer les valeurs initiales conserve le programme ; remplacer une carte change la commande. Cette distinction est utile pour expliquer la programmabilité, sans assimiler notre Python au fonctionnement mécanique d’un métier ou de la machine analytique.

Voir pour comprendre

Quatre repères, quatre traces différentes

Une date se lit avec son objet. Ce tableau ne fait pas de la succession une preuve de causalité.

Quatre repères, quatre traces différentes
RepèreTrace ou objetCe qui change
XVIIe siècle · PascalMachine arithmétiqueMécaniser un calcul
Début XIXe · JacquardCartes et mécanisme du métierModifier la commande du motif
1834 · BabbageProjet de machine analytiqueOrganiser mémoire, opérations et cartes
1843 · LovelaceNotes publiées sur le projetExpliquer la portée de sa programmation

Lis le schéma. Quelle ligne date un texte, et non une machine construite ? À quel objet comparerais-tu notre suite de cartes fictives ?

Lovelace publie ses notes en 1843. Le plan de Babbage et le texte qui l’explique ne sont pas la construction d’un ordinateur complet.

Exemples résolus et erreurs expliquées

Trois cartes pour calculer (A + B) × B

  1. La carte COPIER C A lit la valeur 2 de A et remplace C : l’état devient A=2, B=3, C=2. Copier une valeur ne renomme pas les registres.
  2. La carte AJOUTER C B lit C=2 et B=3, puis écrit 5 dans C. La source B reste égale à 3 ; c’est la destination C qui change.
  3. La carte MULTIPLIER C B remplace C par 5 × 3, soit 15. La trace conserve les valeurs successives 2, 5 et 15.
  4. Le résultat est 15 et le dictionnaire initial garde C=0. Notre copie de travail explique cette non-mutation ; ce choix Python n’est pas une propriété attribuée à une machine historique.

Conclusion. Une commande, une destination et un état avant/après suffisent à expliquer chaque pas.

Laboratoire de code

Languepython

Butsimuler un paquet de cartes d'instructions et distinguer programme, registres et trace

Code solution
def executer_cartes(cartes, registres):
    if not isinstance(cartes, (list, tuple)) or not isinstance(registres, dict):
        raise ValueError('cartes et registres invalides')
    if any(not isinstance(nom, str) or not nom.strip() or type(v) is not int
           for nom, v in registres.items()):
        raise ValueError('noms et entiers attendus')
    etat = dict(registres)
    trace = []
    for numero, carte in enumerate(cartes):
        if not isinstance(carte, (list, tuple)) or len(carte) != 3:
            raise ValueError('carte à trois éléments attendue')
        operation, destination, source = carte
        if operation not in ('COPIER', 'AJOUTER', 'MULTIPLIER'):
            raise ValueError('instruction inconnue')
        if not isinstance(destination, str) or not isinstance(source, str):
            raise ValueError('noms de registres attendus')
        if destination not in etat or source not in etat:
            raise ValueError('registre inconnu')
        avant = dict(etat)
        if operation == 'COPIER':
            etat[destination] = etat[source]
        elif operation == 'AJOUTER':
            etat[destination] += etat[source]
        else:
            etat[destination] *= etat[source]
        trace.append((numero, tuple(carte), avant, dict(etat)))
    return etat, trace

Tests

cartes = [('COPIER','C','A'),('AJOUTER','C','B'),('MULTIPLIER','C','B')]
initial = {'A':2, 'B':3, 'C':0}
etat, trace = executer_cartes(cartes, initial)
assert etat == {'A':2, 'B':3, 'C':15}
assert [ligne[3]['C'] for ligne in trace] == [2,5,15]
assert initial == {'A':2, 'B':3, 'C':0}
assert cartes[0] == ('COPIER','C','A')
assert executer_cartes([], {'A':1}) == ({'A':1}, [])
assert executer_cartes([('AJOUTER','A','A')], {'A':3})[0]['A'] == 6
for mauvaises in ([('DIVISER','A','B')], [('COPIER','X','A')], [('COPIER','A')]):
    try:
        executer_cartes(mauvaises, {'A':1, 'B':2})
    except ValueError:
        pass
    else:
        raise AssertionError('carte invalide acceptée')

Trace

  • carte 0 copie A=2 vers C : l'état devient A=2, B=3, C=2
  • carte 1 ajoute B à C : C devient 5 sans modifier le paquet de cartes
  • carte 2 multiplie C par B : C devient 15 ; programme, état et résultat restent distincts

Clinique de bogue

Indice observéla carte AJOUTER A B modifie B au lieu d'ajouter la valeur de B dans le registre A

CauseLa destination, placée au deuxième rang de la carte, est inversée avec la source. La petite version ci-dessous traite seulement AJOUTER et rend un dictionnaire, sans la trace du laboratoire : son contrat est volontairement plus court. Elle copie l’état fourni et refuse une autre instruction.

02

Étape du cours · 7 à 14 min

Logique et modèles de calcul : trois questions différentes

George Boole publie un traitement algébrique de la logique en 1847, puis Les Lois de la pensée en 1854. On peut calculer sur des propositions suivant des règles, au lieu de raisonner seulement sur leur formulation en langue courante. Dans notre usage booléen, and exige deux valeurs vraies, or au moins une, et not inverse la valeur. Le ou exclusif est vrai lorsque les deux entrées diffèrent.

Les travaux de Claude Shannon sur les relais et les circuits de commutation relient l’algèbre booléenne à des dispositifs électriques. Deux contacts en série ne laissent passer le courant que si les deux sont fermés ; en parallèle, un chemin fermé peut suffire. Une table décrit une fonction logique ; un montage physique doit en plus respecter des contraintes de tension, de temps et de fabrication.

En 1936, Alan Turing définit un modèle de machine pour étudier le calcul effectif. Une description élémentaire comporte un ruban, une tête de lecture-écriture, des états et des règles de transition. Le modèle universel peut interpréter la description d’autres machines. Ce n’est ni le plan d’un ordinateur à transistors ni l’affirmation que toute question mathématique peut être résolue par un algorithme.

Un additionneur complet répond à une question plus limitée : pour deux bits et une retenue entrante, quels sont le bit de somme et la retenue sortante ? Si n est le nombre d’entrées vraies, le bit de somme indique si n est impair et la retenue si n vaut au moins 2. Les huit triplets donnent toutes les possibilités de ce domaine fini.

Le code demande des valeurs True ou False, pas la chaîne « False », qui est non vide et donc vraie lors d’une conversion par bool. Vérifier les huit lignes établit la table de cette fonction. Cela ne valide pas un circuit matériel et ne démontre pas les résultats de Turing sur le calcul. Repère toujours l’objet exact que l’expérience permet de vérifier.

Exemples résolus et erreurs expliquées

Trois bits d’entrée, deux bits de sortie

  1. Compte les valeurs vraies : deux entrées valent 1 et la retenue entrante vaut 0. La valeur arithmétique à représenter est donc 2.
  2. Le nombre 2 s’écrit 10 en binaire. Le bit de poids faible, appelé somme, vaut 0 ; la retenue sortante, de poids 2, vaut 1.
  3. La fonction rend (False, True), dans l’ordre somme puis retenue. Vérifie l’égalité a + b + retenue = somme + 2 × retenue_sortante.
  4. Pour trois entrées vraies, la valeur vaut 3 et s’écrit 11. Pour aucune entrée vraie, elle vaut 0 et s’écrit 00. Les huit cas de la table contrôlent aussi les situations intermédiaires.

Conclusion. L’ordre des sorties compte : (somme, retenue) n’est pas l’ordre d’écriture usuel des deux chiffres binaires.

Laboratoire de code

Languepython

Butproduire et vérifier exhaustivement la table d'un additionneur complet à trois entrées

Code solution
def additionneur_complet(a, b, retenue):
    if not all(type(x) is bool for x in (a, b, retenue)):
        raise ValueError('entrées booléennes attendues')
    entrees = (bool(a), bool(b), bool(retenue))
    nombre_vrais = sum(entrees)
    somme = nombre_vrais % 2 == 1
    sortie_retenue = nombre_vrais >= 2
    return somme, sortie_retenue

def table_additionneur():
    lignes = []
    for a in (False, True):
        for b in (False, True):
            for retenue in (False, True):
                lignes.append((a, b, retenue, *additionneur_complet(a, b, retenue)))
    return lignes

Tests

assert additionneur_complet(False, False, False) == (False, False)
assert additionneur_complet(True, False, False) == (True, False)
assert additionneur_complet(True, True, False) == (False, True)
assert additionneur_complet(True, True, True) == (True, True)
assert len(table_additionneur()) == 8
assert len(set(table_additionneur())) == 8
assert all(int(a)+int(b)+int(r) == int(s)+2*int(c) for a,b,r,s,c in table_additionneur())
try:
    additionneur_complet('False', False, False)
except ValueError:
    pass
else:
    raise AssertionError('entrée invalide acceptée')

Trace

  • entrées 1,0,1 : deux valeurs vraies donnent un total binaire 10
  • le bit de somme est faux car le nombre de vrais est pair
  • la retenue est vraie car au moins deux entrées sont vraies ; les huit lignes couvrent tous les cas

Clinique de bogue

Indice observépour a=True et b=True, le code renvoie somme=True et retenue=True, soit deux bits qui représentent 3 au lieu de 2

CauseLe ou inclusif renvoie vrai pour deux entrées vraies ; le bit de somme doit au contraire revenir à zéro. Le demi-additionneur n’a pas de retenue entrante. Il conserve le même domaine strict True/False que l’additionneur complet.

03

Étape du cours · 8 à 16 min

Programme enregistré et composants : deux transformations

Le programme enregistré place des instructions codées dans une mémoire adressable. La machine les lit, comme elle peut lire une donnée, au lieu de dépendre seulement d’une commande extérieure ou d’un recâblage. Le compteur ordinal indique l’adresse de la prochaine instruction ; l’accumulateur garde une valeur utilisée dans le calcul. Adresse et contenu ne sont pas interchangeables : l’adresse 4 peut contenir la valeur 7.

Le 21 juin 1948, le Manchester Baby, développé par l’équipe de Frederic Williams et Tom Kilburn, exécute un programme enregistré électroniquement en mémoire. En 1949, l’EDSAC de l’équipe de Maurice Wilkes à Cambridge fournit un service régulier de calcul. Un prototype qui démontre un principe et une machine utilisée pour un service sont deux réalisations distinctes. Le programme enregistré est aussi associé au modèle dit de von Neumann ; ce nom ne résume pas à lui seul tous les travaux collectifs qui le rendent possible.

Le composant répond à une autre question : avec quoi construit-on la machine ? Aux Bell Labs, John Bardeen et Walter Brattain démontrent le transistor à contacts ponctuels en décembre 1947 ; l’annonce publique a lieu en juin 1948. Les circuits intégrés rassemblent ensuite plusieurs composants sur une même puce. En 1971, Intel commercialise le microprocesseur 4004 : un processeur intégré sur une puce, pas un ordinateur complet. Cette miniaturisation n’est pas la définition du programme enregistré.

Notre mémoire est une liste commune à des instructions descriptives, comme ('ADD',5), et à des données entières. Les tuples lisibles remplacent ici le codage binaire d’une vraie machine. LOAD lit une donnée dans l’accumulateur, ADD l’y ajoute, STORE écrit l’accumulateur en mémoire, JUMP change le compteur ordinal et HALT arrête. HALT utilise l’argument conventionnel 0 ; les autres arguments sont des adresses à partir de zéro.

On copie l’entrée et on conserve un instantané avant chaque instruction, arrêt compris. La lecture d’une donnée comme instruction, une adresse négative ou une instruction mal formée est refusée. STORE peut remplacer une cellule d’instruction par un entier : si le compteur tente ensuite de l’exécuter, le modèle signale l’erreur. Une limite entière de 1 à 1 000 pas borne l’essai d’un programme qui boucle ; atteindre cette limite ne prouve pas que le programme bouclerait indéfiniment.

Voir pour comprendre

ADD 5 : lire l’adresse 5, puis ajouter sa valeur

Instantané avant l’instruction à l’adresse 1. Les mots lisibles représentent des instructions du modèle, pas leur encodage binaire.

Lire une instruction et sa donnée dans la même mémoire Avant ADD : compteur 1, accumulateur 7. L’instruction lit l’adresse 5, qui contient 8. Après : accumulateur 15, compteur 2. La mémoire est inchangée pendant ce pas. Mémoire communeAdresseContenu 0 LOAD 4 1 ADD 5 2 STORE 6 3 HALT 0 4 7 5 8 6 0 Processeur PC = 1 ACC = 7 7 + 8 = 15 · PC devient 2

Le compteur sélectionne ADD 5. L’argument 5 est une adresse ; la valeur ajoutée est 8. ADD ne modifie aucune cellule de mémoire.

Lis le schéma. Suis le trait plein du compteur à l’instruction, puis le trait pointillé de la donnée vers le processeur. Pourquoi ajoute-t-on 8 et non 5 ?

La même mémoire contient les instructions descriptives et les données. Après ce seul ADD, ACC vaut 15 et PC vaut 2 ; la cellule 6 contient encore 0.

Exemples résolus et erreurs expliquées

Une adresse n’est pas la valeur qu’elle contient

  1. Numérote les sept cellules de 0 à 6. Les adresses 0 à 3 contiennent les instructions descriptives ; les adresses 4, 5 et 6 contiennent ici des entiers.
  2. À pc=0, LOAD 4 place 7 dans l’accumulateur. À pc=1, ADD 5 ajoute le contenu 8 de l’adresse 5, et non le nombre 5 : l’accumulateur devient 15.
  3. À pc=2, STORE 6 écrit 15 dans la cellule 6. Au début de ce pas, cette cellule contient encore 0 ; la trace d’avant HALT montre ensuite la valeur 15.
  4. HALT 0 arrête après quatre instructions lues, arrêt compris. La liste fournie par l’appelant reste intacte car la machine travaille sur sa copie ; la mémoire finale est renvoyée séparément.

Conclusion. Pour lire une trace, annonce son instant : avant l’instruction ou après son effet.

Laboratoire de code

Languepython

Butobserver instructions et données dans un espace adressable commun avec compteur ordinal

Code solution
def machine(memoire, limite=30):
    if not isinstance(memoire, (list, tuple)) or not memoire:
        raise ValueError('mémoire non vide attendue')
    if type(limite) is not int or not 1 <= limite <= 1000:
        raise ValueError('limite entière entre 1 et 1000')
    copie = []
    for cellule in memoire:
        if type(cellule) is int:
            copie.append(cellule)
        elif isinstance(cellule, (list, tuple)) and len(cellule) == 2:
            op, arg = cellule
            if op not in ('LOAD','ADD','STORE','JUMP','HALT') or type(arg) is not int:
                raise ValueError('instruction invalide')
            copie.append((op, arg))
        else:
            raise ValueError('cellule invalide')
    pc, acc, trace = 0, 0, []
    for _ in range(limite):
        if not 0 <= pc < len(copie):
            raise ValueError('compteur hors mémoire')
        instruction = copie[pc]
        if type(instruction) is not tuple:
            raise ValueError('une donnée ne se lit pas comme instruction')
        operation, argument = instruction
        trace.append((pc, instruction, acc, tuple(copie)))
        pc += 1
        if operation == 'HALT':
            if argument != 0:
                raise ValueError('HALT attend 0')
            return acc, copie, trace
        if not 0 <= argument < len(copie):
            raise ValueError('adresse hors mémoire')
        if operation in ('LOAD','ADD'):
            valeur = copie[argument]
            if type(valeur) is not int:
                raise ValueError('donnée entière attendue')
            acc = valeur if operation == 'LOAD' else acc + valeur
        elif operation == 'STORE':
            copie[argument] = acc
        else:
            pc = argument
    raise RuntimeError('limite de pas atteinte')

Tests

programme = [('LOAD',4),('ADD',5),('STORE',6),('HALT',0),7,8,0]
acc, memoire, trace = machine(programme)
assert acc == memoire[6] == 15
assert [ligne[0] for ligne in trace] == [0,1,2,3]
assert [ligne[2] for ligne in trace] == [0,7,15,15]
assert trace[2][3][6] == 0 and trace[3][3][6] == 15
assert programme[6] == 0
assert machine([('HALT',0)], 1)[0] == 0
assert machine([('JUMP',2),99,('HALT',0)])[0] == 0
try:
    machine([('JUMP',0)], 3)
except RuntimeError:
    pass
else:
    raise AssertionError('limite non appliquée')

Trace

  • Avant pc=0 : acc=0 ; LOAD 4 lit la donnée 7 à l’adresse 4.
  • Avant pc=1 : acc=7 ; ADD 5 lit la donnée 8 à l’adresse 5, puis acc devient 15.
  • Avant pc=2 : acc=15 et mémoire[6]=0 ; STORE 6 écrit 15. Avant HALT à pc=3, mémoire[6] vaut 15.

Clinique de bogue

Indice observécharger([10, 20, 30], 1) renvoie 30 alors que l'adresse 1 désigne 20 dans la convention annoncée

CauseLe code ajoute un décalage implicite comme si les adresses commençaient à un, alors que le modèle et les tests utilisent des indices à partir de zéro. Une convention d'adressage doit rester unique et documentée.

04

Étape du cours · 7 à 14 min

Langages et systèmes : changer d’écriture sans perdre le sens

Un langage de haut niveau permet d’écrire un calcul sans détailler chaque instruction du processeur. En 1957, l’équipe IBM dirigée par John Backus développe FORTRAN pour le calcul scientifique. La même année, des travaux de Grace Hopper sur les compilateurs aboutissent notamment à FLOW-MATIC pour le traitement de données. Ces usages ne se réduisent pas à une compétition entre écritures : calcul scientifique et gestion posent des besoins différents.

Un traducteur transforme une description en une autre ; un exécuteur réalise les opérations de la représentation qu’il reçoit. Un compilateur peut produire du code machine ou une représentation intermédiaire. Un interprète exécute un programme, parfois après une traduction intermédiaire. « Compilé » et « interprété » décrivent une mise en œuvre : une même chaîne peut combiner les deux.

À partir de 1969, Ken Thompson et Dennis Ritchie participent au développement d’UNIX aux Bell Labs. Un système d’exploitation organise notamment l’exécution, la mémoire, les fichiers et les périphériques. Il offre des services à des programmes écrits dans plusieurs langages. Il ne faut donc pas confondre langage, traducteur et système d’exploitation, même si leurs histoires et leurs communautés se croisent.

Dans notre exemple, le langage fictif A écrit SET 4 puis ADD 3 ; B écrit valeur 4 puis plus 3. Les deux traducteurs produisent [('SET',4),('ADD',3)]. SET remplace l’accumulateur et ADD lui ajoute une valeur. L’exécuteur commun obtient 7, puis ne conserve aucune information sur l’écriture A ou B d’origine.

Le domaine est volontairement court : une liste ou un tuple de lignes, chacune formée de deux éléments séparés par des espaces, une opération autorisée et un entier lisible par int en base dix. Pas de variable, de commentaire ni d’expression composée dans cette première version. Une erreur de langage ou de traduction est signalée avant l’exécution. L’exécuteur contrôle aussi sa propre entrée, car on peut l’appeler directement sans le traducteur.

Exemples résolus et erreurs expliquées

Deux écritures, un même calcul

  1. Le traducteur A reconnaît deux opérations SET. Le traducteur B transforme chaque mot valeur en SET. Les deux produisent [('SET',10),('SET',3)].
  2. L’exécuteur commence avec acc=0. La première opération SET remplace cette valeur par 10 : ce n’est pas une instruction d’addition.
  3. La seconde opération SET remplace 10 par 3. Le résultat est 3. Pour obtenir 13, il aurait fallu ADD 3, ou plus 3 dans B.
  4. Teste séparément la traduction attendue et le résultat d’exécution. Si la représentation est correcte mais le résultat faux, le problème vient de l’exécuteur, pas des deux lexiques.

Conclusion. Conserver le sens des opérations est plus important que faire correspondre des mots.

Laboratoire de code

Languepython

Buttraduire deux syntaxes fictives vers les mêmes opérations et comparer abstraction et exécution

Code solution
def traduire(lignes, langage):
    if langage not in ('A','B') or not isinstance(lignes, (list, tuple)):
        raise ValueError('langage ou lignes invalides')
    lexique = {'SET':'SET','ADD':'ADD'} if langage == 'A' else {'valeur':'SET','plus':'ADD'}
    operations = []
    for ligne in lignes:
        if not isinstance(ligne, str):
            raise ValueError('ligne de texte attendue')
        morceaux = ligne.split()
        if len(morceaux) != 2 or morceaux[0] not in lexique:
            raise ValueError('syntaxe inconnue')
        try:
            entier = int(morceaux[1], 10)
        except ValueError:
            raise ValueError('entier décimal attendu')
        operations.append((lexique[morceaux[0]], entier))
    return operations

def executer(operations):
    if not isinstance(operations, (list, tuple)):
        raise ValueError('suite d’opérations attendue')
    acc = 0
    for instruction in operations:
        if not isinstance(instruction, (list, tuple)) or len(instruction) != 2:
            raise ValueError('instruction invalide')
        operation, valeur = instruction
        if type(valeur) is not int:
            raise ValueError('entier attendu')
        if operation == 'SET':
            acc = valeur
        elif operation == 'ADD':
            acc += valeur
        else:
            raise ValueError('opération inconnue')
    return acc

Tests

a = traduire(['SET 4','ADD 3'], 'A')
b = traduire(['valeur 4','plus 3'], 'B')
assert a == b == [('SET',4),('ADD',3)]
assert executer(a) == 7
assert executer(traduire(['SET -2','ADD 5'], 'A')) == 3
assert executer([('SET',10),('SET',3)]) == 3
assert executer([]) == 0
for lignes, langage in [([], 'X'), ([''], 'A'), (['SET 1.5'], 'A'), (['plus 3'], 'A')]:
    try:
        traduire(lignes, langage)
    except ValueError:
        pass
    else:
        raise AssertionError('traduction invalide acceptée')

Trace

  • SET 4 et valeur 4 deviennent la même opération intermédiaire ('SET',4)
  • ADD 3 et plus 3 deviennent ('ADD',3) malgré deux syntaxes visibles
  • l'exécuteur ne connaît plus la syntaxe d'origine et produit 7 dans les deux cas

Clinique de bogue

Indice observéla suite SET 10 puis SET 3 renvoie 13, alors que la seconde affectation doit remplacer la première valeur

CauseLa représentation intermédiaire distingue deux sémantiques, mais l'exécuteur les implémente par la même addition. Une abstraction reste utile seulement si chaque opération conserve son contrat propre.

05

Étape du cours · 9 à 16 min

Internet et Web : des réseaux, puis des ressources reliées

ARPANET relie des machines de recherche à partir de 1969. Internet se construit comme une interconnexion de réseaux capables de communiquer selon des protocoles communs, avec des contributions de plusieurs pays. Dans le récit publié en 1997 par des acteurs de cette histoire, Internet Society distingue les idées, les expériences, les infrastructures et les communautés. Le 1er janvier 1983, le passage d’ARPANET de NCP à TCP/IP est un repère de coordination, pas la création de toutes les formes de réseau.

Le 7 avril 1969, Steve Crocker signe la RFC 1, consacrée au logiciel des hôtes du réseau ARPA. Son introduction décrit des réunions et des responsabilités réparties entre équipes. C’est une trace de coopération technique datée, pas une spécification de HTTP. Les RFC sont une famille de documents aux statuts variés : leur numéro seul ne signifie pas qu’une proposition est un standard adopté.

En mars 1989, Tim Berners-Lee propose au CERN un système d’information hypertexte distribué. Le document conservé par le W3C porte aussi une mention de mai 1990 : distingue la date de la proposition et celle de cette version. Le besoin est de retrouver les relations entre documents, personnes et projets. Le premier serveur et le navigateur-éditeur WorldWideWeb sont développés en 1990 ; proposition et logiciel ne sont donc pas le même événement.

Le Web articule l’identification des ressources, les échanges HTTP et les documents HTML avec des liens. Ces fonctions utilisent les services réseau, mais ne sont pas IP. Une URL précise une adresse de ressource ; HTML décrit un document, HTTP organise requêtes et réponses. TCP fournit un transport ordonné fiable selon son contrat ; les échanges Web ne sont pas tous fondés sur TCP, notamment avec HTTP/3. Retenir les rôles est plus solide que dessiner une pile unique valable dans tous les cas.

Notre atelier découpe un texte Python en fragments numérotés. Il compte des éléments de chaîne, donc des points de code, pas des octets ni forcément des caractères visuels entiers. Le récepteur connaît déjà le nombre total attendu. Il refuse une perte, un doublon ou une incohérence avant de reconstruire. Ainsi, zéro fragment reçu pour un message qui en attend trois n’est pas confondu avec un message vide.

Annoter un chemin comme A → B → D ajoute une indication à notre trace ; cela ne réalise aucun routage. Tous les fragments concernent un seul message, sans mélange, corruption ni retransmission. La simulation montre l’intérêt de l’ordre logique ; le document historique explique l’organisation du réseau. Aucun appel réseau n’est nécessaire pour exécuter le modèle.

Voir pour comprendre

Internet et Web : des fonctions imbriquées

Le Web utilise l'interconnexion de réseaux, mais ne la résume pas.

Internet et Web : des fonctions imbriquées
EnsembleFonctionRepères à distinguer
Internetinterconnecter des réseaux ; IP achemine les paquetsARPANET : 1969 ; transition TCP/IP : 1983
Webidentifier et relier des ressources, échanger en HTTPproposition : 1989 ; premiers logiciels : 1990

Lis le schéma. Situe un échange HTTP dans les deux lignes. Un réseau doit-il cesser d'exister lorsqu'aucune page Web n'est consultée ?

La proposition du Web au CERN en 1989 ne marque pas la naissance de toute l'interconnexion Internet.

Exemples résolus et erreurs expliquées

Un texte intact malgré une arrivée désordonnée

  1. Le fragment 0 contient HYPE, le 1 RTEX et le 2 TE. Chacun annonce le total 3. Le dernier fragment peut être plus court que les autres.
  2. Dans l’ordre d’arrivée, la concaténation donnerait TE + HYPE + RTEX, soit TEHYPERTEX. Ce texte faux montre pourquoi l’arrivée ne définit pas la position.
  3. Le récepteur contrôle les types, les bornes 0 à 2, l’unicité des numéros et le total attendu. Trois numéros distincts dans ces bornes établissent ici que tous sont présents.
  4. Il lit ensuite les contenus dans l’ordre 0, 1, 2 pour rendre HYPERTEXTE. Si aucun fragment n’arrive, le total attendu 3 fait signaler une réception incomplète, pas un message vide.

Conclusion. Le modèle reconstruit un message ; il ne choisit pas ses routes et ne retransmet pas ses pertes.

Laboratoire de code

Languepython

Butfragmenter un message synthétique, suivre des chemins et reconstruire selon les numéros de fragments

Code solution
def fragmenter(message, taille):
    if not isinstance(message, str) or type(taille) is not int or taille <= 0:
        raise ValueError('texte et taille entière positive attendus')
    morceaux = [message[i:i + taille] for i in range(0, len(message), taille)]
    return [(numero, len(morceaux), morceau) for numero, morceau in enumerate(morceaux)]

def reconstruire(paquets, total_attendu):
    if not isinstance(paquets, (list, tuple)):
        raise ValueError('liste de fragments attendue')
    if type(total_attendu) is not int or total_attendu < 0:
        raise ValueError('total attendu entier positif ou nul')
    contenus = {}
    for paquet in paquets:
        if not isinstance(paquet, (list, tuple)) or len(paquet) != 3:
            raise ValueError('fragment à trois éléments attendu')
        numero, total, contenu = paquet
        if type(numero) is not int or type(total) is not int:
            raise ValueError('numéro et total entiers attendus')
        if total != total_attendu or not 0 <= numero < total or numero in contenus:
            raise ValueError('numéro, total ou doublon invalide')
        if not isinstance(contenu, str) or not contenu:
            raise ValueError('contenu textuel non vide attendu')
        contenus[numero] = contenu
    if len(contenus) != total_attendu:
        raise ValueError('fragments incomplets')
    return ''.join(contenus[i] for i in range(total_attendu))

def annoter_chemin(paquet, chemin):
    if not isinstance(paquet, (list, tuple)) or len(paquet) != 3:
        raise ValueError('fragment attendu')
    if not isinstance(chemin, (list, tuple)) or len(chemin) < 2:
        raise ValueError('au moins deux nœuds attendus')
    if any(not isinstance(n, str) or not n.strip() for n in chemin):
        raise ValueError('noms de nœuds attendus')
    return tuple(paquet), tuple(chemin)

Tests

paquets = fragmenter('HYPERTEXTE', 4)
assert paquets == [(0,3,'HYPE'),(1,3,'RTEX'),(2,3,'TE')]
assert reconstruire([paquets[2],paquets[0],paquets[1]], 3) == 'HYPERTEXTE'
assert fragmenter('',4) == [] and reconstruire([],0) == ''
assert annoter_chemin(paquets[0], ['A','B','D'])[1] == ('A','B','D')
assert reconstruire(fragmenter('é🙂e\u0301',1),4) == 'é🙂e\u0301'
for recue in ([], paquets[:2], paquets + [paquets[0]], [(0,3,'X'),(1,2,'Y')]):
    try:
        reconstruire(recue, 3)
    except ValueError:
        pass
    else:
        raise AssertionError('réception invalide acceptée')

Trace

  • HYPERTEXTE fournit trois fragments numérotés 0, 1, 2 ; le total 3 est connu séparément du récepteur.
  • L’arrivée 2,0,1 n’est pas l’ordre du texte : concaténer directement donnerait TEHYPERTEX.
  • Après contrôle des numéros uniques et du total attendu, l’ordre 0,1,2 rend HYPERTEXTE ; même la perte de tous les fragments est détectée.

Clinique de bogue

Indice observédes fragments arrivés dans l'ordre 2,0,1 donnent TEHYPERTEX au lieu de HYPERTEXTE

CauseL’ordre d’arrivée est pris pour l’ordre du texte. Le récepteur doit aussi connaître le total attendu hors des fragments reçus : sinon la perte de tout le message serait confondue avec un texte vide. Ici les numéros sont uniques, les totaux cohérents et les contenus non vides ; le nombre reçu doit égaler le nombre attendu.

06

Étape du cours · 9 à 16 min

Enquêter et réaliser : relier une décision à sa preuve

Pour une fiche historique, écris une affirmation assez précise pour être discutée. Par exemple : « Tim Berners-Lee propose au CERN en 1989 un système d’information hypertexte distribué. » Relève auteur, institution, date portée par le document, passage pertinent et adresse de consultation. La proposition conservée par le W3C explique un besoin et une solution envisagée ; elle ne mesure pas à elle seule le nombre de personnes qui ont ensuite utilisé le Web.

Croise une trace de l’époque avec une étude ou une notice de conservation. Une notice peut décrire une pièce authentique, une reproduction ou une reconstruction récente : lis la légende avant de dater une photographie. Pour Lovelace, distingue le texte publié en 1843 d’une réalisation matérielle de la machine. Si deux documents donnent des dates différentes, vérifie d’abord s’ils datent la conception, la publication, le prototype ou la diffusion.

Le projet suit la même exigence de précision. Définis le public et un besoin, puis des critères observables : « chaque lien mène à une fiche existante » est testable, « le musée est intéressant » ne dit pas encore comment le contrôler. Prépare le code et les documents dans un dossier local versionné, avec un journal court : problème, options, choix, raisons et vérification. Après une modification, relance les tests qui portent sur le comportement changé.

Le laboratoire lit un journal fictif dans l’ordre donné. Il exige un identifiant unique, des dépendances déjà acceptées, deux critères textuels distincts, au moins une référence de preuve et un responsable fictif. Il ne lit pas les documents référencés et ne lance aucun test : « valide » signifie seulement conforme à ce contrat documentaire. Une ligne qui dit « tests verts » n’établit pas que les tests ont été exécutés.

Si un jalon vient avant sa dépendance, il reste refusé pendant ce passage, même si la dépendance arrive plus tard : la fonction ne réordonne pas le journal. Pour réexaminer le même jalon après correction, modifie sa fiche dans une nouvelle version du journal puis relance tout le contrôle. Ne duplique pas son identifiant. Les membres du groupe vérifient ensuite que chaque preuve est réelle et correspond à la bonne version.

Pour répartir le travail, fais tourner recherche, programmation, tests et présentation à chaque étape. Chacun explique au moins un choix documentaire et un morceau de code qu’il n’a pas rédigé seul. Le modèle de flux d’intégration décrit dans Pro Git aide à comprendre la relecture avant fusion ; le journal Python n’est pas un gestionnaire de versions. Le projet proposé ici entraîne cette démarche sur un objet borné, avec un temps propre de recherche et de réalisation.

Voir pour comprendre

Deux contrôles avant d’accepter un jalon

Les champs remplis rendent une vérification possible ; ils ne la remplacent pas.

  1. Définir le critèreQuel résultat observable est attendu, dans quelle version et après quelles dépendances ?
  2. Contrôler le journalLe code vérifie identifiants, dépendances, critères, références et responsable. Il n’ouvre pas les preuves.
  3. Vérifier la preuveLe groupe lit le document ou exécute le test, puis consigne résultat et version. Il recontrôle après modification.

Lis le schéma. Choisis un critère de ton projet et demande quelle preuve précise serait perdue si le code changeait.

La traçabilité relie une décision à des éléments vérifiables. Un statut « terminé » sans preuve actuelle n'établit pas le fonctionnement.

Exemples résolus et erreurs expliquées

Corriger une phrase historique à partir de sa source

  1. Identifie d’abord deux objets dans la phrase : l’interconnexion de réseaux et le système de ressources hypertextes. Chercher une date commune masque déjà cette différence de fonction.
  2. La proposition conservée par le W3C nomme Tim Berners-Lee et le CERN ; elle porte mars 1989 et mai 1990. Son début présente un besoin de gestion d’informations liées. Cela renseigne une proposition et sa version, pas la naissance d’Internet.
  3. Croise avec le récit d’Internet Society : la transition d’ARPANET vers TCP/IP est datée du 1er janvier 1983. La page historique du W3C situe les premiers logiciels Web en 1990. Ne donne pas à un document la portée d’un autre.
  4. Réécris : « Le Web, proposé au CERN en 1989 puis mis en œuvre en 1990, utilise un Internet déjà développé. » Conserve les trois références et explique que cette phrase distingue proposition, réalisation et infrastructure.

Conclusion. Une bonne date répond à « quel événement ? ». La source, son contexte et le croisement permettent de justifier la reformulation.

Laboratoire de code

Languepython

Butcontrôler un journal de projet par dépendances, critères, preuves et responsables fictifs

Code solution
def textes_distincts(valeurs, minimum):
    return (isinstance(valeurs, (list, tuple))
            and len(valeurs) >= minimum
            and all(isinstance(v, str) and v.strip() == v and v for v in valeurs)
            and len(set(valeurs)) == len(valeurs))

def verifier_jalons(jalons):
    if not isinstance(jalons, (list, tuple)):
        raise ValueError('journal attendu')
    termines, vus, rapport = set(), set(), []
    for jalon in jalons:
        if not isinstance(jalon, dict):
            raise ValueError('fiche de jalon attendue')
        identifiant = jalon.get('id')
        if not isinstance(identifiant, str) or not identifiant.strip() or identifiant != identifiant.strip():
            raise ValueError('identifiant non vide attendu')
        if identifiant in vus:
            raise ValueError('identifiant dupliqué')
        vus.add(identifiant)
        dependances = jalon.get('dependances')
        if not textes_distincts(dependances, 0) or identifiant in dependances:
            raise ValueError('dépendances invalides')
        dependances_ok = set(dependances) <= termines
        criteres_ok = textes_distincts(jalon.get('criteres'), 2)
        preuves_ok = textes_distincts(jalon.get('preuves'), 1)
        responsable = jalon.get('responsable')
        responsable_ok = isinstance(responsable, str) and bool(responsable.strip())
        valide = dependances_ok and criteres_ok and preuves_ok and responsable_ok
        rapport.append((identifiant, valide, dependances_ok, criteres_ok, preuves_ok, responsable_ok))
        if valide:
            termines.add(identifiant)
    return rapport, termines

Tests

J = [
 {'id':'besoin','dependances':[],'criteres':['public défini','problème borné'],'preuves':['fiche-v1'],'responsable':'A'},
 {'id':'prototype','dependances':['besoin'],'criteres':['cas nominal','cas limite'],'preuves':['tests-v1'],'responsable':'B'}
]
assert verifier_jalons(J)[1] == {'besoin','prototype'}
assert all(ligne[1] for ligne in verifier_jalons(J)[0])
assert verifier_jalons(J[::-1])[1] == {'besoin'}
assert verifier_jalons([]) == ([], set())
sans_preuve = dict(J[0], preuves=[])
assert verifier_jalons([sans_preuve,J[1]])[1] == set()
try:
    verifier_jalons([J[0],J[0]])
except ValueError:
    pass
else:
    raise AssertionError('identifiant dupliqué accepté')

Trace

  • besoin satisfait les conditions du journal et n’a pas de dépendance ; son identifiant entre dans l’ensemble accepté.
  • prototype peut ensuite satisfaire sa dépendance à besoin ; le contrôleur vérifie la présence de références, pas leur vérité.
  • Inverser les deux fiches refuse prototype pendant ce passage. Modifier une référence dans une nouvelle version oblige à contrôler de nouveau le journal et les preuves.

Clinique de bogue

Indice observéun jalon avec seulement un nom de responsable est considéré terminé, même sans critère ni preuve

Causeor accepte une seule condition et peut renvoyer une chaîne ou une liste. La petite fonction ci-dessous ne vérifie que le contenu d’une fiche, sans dépendances ni identifiant : elle exige la présence conjointe du responsable, de critères distincts et de références. Son résultat booléen ne certifie pas que les preuves sont vraies.

Poursuivre avec l’abonnement

Comprendre les repères, puis vérifier ton raisonnement

Les explications, quatre schémas et six exemples guidés sont en accès libre.

L’abonnement ouvre les six ateliers, les diagnostics, dix questions corrigées, douze cartes et le projet d’hypertexte à adapter.

10 questions · 12 cartes. La reprise des ateliers, du quiz et des cartes reste enregistrée dans ce navigateur.

Voir les formules

Vérifier et prolonger

Sources du cours

Édition Maxdecours · Vérifié le .

Spécialité NSI, Première générale · programme du BO spécial du 22 janvier 2019

  1. Programme de spécialité NSI de Première, pages 2 et 3Ministère de l’Éducation nationale · consulté le 2026-09-06
  2. Charles Babbage’s Difference Engines and the Science MuseumScience Museum · consulté le 2026-09-06
  3. Professor George Boole, archives et bibliographieUniversity College Cork · consulté le 2026-09-06
  4. Claude Shannon, travaux sur la commutationMassachusetts Institute of Technology · consulté le 2026-09-06
  5. On Computable Numbers, article de TuringA. M. Turing, copie conservée au MIT · consulté le 2026-09-06
  6. How a 70-year-old ‘Baby’ changed the face of modern computingUniversity of Manchester · consulté le 2026-09-06
  7. Timeline 1949, EDSACComputer History Museum · consulté le 2026-09-06
  8. 1947: Invention of the Point-Contact TransistorComputer History Museum · consulté le 2026-09-06
  9. Timeline 1971, Intel 4004Computer History Museum · consulté le 2026-09-06
  10. Timeline 1957, FORTRAN et FLOW-MATICComputer History Museum · consulté le 2026-09-06
  11. Timeline 1969, UNIX et réseauxComputer History Museum · consulté le 2026-09-06
  12. A Brief History of the Internet, récit publié en 1997Internet Society · consulté le 2026-09-06
  13. Information Management: A Proposal, mars 1989 / mai 1990Tim Berners-Lee, CERN ; conservation W3C · consulté le 2026-09-06
  14. History, premiers logiciels du WebWorld Wide Web Consortium · consulté le 2026-09-06
  15. RFC 1: Host Software, 7 avril 1969Steve Crocker, UCLA ; RFC Editor · consulté le 2026-09-06
  16. RFC 9114: HTTP/3, introductionIETF, RFC Editor · consulté le 2026-09-06
  17. Pro Git, Distributed WorkflowsProjet Git · consulté le 2026-09-06