Principes de programmation

1. Qu'est-ce que programmer ?

Programmer, c'est écrire un texte dans un langage compréhensible par une machine, visant à exécuter un certain nombre d'instructions. Il existe plusieurs langages de programmation, qui se répartissent en plusieurs niveaux. Les langages "bas-niveau" sont des langages très proches des instructions machine tels que l'Assembleur, contrairement aux langages de plus haut niveau comme le C++ qui est un langage "facilement" compréhensible par l'être humain (if color=="red" ... la machine ne sait absolument pas ce que veut dire "red" ...)

La programmation est un langage, elle met donc en avant une syntaxe régie par une grammaire. Les fonctions et outils sont le vocabulaire de cette langue.

J'entends souvent dire "tel langage est plus difficile que tel autre", ou "tel langage est à connaître avant tel autre"... Je serais tenté de dire que ceci est faux : c'est comme s'il fallait connaître l'anglais avant d'étudier l'allemand ... Bien entendu, la connaissance d'un langage avant celle d'un autre peut en faciliter l'apprentissage, mais ce n'est pas toujours le cas.

L'apprentissage d'un langage de programmation se déroule comme celui d'une langue (vivante ou morte) : on en apprend la grammaire (les structures de contrôle, les boucles s'il y a, les objets s'il y a ...), la syntaxe (parenthèses, saut de ligne, point virgule après chaque instruction, la syntaxe des variables ...), ainsi que le vocabulaire (les fonctions existantes).

Petite anecdote : j'ai souvent lu la (fausse) association d'idées entre le programmateur et le gars qui développe un code source ... Non : le programmateur, c'est le gros bouton "Démarrer / lavage / essorage / Arrêt" de la machine à laver, alors que le programmeur est bien celui qui écrit un code source ... :-)

2. Grammaire, syntaxe et vocabulaire

Je n'ai pas encore abordé de langage précis vu que ces notions s'appliquent à tous ...

Je distinguerai pour un langage de programmation 3 éléments (orienté langage de programmation, pas cours de français) :

La Grammaire
Ce sont les règles d'écriture qui permettent de structurer un énoncé. La grammaire est composée de plusieurs sous parties, entres autres la syntaxe et la sémantique, c.à.d. un ensemble de mots sur un alphabet.
La Syntaxe
C'est la manière d'écrire les instructions, au sens général du terme; une instruction pouvant être une déclaration de fonction, une boucle (if, for, while ...) ou une déclaration de variable, par exemple.. Certains langages tels que le Visual Basic demandent une instruction par ligne, chaque ligne devant se terminer par un simple retour à la ligne suivante.
Le Vocabulaire
Le vocabulaire est un ensemble de mots ayant une signification particulière dans une langue. En programmation, on pourrait associer cette notion aux fonctions et méthodes. (exemple : fonctions mathématiques, traitement de chaînes de caractères...)

3. Conventions et styles d'écriture

Chaque langage de programmation a ses propres requis en matière de conventions d'écriture. Chaque langage a aussi ses permissions. La façon d'écrire selon un langage n'est donc plus seulement une question de personnalité, mais aussi une question de permissivité du langage.

En outre, certaines conventions sont généralement fixées, c.à.d. qu'on retrouve dans la plupart des codes sources les mêmes façons de faire pour certains éléments :

  • les commentaires
  • les variables et leur dénomination
  • imbrication d'instructions

3.1. Les commentaires

Ce sont des morceaux de phrase, des indications, qui ne seront pas prises en compte lors de l'exécution du programme (parce qu'omis dans la compilation si le code est compilé) qui permettent au développeur d'expliquer ce qu'il fait. C'est une étape très importante, car elle permet non seulement de suivre le raisonnement (et de l'écrire en "bon" français) mais aussi de relire un code source quelques temps plus tard, ou le faire relire par quelqu'un d'autre.

Les commentaires permettent de se replonger dans le code source soit après une "pause", soit lorsque quelqu'un d'autre le regarde. Essayez de faire un code sans commentaire, de le laisser de coté pour 3 mois et d'y jeter un oeil après : selon la complexité du code, ça sera facile ou impossible ... De même, imaginez-vous un ami qui veut vous aider, s'il ne comprend pas ce qui est fait dans le code, il mettra beaucoup plus de temps ...

Selon la permissivité des langages, les commentaires peuvent se mettre sur une ou plusieurs lignes, voire sur un morceau de ligne.

Les commentaires se notent en général comme ceci :

  • // commente toute la ligne en cours
  • /* ..... */ commente tout ce qui est entre /* et */, que ce soit sur une ligne ou plusieurs
  • en ASP, c'est l'apostrophe qui remplace //

