Bonnes pratiques de programmation en Pascal
Un débat pour rassembler les meilleurs conseils de programmation
Le 2011-03-28 06:47:27, par Alcatîz, Responsable Pascal, Lazarus et Assembleur
Bonjour à toutes et à tous,
Le forum Pascal regorge de conseils et de bonnes pratiques de programmation. Force est de constater qu'il faut beaucoup de recherches pour les retrouver et que certains conseils doivent sans cesse être répétés aux développeurs qui débutent en Pascal.
D'où l'idée de les regrouper dans un unique fil de discussion.
Nous en profitons pour vous rappeler l'article de Philippe Gormand sur l'écriture de code Pascal, qui contient plein de conseils d'indentation et de mise en forme, de choix d'identificateurs, etc.
Nous vous invitons à partager avec tous les membres du forum vos meilleures pratiques. Lorsqu'il y aura suffisamment de matière, nous pourrons rassembler tous vos conseils dans un véritable guide.
Le forum Pascal regorge de conseils et de bonnes pratiques de programmation. Force est de constater qu'il faut beaucoup de recherches pour les retrouver et que certains conseils doivent sans cesse être répétés aux développeurs qui débutent en Pascal.
D'où l'idée de les regrouper dans un unique fil de discussion.
Nous en profitons pour vous rappeler l'article de Philippe Gormand sur l'écriture de code Pascal, qui contient plein de conseils d'indentation et de mise en forme, de choix d'identificateurs, etc.
Nous vous invitons à partager avec tous les membres du forum vos meilleures pratiques. Lorsqu'il y aura suffisamment de matière, nous pourrons rassembler tous vos conseils dans un véritable guide.
-
AlcatîzResponsable Pascal, Lazarus et AssembleurQuelques pratiques pour initier le débat :
- Pensez au couple papier+crayon !
Droggo n'a de cesse de le répéter (depuis le temps, il y a un copyright) : avant de commencer à coder, couchez votre programme sur papier. Que ce soit en pseudo-code ou en langage courant, écrivez votre programme ou votre algorithme de manière claire et exécutez-le sur papier. Ce n'est qu'après cette étape de conception et de tests que vous pourrez traduire votre programme en Pascal.
- Indentez convenablement votre code
Une bonne indentation facilite la lecture et permet de détecter beaucoup d'erreurs, comme, par exemple, l'absence de fermeture d'un bloc d'instructions.
Qui peut facilement voir où manque un end dans ce code ?
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Program Chiffres_Lettres; Uses WinCrt; Var Caractere : Char; Begin InitWinCrt; repeat Write('Entrez un caractère ("X" pour quitter) : '); Caractere := ReadKey; WriteLn; if Caractere in ['0'..'9'] then WriteLn('C''est un chiffre.') else if Caractere in ['A'..'Z','a'..'z'] then begin Write('C''est une lettre '); if Caractere in ['A'..'Z'] then WriteLn('majuscule.') else WriteLn('minuscule.'); else WriteLn('C''est une lettre accentuée ou un caractère spécial.'); WriteLn; until Caractere = 'X'; DoneWinCrt; End.
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29Program Chiffres_Lettres; Uses WinCrt; Var Caractere : Char; Begin InitWinCrt; repeat Write('Entrez un caractère ("X" pour quitter) : '); Caractere := ReadKey; WriteLn; if Caractere in ['0'..'9'] then WriteLn('C''est un chiffre.') else if Caractere in ['A'..'Z','a'..'z'] then begin Write('C''est une lettre '); if Caractere in ['A'..'Z'] then WriteLn('majuscule.') else WriteLn('minuscule.'); end (* <-- C'est ici ! *) else WriteLn('C''est une lettre accentuée ou un caractère spécial.'); WriteLn; until Caractere = 'X'; DoneWinCrt; End.
- Soyez cohérent(e) dans votre approche
Essayez de traiter des problèmes identiques de manière similaire. Combien de fois voit-on qu'un bout de code a été écrit en utilisant un concept puis le bout de code suivant avec une autre approche, alors que la même approche aurait permis d'avoir un code cohérent.
- Commentez votre code !
Que ce soit pour vous relire vous-même plus tard ou pour qu'une autre personne lise et comprenne votre code, de grâce ajoutez suffisamment de commentaires là où c'est utile.
Par exemple, dans une procédure, indiquez l'utilité de vos variables locales. Si, dans un traitement, vous effectuez un tri, précédez le tri d'un commentaire du genre "Tri du tableau par quick-sort" : vous serez bien content(e), six mois plus tard, d'avoir ce commentaire pour vous rappeler immédiatement ce que fait votre code sans avoir à le relire pour le comprendre.
- Utilisez des identificateurs parlants
Il est très utile de choisir des noms d'identificateurs qui donnent un maximum de renseignements sur l'utilité d'une variable, un type, une procédure ou fonction, etc.
Par exemple, ce code :
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Const AgeMajorite = 18; Type TTabEntiers = Array [1..20] of Integer; Var TableauAges : TTabEntiers; Function Age_Maximum (Const Tableau : TTabEntiers) : Integer; Begin (* ... *) End; Begin (* ... *) if Age_Maximum(TableauAges) > AgeMajorite then (* ... *) End.
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Type t = Array [1..20] of Integer; Var a : t; Function v (const tab : t) : Integer; Begin (* ... *) End; Begin (* ... *) if v(a) > 18 then (* ... *) End.
- Structurez vos programmes
Le Pascal permet énormément de souplesse pour structurer son code. Isolez chaque traitement dans une procédure ou fonction et découpez vos programmes en unités. La structuration logique d'un programme facilite grandement sa compréhension, sa lecture et sa maintenance. De plus, vous pourrez plus aisément aisément réutiliser votre code dans d'autres programmes.
- Une procédure ou fonction est une boîte hermétique
Une procédure ou fonction doit recevoir comme paramètres tout ce dont elle a besoin et ne doit pas travailler directement avec des variables globales. Il faut considérer la procédure ou fonction comme une boîte hermétiquement fermée, qui reçoit d'un côté des paramètres et qui renvoie de l'autre côté un résultat et/ou une version modifiée des paramètres reçus en entrée.
En appliquant systématiquement cette règle, on facilite la compréhension et le débogage d'un programme.
- Transmettez vos paramètres invariables comme constantes
Quand c'est possible (ce qui n'est pas le cas en Turbo Pascal), transmettez à vos procédures et fonctions des paramètres qui ne doivent pas être modifiés comme constantes. Si vous les transmettez par valeur, il sont inutilement recopiés sur la pile, ce qui est un non-sens en matière d'optimisation.
Si l'on reprend un exemple cité plus haut :
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Const AgeMajorite = 18; Type TTabEntiers = Array [1..20] of Integer; Var TableauAges : TTabEntiers; Function Age_Maximum (Const Tableau : TTabEntiers) : Integer; Begin (* ... *) End; Begin (* ... *) if Age_Maximum(TableauAges) > AgeMajorite then (* ... *) End.
Code : Function Age_Maximum (Tableau : TTabEntiers) : Integer;
- Utilisez des constantes pour représenter des valeurs numériques
En déclarant des constantes pour représenter des valeurs numériques utilisées dans un programme, on se facilite la vie : il suffit de modifier la déclaration d'une constante en tête de programme ou d'unité pour que cela modifie automatiquement tous les exemplaires de sa valeur dans le programme ou l'unité.le 28/03/2011 à 6:49 -
Paul TOTHExpert éminent séniorautre bonne pratique, et c'est valable dans tous les langages, ne pas faire une fonction de 15 pages de long, c'est imbuvable. Et sur 15 pages on peut forcément identifier des sous-traitements à mettre dans des sous-fonctions afin de rendre le tout plus digeste.
dans le même genre, il faut bannir le copier/coller de code (celui-là même qui produit des fonctions de 15 pages), si un code est suffisamment proche d'un autre pour permettre un copier/coller, c'est que le code peut être paramétré dans une sous-fonction qui sera utilisée deux fois.le 12/04/2011 à 14:36 -
Paul TOTHExpert éminent séniorj'ai changé 5 ou 6 fois de choix de mise en forme de mes sources au cours de ma longue carrière
il faut savoir qu'un source est d'autant plus lisible qu'il est sous la forme à laquelle on est habitué.
par exemple, le begin en fin de ligne ou à la ligne va être pratique ou pas selon l'habitude
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25if test then begin ... end; // si on s'attend à avoir le begin sous le if, // on se demande ce que fait ce end ici if test then begin ... end; // si on a l'habitude d'avoir le begin en fin de ligne, // le if semble inachevé car il n'a pas de end correspondant if test then begin ... end; begin ... end; // on pire, il semble indépendant du begin/end if test then Inc(x); begin ... end;
Code : 1
2
3
4
5// tester les bornes if (x<0)or(y<0) then continue; if x>maxx then begin x:=0; Inc(y); end; if y>maxy then exit;
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// point avant l'image if (x < 0) or (y < 0) then Continue; // changement de ligne if x > MaxX then begin x := 0; Inc(y); end; // au delà de l'image on s'arrête if y > MaxY then Exit;
pour ce qui est de l'usage de With, c'est un outil comme un autre
je l'utilise notamment avec les Canvas, ça permet en modifiant une ligne de changer les choses sans passer par une variable temporaire
Code : 1
2
3
4
5
6
7
8
9
10
11
12
13{$IFDEF DIRECT_PAINT} with Canvas do {$ENDIF} {$IFDEF BITMAP_PAINT} with FBitmap.Canvas do {$ENDIF} {$IFDEF PAINTBOX_PAINT} with TPaintBox(Sender).Canvas do {$ENDIF} begin ... end;
le 31/03/2011 à 10:20 -
popoExpert confirméPour ma part, je vais reprendre l'un des éléments de Alcatiz (le passage de paramètres) et développer un peu plus car, c'est selon moi un point essentiel à l'optimisation
A l'exception des varaibles objet
- Tout paramètre dont la valeur en utilisée seulement en entrée et qui n'est pas modifiée en sortie doit être passée en const
- Tout paramètre dont la valeur est systématiquement modifiée et dont la valeur initiale n'est pas utilisée doit être passée en out
- Tout paramètre dont la valeur est utilisée en entrée comme en sortie doit être passé en var
On peut rapidement voir la différence par exemple lors du passage de paramètre de type chaine et en particulier les WideString
Un autre point que je trouve particulièrement important, c'est d'éviter d'utiliser les composant dans une procédure de traitement qui ne nécessite pas leur utilisation.
Exemple concret à ne pas faire :
Code : 1
2
3
4
5function EstDateSuperieurADateDuJour : Boolean; begin Result := False; if (MonDateTimePicker.Date > now) then Result := True; end;
Code : 1
2
3
4
5function EstDateSuperieurADateDuJour(Const UneDate : TDateTime) : Boolean; begin Result := False; if (UneDate > now) then Result := True; end;
le 12/04/2011 à 13:30 -
nostroyoMembre éclairéMettre un préfixe à ses variables en fonction du contexte
-Paramètre A + nom de la variable
-Variable local L + nom de la variable
-Champs d'une classe F + nom de variable
Lors de la création d'un objet pensez toujours à mettre (quand c'est possible) sa destruction dans un finally.
Code : 1
2
3
4
5
6LData := TMemoryStream.Create; try // traitement finally LData.Free; end;
Je suis pour ma part totalement contre le with qui empêche l'inspection correct des variables en delphi et qui est source de bug.le 28/03/2011 à 15:42 -
EpiTouilleMembre éprouvéPensez à utilisé plusieurs fichiers pour de long code. Surtout avec Tp.
C'est plus facile de changer de fenetre avec F6 que de parcourir 70 fonctions ou procedures.
J'ai déja vu des codes avec 150 fonctions dans le main. C'est pas humain
Ce que je fais c'est que je donne le 'U' a mon préfix d'unit, comme ça je sais directement ou est le main. comme par exemble Uoption ou Usauvegarde.
Pour moi, le plus important a part l'indentation est le fait de mettre de nom explicite a vos variables. Comme j'ai aussi lut dans 'Code Proprement', les commentaire c'est bien mais il ne faut pas trop en mettre sinon, ça alourdie vachement le code. Certaines fois, une procedure avec de nom claire, et un bon code peut éviter une panoplie de commentaires mais les commentaires sont utiles aussi;
Aussi éviter les GOTO et les Break. Il y d'autre moyen plus lisible de s'y prendre.
Titeeeele 28/03/2011 à 16:17 -
bubulemasterMembre éclairéBonjour,
pour ma part, contrairement à l'article de Philippe Gormand sur l'écriture de code Pascal.
Je suis pour toujours mettre begin end. Comme ça si on rajoute dans un block on est sûr que c'est pris et on est sûr où s'arrête le block
Totalement contre le "with" comme teubies, car c'est illisible.
La "ligne de séparation" à voir, c'est utile pour l'entête de fonction et encore. Ca alourdi la lecture du code je trouve.
Pour l'utilisation du break voir au cas par cas, dès fois ça simplifie les choses et évite de mettre des conditions à rallonge.le 30/03/2011 à 21:54 -
Dr.WhoMembre éprouvéEvitez les dépendances aux variables globale de classe dans l’implémentation de cette classe (FormX):
NE PAS FAIRE :Code : 1
2
3
4
5
6
7
8
9
10
11var Form1 : TForm1; implementation procedure TForm1.button1Click(Sender: TButton); begin Form1.caption := 'Bonjour'; // dépendance à la variable : Form1 -> source de bugs end;
FAIRE :Code : 1
2
3
4
5
6
7
8
9
10
11var Form1 : TForm1; implementation procedure TForm1.button1Click(Sender: TButton); begin Caption := 'Bonjour'; // ou Self.Caption (temporairement en test, inutile en prod) end;
le 07/05/2011 à 4:08 -
darrylsiteRédacteurj' ajouterai qu'il faut éviter de mélanger de la POO et du procédurale surtout dans une même unité (fichier). Le cas le plus courant se retrouve dans les forms.le 09/05/2011 à 12:57
-
Dr.WhoMembre éprouvéStructurer les fichiers sources :
- Nommer l'unité principale "Main" par exemple ou "TotoMain" pour votre projet "Toto".
- Les fonctions d'outils peuvent être délocalisée dans une unité "Tools" ou "Utils" ou encore "TotoUtils", "TotoTools"
- Chaque unité doit être nommée selon son utilisation, Outils (Tools, Utils), Traduction (Lang, Language), Importation/Exportation (Import, Export), gestion des données (BinFiles, DatFiles, ZipFiles, DbFiles) etc. Soyez clair, précis et concis.
- Placez les ressources dans un sous-dossiers "Ressources" ou "Res" ou encore "Medias", hiérarchisez correctement vos projets en séparant chaques types de données (sons, images, scripts etc), exemple de structure claire :
- \Toto
- \Garbage
- \Medias
- \Sounds
- \Sounds\open.ogg
- \Sounds\close.ogg
- \Sounds\click.ogg
- \Graphics
- \Graphics\logo.jpg
- \Graphics\ground.jpg
- \Graphics\splash.jpg
- \Datas
- \Datas\DataBase.db
- \Setup
- \Licence
- \Licence\CeCill.fr.txt
- \Licence\CeCill.en.txt
- \Script
- \Script\Toto.iss
- \Script\Toto.ico
- \Release
- \Release\Toto-setup-v1.0.0.0.exe
- \Release\Toto-setup-v1.0.1.0.exe
- \Release\Toto-setup-v1.0.2.0.exe
- \Setup\ChangeLog.txt
- \Toto\Toto.dproj
- \Toto\Toto.res
- \Toto\Toto.dfm
- \Toto\TotoMain.pas
- \Toto\TotoTools.pas
le 09/05/2011 à 21:10 - \Toto