IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Bonnes pratiques de programmation en Pascal
Un débat pour rassembler les meilleurs conseils de programmation

Le , par Alcatîz

7PARTAGES

7  0 
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.

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de Alcatîz
Responsable Pascal, Lazarus et Assembleur https://www.developpez.com
Le 28/03/2011 à 6:49
Quelques 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 : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Program 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.
...alors qu'on le voit tout de suite quand c'est indenté :
Code : Sélectionner tout
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
29
Program 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 : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Const 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.
est beaucoup plus parlant que :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Type 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 : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Const 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.
La fonction Age_Maximum ne modifie pas le tableau TableauAges, elle ne fait qu'en extraire la valeur maximum. Il est donc logique de passer le tableau comme constante et seule son adresse est déposée sur la pile. Tandis que si on l'avait passé par valeur :
Code : Sélectionner tout
Function Age_Maximum (Tableau : TTabEntiers) : Integer;
il serait intégralement recopié sur la pile, ce qui prendrait inutilement du temps machine et consommerait inutilement de l'espace sur la pile.
  • 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é.
6  0 
Avatar de Paul TOTH
Expert éminent sénior https://www.developpez.com
Le 12/04/2011 à 14:36
autre 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.
6  0 
Avatar de Paul TOTH
Expert éminent sénior https://www.developpez.com
Le 31/03/2011 à 10:20
j'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 : Sélectionner tout
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
 if 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;
J'ai longtemps privilégié l'écriture compacte, car elle permet d'avoir un maximum d'informations dans un minimum de place
Code : Sélectionner tout
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;
aujourd'hui je préfère un code aéré bien qu'il occupe plus d'espace

Code : Sélectionner tout
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;
Mais tout cela est sans doute moins important avec l'apparition des outils de refactoring.

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 : Sélectionner tout
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;
4  0 
Avatar de popo
Expert confirmé https://www.developpez.com
Le 12/04/2011 à 13:30
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 : Sélectionner tout
1
2
3
4
5
function EstDateSuperieurADateDuJour : Boolean;
begin
  Result := False;
  if (MonDateTimePicker.Date > now) then Result := True;
end;
Préférer ceci :
Code : Sélectionner tout
1
2
3
4
5
function EstDateSuperieurADateDuJour(Const UneDate : TDateTime) : Boolean;
begin
  Result := False;
  if (UneDate > now) then Result := True;
end;
Cela évite de refaire une fonction si la date d'un autre composant doit être validée. Malheurement, on voit encore se genre de chose dans le monde professionnel !
4  0 
Avatar de nostroyo
Membre éclairé https://www.developpez.com
Le 28/03/2011 à 15:42
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 : Sélectionner tout
1
2
3
4
5
6
  LData := TMemoryStream.Create;
  try
  // traitement
  finally
    LData.Free;
  end;
Essayer de respecter fonction qui créer un objet = fonction qui détruit cet objet

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.
3  0 
Avatar de EpiTouille
Membre éprouvé https://www.developpez.com
Le 28/03/2011 à 16:17
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.

Titeeee
3  0 
Avatar de bubulemaster
Membre éclairé https://www.developpez.com
Le 30/03/2011 à 21:54
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.
3  0 
Avatar de Dr.Who
Membre éprouvé https://www.developpez.com
Le 07/05/2011 à 4:08
Evitez les dépendances aux variables globale de classe dans l’implémentation de cette classe (FormX):

NE PAS FAIRE :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
var 
  Form1 : TForm1;

implementation

procedure TForm1.button1Click(Sender: TButton);
begin
  Form1.caption := 'Bonjour';
  // dépendance à la variable : Form1 -> source de bugs
end;

FAIRE :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
var 
  Form1 : TForm1;

implementation

procedure TForm1.button1Click(Sender: TButton);
begin
  Caption := 'Bonjour';
  // ou Self.Caption (temporairement en test, inutile en prod)
end;
2  0 
Avatar de darrylsite
Rédacteur https://www.developpez.com
Le 09/05/2011 à 12:57
j' 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.
2  0 
Avatar de Dr.Who
Membre éprouvé https://www.developpez.com
Le 09/05/2011 à 21:10
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
2  0