D'une manière générale, le code source est comme un livre qu'on lit de haut en bas, ainsi est-il préférable (disons, plus commun) de précéder l'instruction de son commentaire.

Voici quelques MAUVAIS exemples :

if ($a == 10) { echo "On est arrivé à 10, terminus !"; }
/* 10 est la fin de traitement */
/* j'ajoute 10 à $a pour obtenir $b */
$b = $a + 10;

Le premier mauvais exemple montre un commentaire qui suit l'instruction. Pour cette ligne, l'interprétation est simple, seulement pour un morceau de code plus complexe, devoir rechercher le commentaire après le code est fatigant...

En lisant un commentaire, il est intéressant de savoir ce qu'on se prépare à lire. Le second mauvais exemple illustre bien ceci : ce n'est pas la peine de commenter une action élémentaire, il vaut mieux avoir des commentaires plus efficaces.

Voici un MEILLEUR (je n'ose dire "bon") exemple :

	/*
	 * RandomPassword crée un texte aléatoire de $longueur caractères :o)
	 * param $longueur (int) -- longueur finale attendue
	 *
	 * @retour (string)
	 */
	function RandomPassword($longueur)
	{
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#';

		$password = '';
		for ($i = 0; $i < $longueur; $i++) { $password .= substr($chars, (mt_rand() % strlen($chars)), 1); }
		return $password;
	};

Cet exemple est tiré de NewsletTux 2, le choix du commentaire en anglais revient au développeur. Lorsqu'on lit le commentaire, on apprend ici :

  • ce que fait la fonction (générer un mot de passe aléatoire d'une certaine longueur)
  • ce qu'elle a en entrée (la longueur finale du mot de passe : un entier numérique)
  • ce qu'elle retourne (string = chaîne de caractères)

Le choix de ces commentaires est arbitraire, pour cet exemple j'ai choisi de donner une fonction que j'ai annotée, mais je peux tout aussi bien donner un déroulement d'une recherche dans une base de données...

Pourquoi n'ai-je pas dit "voici un "bon" exemple" ? Tout simplement parce qu'il n'y a pas de meilleure façon de travailler qu'une autre, chacun a sa touche de personnalité dans la façon d'écrire.

3.2. Les variables et leur dénomination

Une variable est un emplacement mémoire que la machine alloue pour y contenir une information. Par exemple, l'âge du capitaine. Plus concrètement, la variable est constituée de sept paramètres :

  • son nom
  • son type
  • sa valeur (contenu)
  • sa portée
  • sa taille
  • son adresse mémoire
  • sa durée de vie

Noms de variables

Le nom d'une variable est une chaîne de caractères, selon le langage précédée ou non d'un caractère spécial. En PHP, par exemple, les variables commencent toutes* par le signe "$" (dollar). (*toutes sauf les "define" superglobales)

LE VB (Visual Basic) ou l'ASP, ou encore le Javascript utilisent la syntaxe var pour définir une variable.

Voici quelques exemples :

PHP
---
	$prenom = 'Matthieu';
	$page = 3;

ASP
---
	var prenom = "Matthieu"
	var page = 20

Javascript
----------
	var prenom = "Matthieu";
	var page = 50;

Nommer une variable est une chose obligatoire pour tout langage acceptant les variables. Seulement s'en souvenir par la suite ... c'est mieux ! Certains langages sont sensibles à la casse, en PHP par exemple, $Prix et $prix seront deux variables différentes.

Le nom d'une variable n'a généralement pas de limite (sauf celle de stockage du programme), donc il est tout à fait possible, pour un chimiste par exemple, de nommer ainsi ses variables :

		$benzodiazepine = 1;
		$deux_deux_dimethyl_hydrazine = 0;
		$acide_desoxyribo_nucleique = 30;

Les seuls inconvénients en termes de nommage de variables sont les suivants :

  • Si le langage a un caractère pour la variable, il devient inaccessible dans la variable. Ex. en PHP, $ ne peut faire partie du nom d'une variable ($$auci$$e ne peut pas être la variable $saucisse) ;
  • les noms de fonctions et d'outils (boucles, etc.) sont réservés, par exemple, on ne pourra pas écrire var while = "Salut"
  • Un nom de variable trop court ou mal adapté peut être nuisible (ex. $bouton1, $bouton2, $bouton3... $bouton 16 => $bouton_accueil, $bouton_presentation, $bouton_achats ...) ;
  • Un nom trop long peut donner lieu à des fautes de frappe ;
  • un nom de variable commence par une lettre et non un chiffre.
  • L'alphabet pour le nom peut être différent d'un langage à l'autre, en général les 26 lettres de l'alphabet + les 10 chiffres et l'underscore (_), le trait d'union étant réservé à la soustraction.

Il s'agit donc de trouver un compromis entre la longueur du nom et son utilité. Mais quoi de plus parlant que $page pour le numéro de page, $somme_caddie pour un montant à payer ?

Types de variables

Certains langages sont très fortement typés, d'autres beaucoup moins. PHP, par exemple, est pauvrement typé (du moins jusqu'à sa version 5).

Le typage d'une variable consiste, lors de la déclaration, à donner sa nature. Son contenu lui sera donné plus tard.

Exemple : int age_capitaine;

cette variable sera de type "entier" (integer) et écrire par la suite age_capitaine="cinquante" posera un problème ... (vu qu'il s'agit d'une chaîne de caractères et non d'un nombre).

PHP ne requiert pas ce typage mais d'autres langages comme le Java par exemple sont fortement typés, et écrire age_capitaine=50; sans le faire précéder de int age_capitaine; affichera donc une erreur.

On peut, par transtypage (casting) changer le type d'une variable. Exemple : age_capitaine = (string) "cinquante" => ici age_capitaine qui était autrefois un entier devient une chaine de caractères.

Valeur de la variable

La valeur de la variable est ce qu'elle contient. Par exemple, $lambda = 30; : on stocke le nombre "30" dans la variable $lambda.

Portée de variable

La portée d'une variable est sa visibilité. La variable peut être omniprésente (on parle alors de variable globale) ou simplement locale (on parle alors de variable locale). Prenons quelques exemples, en PHP :

<?php
	/*
	 * premier test : variable globale
	 * On enregistre une variable, on l'appelle à plusieurs endroits après
	 */
	$stock_armoires = 50;

	echo '<ul>'."\n";
	echo '	<li>Quantité de pièces restantes : '.$stock_armoires.'</li>'."\n";
	echo '</ul>'."\n";

	echo '<p><a href="commander.php?article=armoire&stock='.$stock_armoires.'">Commander une armoire</a></p>'."\n";

	/*
	 * Fin de la première partie
	 * Ici $stock_armoires existe toujours et vaut toujours 50.
	 */

	 /*
	  * Seconde partie : variable locale
	  * On va enregistrer une variable dans le programme, et la manipuler localement.
	  * On s'aide pour cela d'une fonction
	  */

	$nombre1 = 10;
	$nombre2 = 10;
	$nombre3 = 100;

	function Addition($nombre_A, $nombre_B)
	{
		// dans cette fonction, on reçoit 2 nombres et on les additionne dans un troisième
		$nombre3 = $nombre_A + $nombre_B;

		// maintenant on renvoie le résultat de l'addition
		return $nombre3;
	};

	// Que vaut $nombre3 ici ?
	$nombre4 = Addition($nombre1, $nombre2);

	// réponse : $nombre3 = 100 !

	/*
	 * Explication
	 * Premièrement, je déclare mes 3 nombres.
	 * Deuxièmement, je déclare ma fonction "addition" : elle reçoit 2 paramètres (appelés $nombre_A et $nombre_B) et retourne un résultat
	 *
	 * Plus loin, je crée un 4ème nombre qui est le résultat de l'addition entre $nombre1 et $nombre2
	 * le $nombre3 qui est créé DANS la fonction est LOCAL, c.à.d. qu'il n'est pas visible à l'extérieur ...
	 * et $nombre3 DANS la fonction par rapport à $nombre3 déclaré avant (et contenant 100) ne sont pas les mêmes !
	 */

	// ici on a au final :
	$nombre1 -> 10
	$nombre2 -> 10
	$nombre3 -> 100
	$nombre4 -> 20

	// Maintenant si ici je fais :
	$nombre3 = 6000;

	// alors il ne vaut plus 100 : le $nombre3 ici n'est pas dans la fonction, il est sur le même terrain que celui déclaré au tout début.
?>

Soyons clairs : ce n'est pas très futé de ma part de choisir 2 fois $nombre3, mais le fait d'avoir mis le même nom est volontaire, cela illustre bien que dans la fonction, localement, on crée un $nombre3 indépendant de celui déjà existant : la fonction ne sait pas qu'un autre $nombre3 existe, tout ce qu'elle sait, c'est qu'il existe $nombre_A et $nombre_B. Elle se crée donc son propre $nombre3 qui n'écrasera pas l'autre. Par contre à la fin, on retourne dans le même terrain de jeu qu'au début, et là $nombre3 prend la valeur de 6000, écrasant celle de 100.

3.3. Imbrication d'instructions

Ce n'est pas un paragraphe propre à un langage, mais c'est plutôt un retour d'expérience. Plutôt axé PHP, je l'avoue.

L'idée ici est d'écrire une suite d'instructions (commentées !) avec plusieurs conditions. Ce que je tiens à illustrer par cet exemple est le saut de lignes, l'alinéa, les espacements et alignements des accolades { } qui encadreront mes instructions.

Soit l'énoncé suivant :

Afficher les liens des 20 pages pour un moteur de recherche, avec page précédente (si nécessaire), page suivante (si nécessaire), et tous les numéros de pages cliquables.

Voici mon exemple de code source, commenté et "alourdi" (on peut l'alléger après, je ne prends pas en compte les title des liens, c'est juste pour le principe) :

<?php
	// Système de pages
	$page = 5; // Supposons qu'on ait récupéré la page courante par un $_GET['page'] ou autre moyen
	$nombre_pages = 20; // Le nombre total de pages à afficher

	// Page précédente ?
	if ($page != 1)
	{
		// On n'est pas sur la première page => afficher "page précédente"
		echo '<a href="?page='.($page-1).'">Page précédente</a>';
	};

	// Pages de 1 à 20
	for ($i = 1; $i <= $nombre_pages; $i++)
	{
		echo '<a href="?page='.$i.'">- '.$i.' -</a>';
	};

	// Page suivante ?
	if ($page != $nombre_pages)
	{
		// On n'est pas sur la dernière page => afficher "page suivante"
		echo '<a href="?page='.($page+1).'">Page suivante</a>';
	};
?>

J'ai fait le choix de passer à la ligne pour ouvrir une accolade { et toutes les instructions comprises dans celles-ci ont un retrait d'une tabulation relativement à cette accolade ouvrante.

Je complète l'énoncé :

On devra différencier la page en cours par une couleur verte des autres pages qui seront rouges.

En gros, c'est la boucle for (qui va de 1 à 20) qu'il faut retoucher : regarder si à chaque étape on est à la page en cours ou non. Il faut donc une 2ème instruction dans cette instruction.

Le morceau à ajouter est celui-ci :

<?php
	if ($i == $page)
	{
		// on est à la page actuelle
		echo '<span style="color:#009900;">';
	}
	else
	{
		// ce n'est pas la page actuellement affichée
		echo '<span style="color:#FF0000;">';
	};
?>

puis rajouter le </span> pour clôturer la coloration.

Voici dans mon premier code ce que cela donne :

<?php
	// Système de pages
	$page = 5; // Supposons qu'on ait récupéré la page courante par un $_GET['page'] ou autre moyen
	$nombre_pages = 20; // Le nombre total de pages à afficher

	// Page précédente ?
	if ($page != 1)
	{
		// On n'est pas sur la première page => afficher "page précédente"
		echo '<a href="?page='.($page-1).'">Page précédente</a>';
	};

	// Pages de 1 à 20
	for ($i = 1; $i <= $nombre_pages; $i++)
	{
		if ($i == $page)
		{
			// on est à la page actuelle
			echo '<span style="color:#009900;">';
		}
		else
		{
			// ce n'est pas la page actuellement affichée
			echo '<span style="color:#FF0000;">';
		}
		echo '<a href="?page='.$i.'">- '.$i.' -</a></span>';
	};

	// Page suivante ?
	if ($page != $nombre_pages)
	{
		// On n'est pas sur la dernière page => afficher "page suivante"
		echo '<a href="?page='.($page+1).'">Page suivante</a>';
	};
?>

J'ai encore décalé d'un alinéa mon if ... else.

Complication simple :)

