Présentation de l'art de programmer ==================================== Qu'est-ce que la programmation ? -------------------------------- programmation Description d’un calcul (traitement) dans un langage compréhensible par la machine (langage de programmation) Le processus d'abstraction -------------------------- Débuter en programmation n'est pas une chose aisée. Aujourd'hui, la tendance est au "bas niveau". Souvent, on se jette dans le grand bain : - soit en s'approchant au maximum de la machine (admin système et réseau, noyau linux, langage C) - soit en faisant du dev web côté backend, ce qui ramène à une administration réseau de bas niveau (microservices, monde nodeJS/javascript, etc...) Soit on suit un cursus scolaire traditionnel qui commence souvent par une explication du fonctionnement d'une machine abstraite de bas niveau, puis en allant de plus en plus haut, mais étant sous-entendu qu'il faut rester connecté au bas niveau (comprendre comment ça se passe derrière la scène). Dans ces deux cas, il est sous-entendu qu'on apprend plus de choses et plus rapidement en mettant les mains dans le cambouis, ce qui est vrai bien sûr. Mais cela sous-entend qu'un développeur doit rester le nez dans le guidon. Qu'il doit être un expert de son domaine en accumulant des technologies sans aucun recul. Bien sûr il se doit d'être un expert du système dans lequel il évolue (connaissance du système d'exploitation, binding avec le C, du ramasse miette (garbage collector), interaction avec les différentes librairies, gestion et optimisation de la mémoire, architecture par microservices, threads...) mais il doit aussi être capable de prendre du recul. L'approche algorithmique (algorithmique de pseudo code, algorithmique algébrique et modulaire) est un véritable moyen pour le programmeur de prendre du recul : elle commence par se placer du côté de l'esprit humain et de ses capacités de compréhension et d'abstraction, elle autorise une pensée rationnelle sur l'art de programmer et permet au programmeur d'effectuer les bons choix, en connaissance de sa discipline. Le lien est fait ensuite avec le plus bas niveau grâce une implémentation effective des langages à partir des paradigmes de rationalisation de la penseée (modules, objects, généricité, polymorphisme paramétrique...) et d'un outil de communication avec la machine qu'on appelle compilateur (dont la description est en dehors de l'objectif de ce cours). La tendance générale de l'évolution des langages est de se libérer de ces contraintes de bas niveau, un peu comme en sciences physiques où les lois physiques dépendent de l'échelle d'en dessous (du niveau microscopique/quantique) mais qu'à l'échelle du dessus, on n'a pas affaire à des effets de bas niveau (pas d'effets quantiques à un niveau macroscopique en général). Ce processus d'évolution est vrai aussi dans le monde de la technique informatique lui-même (modèle OSI, comment est construite une trame IP, indépendances de chaque couche (transport, payload) entre elles). Même la tendance système est à la virtualisation qui accentue encore la tendance à s'affranchir du bas niveau (le niveau système), le séparer nettement du haut niveau (le niveau applicatif). Il apparaît régulièrement de nouveaux langages. Comment s'orienter ? Quel(s) langage(s) choisir pour un projet de développement ? Au delà de leurs disparités, la conception et la genèse de chacun d'eux procèdent d'une motivation partagée : la volonté d'abstraire. - **s'abstraire de la machine** : un langage de programmation permet de négliger l'aspect *mécanique* de l'ordinateur. On oublie le modèle du microprocesseur, jusqu'au système d'exploitation sur lequel sera exécuté le programme. - **abstraire les erreurs** : Il s'agit ici de garantir la sûreté d'exécution; un programme ne doit pas se terminer brutalement ou devenir incohérent en cas d'erreur. Un des moyens pour y parvenir est le typage des programmes et la mise en oeuvre d'un mécanisme d'exceptions. - **abstraire le mode opératoire** : Il s'agit de choisir une représentation, un paradigme d'implémentation qui est indépendant du domaine considéré (paradigme objet, modulaire, générique, composants...) - **abstraire les composants** : Les langages de programmation donnent la possibilité de découper une application en différents composants logiciels, plus ou moins indépendants et autonomes. La modularité permet une structuration de plus haut niveau de l'ensemble d'une application complexe. Les langages à objets constituent une autre approche de la réutilisabilité permettant la réalisation très rapide de prototypes. Description des niveaux d'abstraction par rapport à la machine --------------------------------------------------------------- Les langages de haut niveau simplifient le travail du programmeur là où les langages de bas niveau permettent de produire un code plus efficace. - **niveau 0** : le langage machine. Illisible, c'est une suite d'optcode. impossible de coder dans ce langage. - **niveau 1** : langage d'assemblage. Il reste très dépendant de la machine et aujourd'hui il est rare d'en faire, sauf si on code un bootloader par exemple, la gestion de l'accès à la mémoire est en réel (le mode protégé n'apparaît que après). Il faut gérer les ressources,le langage est très optimisé mais presque impossible à maintenir et rendre générique. Aujourd'hui plus personne ne code en assembleur. - **niveau 2** : langages dits de **bas niveau** : (exemple : le C, le C++) indépendance par rapport à la machine, grande structuration mais très verbeux - **niveau 3** : langages dits de **haut niveau** : le raisonnement dans ces langages ne dépent plus de la machine, et ils implémentent des paradigmes de programmation indépendant de l'état de la mémoire de l'ordinateur, ils sont indépendant même du système d'exploitation. Qu'est-ce qu'une machine ? --------------------------- Une machine, ce truc apparemment si complexe, est en fait un assemblage de bric et de brac. L'assemblage des connecteurs permet de simuler un additionneur, en prenant en compte les propriétés de **reste euclidien** de l'addition. La structure électronique est composée de : - un ordonnanceur. - le stockage d'un **état**. - une pile d'instruction .. glossary:: adressage Dès lors qu'on dispose de ces bases électronique au dessus du processeur, un langage d'assemblage est possible, c'est le langage de calcul sur les registres. registre machines ont un espace mémoire et un espace de calcul (registres) Un ordinateur, c'est très très stupide, mais ça permet de disposer de : - une mémoire très grande et ordonnée, - une capacité à effectuer inlassablement des tâches répétitives - une grande rapidité de calcul Apprendre à programmer, c'est-à-dire être capable de contrôler la machine. .. important:: Apprendre à programmer, c'est-à-dire apprendre à penser de manière structurée, pour pouvoir accessoirement ensuite communiquer avec une machine. Compilateur ----------- Schématiquement, un compilateur est un programme qui traduit un programme d’un langage source vers un langage cible, en signalant d’éventuelles erreurs. Quand on parle de compilation, on pense typiquement à la traduction d’un langage de haut niveau (C, Java, Caml, ...) vers le langage machine d’un processeur (Intel Pentium, PowerPC, ...) - xml (libre office, word) -> postscript (imprimante) - postcript -> image - syntaxe wiki -> html (Wikipédia...) compilation graphique passer une description, ça donne un dessin genre ocaml Quilt < mon_dessin.txt passer par une api qui permet de causer avec une interface **transpiler** : transformation d'un langage de haut niveau vers un autre langage de haut niveau. - cofee script, typescript -> javascript - (babel) javascript -> javascript ES 6 - python -> javascript Un compilateur traduit un programme P en un programme Q tel que pour toute entrée x , la sortie de `Q(x)` soit la même que celle de `P(x)` Un interprète est un programme qui, étant donné un programme `P` et une entrée x , calcule la sortie s de `P(x)` Le compilateur fait un travail complexe une seule fois, pour produire un code fonctionnant pour n’importe quelle entrée L’interprète effectue un travail plus simple, mais le refait sur chaque entrée Autre différence : le code compilé est généralement bien plus efficace que le code interprété Typiquement, le travail d’un compilateur se compose d’une phase d’analyse - reconnaît le programme à traduire et sa signification - signale les erreurs et peut donc échouer (erreurs de syntaxe, de portée, de typage, etc.) Puis d’une phase de synthèse - production du langage cible - utilise de nombreux langages intermédiaires - n’échoue pas