On pourrait envisager une structure beaucoup plus compacte de ce petit exemple, vu que beaucoup de choses sont répétées inutilement.

En utilisant une structure ternaire, par exemple :

<?php
	echo ($prenom == 'Matthieu') ? "salut" : "au revoir";
?>

la structure est assez simple : une condition est exprimée entre parenthèses, puis suivie d'un ? (point d'interrogation). S'ensuivent 2 "réponses" séparées par 2 points, c'est le retour de ce test. Le premier élément est renvoyé si vrai, le 2ème si faux.

ici, le test donnera le résultat de la commande "echo". Le echo affichera "salut" si $prenom est égal à "Matthieu", ou sinon "au revoir".

Adapté à mon exemple de système de page, cela permet de compacter l'écriture de la sorte :

<?php
	// Système de pages
	$page = 5; // Supposons qu'on ait récupéré la page courante par un $_GET['page'] ou autre moyen
	$nombre_pages = 20; // Le nombre total de pages à afficher

	// Page précédente ? Afficher si nécessaire.
	echo ($page != 1) ? '<a href="?page='.($page-1).'">Page précédente</a>' : '';

	// Pages de 1 à 20
	for ($i = 1; $i <= $nombre_pages; $i++)
	{
		echo '<span style="color:#"';
		echo ($i == $page) ? "009900" : "FF0000"; // vert si page courante, sinon rouge
		echo '"><a href="?page='.$i.'">- '.$i.' -</a></span>';
	}

	// Page suivante ? Afficher si nécessaire.
	echo ($page != $nombre_pages) ? '<a href="?page='.($page+1).'">Page suivante</a>' : '';
?>

La compaction de ce code est donc juste pour montrer qu'on peut écrire une condition if/else en une ligne, mais surtout que les commentaires, placés avant ou judicieusement à proximité du code qu'ils commentent, doivent être facilement compréhensibles et explicites pour une personne qui se pencherait sur un tel code.

Notons toutefois que l'écriture en structure ternaire des liens page précédente/suivante peut paraître moins lisible qu'avec un if plus classique ... C'est au goût de la personne qui travaille après ! Par contre quand il s'agit de permuter l'affichage rouge/vert, je trouve ça plus facile qu'un if/else.

4. Programmations Procédurale et Orientée Objet

Ce court paragraphe est juste là pour présenter 2 écoles de la programmation. Tous les langages acceptent la première, certains n'acceptent pas la seconde. Tous les tests expliqués précédemment mis de coté, détaillons un peu ces deux principes :

4.1. Programmation procédurale

C'est une programmation presque "linéaire", la programmation classique utilisable dans quasiment tous les langages. Elle met en scène des algorithmes, des fonctions, etc. C'est une façon "simple" de programmer (ce qui ne veut pas dire "inefficace").

4.2. La programmation Orientée Objet

Concept totalement différent, cette école enseigne l'art de créer un objet. Elle utilise pour cela des classes que l'on instancie. Pour prendre un exemple, la classe est une sorte de moule de fabrication. La classe "Voitures" aura des paramètres tels que : des portes, un pare-brise, des roues, une couleur et un moteur. Lorsqu'on crée l'objet "une voiture", on instancie la classe "Voitures" en un objet qui est "une voiture". On précise qu'elle a 4 roues (d'après le "moule", on sait fabriquer les roues), un moteur, 1 pare-brise, 5 portes et une couleur bleue. On peut instancier, à partir du même moule, une autre voiture qui sera en 3 portes et rouge.

Chaque classe regroupe des méthodes (en quelque sorte, ce ne sont que des fonctions) dont 1 est particulière : le constructeur. C'est la méthode qui sera appelée immédiatement lorsque la classe sera instanciée en objet (pour "définir les paramètres par défaut"). Puis, les autres méthodes pourront être appelées quand on en aura besoin.

Il faut bien comprendre qu'on ne peut pas jeter un papier à la poubelle si la poubelle n'existe pas : on doit d'abord instancier une classe (donc, créer un objet) afin d'utiliser ses méthodes et d'utiliser l'objet, surtout ! (l'objet hérite de toutes les méthodes de sa classe).

Que choisir ? C'est au goût de chacun. C'est aussi selon la facilité de programmation : s'il est plus facile de travailler en "procédural" lorsqu'il s'agit d'afficher des pages, il est plus facile de travailler en objet lorsqu'on crée un jeu avec des personnages qui ont des races, des points de vie, des compétences, etc.

5. Conclusion ...

On n'a nullement démontré quelle était la meilleure manière de programmer ... Ni même quel était le meilleur langage. On a simplement mis en évidence qu'il y a diverses manières de travailler, mais en programmation, je crois que le plus important est de se rappeler ceci :

« On est étranger à soi-même en quelques semaines »

Pour présenter un code source, les mots clés sont "rigueur" et "commentaires" ... autrement le plus simple sera de tout reprendre à zéro.

Il m'est arrivé de donner un coup de main à des gens qui m'ont présenté un code source tellement illisible que je n'avais pas envie de le lire... Aucun commentaire, je n'ai pas forcément pensé à tout ce que le créateur du code a pensé, donc jouant aux devinettes, je laisse passer des erreurs, et puis sans rigueur, on s'expose à des fautes de frappe, à des parenthèses oubliées ... Et pour quelqu'un qui est étranger à un code source, c'est très difficile de s'y plonger dans de telles conditions.

Enfin, ce qui est vrai le jour J peut être faux le jour J+1 : chacun évolue dans sa manière de travailler ...

Bonne programmation !